]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - cvmx-atomic.h
Initial import of Cavium Networks Octeon Simple Executive, SDK version 1.9.0.
[FreeBSD/FreeBSD.git] / cvmx-atomic.h
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3  *  reserved.
4  *
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are
8  *  met:
9  *
10  *      * Redistributions of source code must retain the above copyright
11  *        notice, this list of conditions and the following disclaimer.
12  *
13  *      * Redistributions in binary form must reproduce the above
14  *        copyright notice, this list of conditions and the following
15  *        disclaimer in the documentation and/or other materials provided
16  *        with the distribution.
17  *
18  *      * Neither the name of Cavium Networks nor the names of
19  *        its contributors may be used to endorse or promote products
20  *        derived from this software without specific prior written
21  *        permission.
22  *
23  *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24  *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25  *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26  *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27  *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28  *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29  *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30  *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31  *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32  *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39
40
41
42
43
44 /**
45  * @file
46  *
47  * This file provides atomic operations
48  *
49  * <hr>$Revision: 41586 $<hr>
50  *
51  *
52  */
53
54
55 #ifndef __CVMX_ATOMIC_H__
56 #define __CVMX_ATOMIC_H__
57
58 #ifdef  __cplusplus
59 extern "C" {
60 #endif
61
62
63 /**
64  * Atomically adds a signed value to a 32 bit (aligned) memory location.
65  *
66  * This version does not perform 'sync' operations to enforce memory
67  * operations.  This should only be used when there are no memory operation
68  * ordering constraints.  (This should NOT be used for reference counting -
69  * use the standard version instead.)
70  *
71  * @param ptr    address in memory to add incr to
72  * @param incr   amount to increment memory location by (signed)
73  */
74 static inline void cvmx_atomic_add32_nosync(int32_t *ptr, int32_t incr)
75 {
76     if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
77     {
78         uint32_t tmp;
79
80         __asm__ __volatile__(
81         ".set noreorder         \n"
82         "1: ll   %[tmp], %[val] \n"
83         "   addu %[tmp], %[inc] \n"
84         "   sc   %[tmp], %[val] \n"
85         "   beqz %[tmp], 1b     \n"
86         "   nop                 \n"
87         ".set reorder           \n"
88         : [val] "+m" (*ptr), [tmp] "=&r" (tmp)
89         : [inc] "r" (incr)
90         : "memory");
91     }
92     else
93     {
94         __asm__ __volatile__(
95         "   saa %[inc], (%[base]) \n"
96         : "+m" (*ptr)
97         : [inc] "r" (incr), [base] "r" (ptr)
98         : "memory");
99     }
100 }
101
102 /**
103  * Atomically adds a signed value to a 32 bit (aligned) memory location.
104  *
105  * Memory access ordering is enforced before/after the atomic operation,
106  * so no additional 'sync' instructions are required.
107  *
108  *
109  * @param ptr    address in memory to add incr to
110  * @param incr   amount to increment memory location by (signed)
111  */
112 static inline void cvmx_atomic_add32(int32_t *ptr, int32_t incr)
113 {
114     CVMX_SYNCWS;
115     cvmx_atomic_add32_nosync(ptr, incr);
116     CVMX_SYNCWS;
117 }
118
119 /**
120  * Atomically sets a 32 bit (aligned) memory location to a value
121  *
122  * @param ptr    address of memory to set
123  * @param value  value to set memory location to.
124  */
125 static inline void cvmx_atomic_set32(int32_t *ptr, int32_t value)
126 {
127     CVMX_SYNCWS;
128     *ptr = value;
129     CVMX_SYNCWS;
130 }
131
132 /**
133  * Returns the current value of a 32 bit (aligned) memory
134  * location.
135  *
136  * @param ptr    Address of memory to get
137  * @return Value of the memory
138  */
139 static inline int32_t cvmx_atomic_get32(int32_t *ptr)
140 {
141     return *(volatile int32_t *)ptr;
142 }
143
144 /**
145  * Atomically adds a signed value to a 64 bit (aligned) memory location.
146  *
147  * This version does not perform 'sync' operations to enforce memory
148  * operations.  This should only be used when there are no memory operation
149  * ordering constraints.  (This should NOT be used for reference counting -
150  * use the standard version instead.)
151  *
152  * @param ptr    address in memory to add incr to
153  * @param incr   amount to increment memory location by (signed)
154  */
155 static inline void cvmx_atomic_add64_nosync(int64_t *ptr, int64_t incr)
156 {
157     if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
158     {
159         uint64_t tmp;
160         __asm__ __volatile__(
161         ".set noreorder         \n"
162         "1: lld  %[tmp], %[val] \n"
163         "   daddu %[tmp], %[inc] \n"
164         "   scd  %[tmp], %[val] \n"
165         "   beqz %[tmp], 1b     \n"
166         "   nop                 \n"
167         ".set reorder           \n"
168         : [val] "+m" (*ptr), [tmp] "=&r" (tmp)
169         : [inc] "r" (incr)
170         : "memory");
171     }
172     else
173     {
174         __asm__ __volatile__(
175         "   saad %[inc], (%[base])  \n"
176         : "+m" (*ptr)
177         : [inc] "r" (incr), [base] "r" (ptr)
178         : "memory");
179     }
180 }
181
182 /**
183  * Atomically adds a signed value to a 64 bit (aligned) memory location.
184  *
185  * Memory access ordering is enforced before/after the atomic operation,
186  * so no additional 'sync' instructions are required.
187  *
188  *
189  * @param ptr    address in memory to add incr to
190  * @param incr   amount to increment memory location by (signed)
191  */
192 static inline void cvmx_atomic_add64(int64_t *ptr, int64_t incr)
193 {
194     CVMX_SYNCWS;
195     cvmx_atomic_add64_nosync(ptr, incr);
196     CVMX_SYNCWS;
197 }
198
199 /**
200  * Atomically sets a 64 bit (aligned) memory location to a value
201  *
202  * @param ptr    address of memory to set
203  * @param value  value to set memory location to.
204  */
205 static inline void cvmx_atomic_set64(int64_t *ptr, int64_t value)
206 {
207     CVMX_SYNCWS;
208     *ptr = value;
209     CVMX_SYNCWS;
210 }
211
212 /**
213  * Returns the current value of a 64 bit (aligned) memory
214  * location.
215  *
216  * @param ptr    Address of memory to get
217  * @return Value of the memory
218  */
219 static inline int64_t cvmx_atomic_get64(int64_t *ptr)
220 {
221     return *(volatile int64_t *)ptr;
222 }
223
224 /**
225  * Atomically compares the old value with the value at ptr, and if they match,
226  * stores new_val to ptr.
227  * If *ptr and old don't match, function returns failure immediately.
228  * If *ptr and old match, function spins until *ptr updated to new atomically, or
229  *  until *ptr and old no longer match
230  *
231  * Does no memory synchronization.
232  *
233  * @return 1 on success (match and store)
234  *         0 on no match
235  */
236 static inline uint32_t cvmx_atomic_compare_and_store32_nosync(uint32_t *ptr, uint32_t old_val, uint32_t new_val)
237 {
238     uint32_t tmp, ret;
239
240     __asm__ __volatile__(
241     ".set noreorder         \n"
242     "1: ll   %[tmp], %[val] \n"
243     "   li   %[ret], 0     \n"
244     "   bne  %[tmp], %[old], 2f \n"
245     "   move %[tmp], %[new_val] \n"
246     "   sc   %[tmp], %[val] \n"
247     "   beqz %[tmp], 1b     \n"
248     "   li   %[ret], 1      \n"
249     "2: nop               \n"
250     ".set reorder           \n"
251     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
252     : [old] "r" (old_val), [new_val] "r" (new_val)
253     : "memory");
254
255     return(ret);
256
257 }
258
259 /**
260  * Atomically compares the old value with the value at ptr, and if they match,
261  * stores new_val to ptr.
262  * If *ptr and old don't match, function returns failure immediately.
263  * If *ptr and old match, function spins until *ptr updated to new atomically, or
264  *  until *ptr and old no longer match
265  *
266  * Does memory synchronization that is required to use this as a locking primitive.
267  *
268  * @return 1 on success (match and store)
269  *         0 on no match
270  */
271 static inline uint32_t cvmx_atomic_compare_and_store32(uint32_t *ptr, uint32_t old_val, uint32_t new_val)
272 {
273     uint32_t ret;
274     CVMX_SYNCWS;
275     ret = cvmx_atomic_compare_and_store32_nosync(ptr, old_val, new_val);
276     CVMX_SYNCWS;
277     return ret;
278
279
280 }
281
282 /**
283  * Atomically compares the old value with the value at ptr, and if they match,
284  * stores new_val to ptr.
285  * If *ptr and old don't match, function returns failure immediately.
286  * If *ptr and old match, function spins until *ptr updated to new atomically, or
287  *  until *ptr and old no longer match
288  *
289  * Does no memory synchronization.
290  *
291  * @return 1 on success (match and store)
292  *         0 on no match
293  */
294 static inline uint64_t cvmx_atomic_compare_and_store64_nosync(uint64_t *ptr, uint64_t old_val, uint64_t new_val)
295 {
296     uint64_t tmp, ret;
297
298     __asm__ __volatile__(
299     ".set noreorder         \n"
300     "1: lld  %[tmp], %[val] \n"
301     "   li   %[ret], 0     \n"
302     "   bne  %[tmp], %[old], 2f \n"
303     "   move %[tmp], %[new_val] \n"
304     "   scd  %[tmp], %[val] \n"
305     "   beqz %[tmp], 1b     \n"
306     "   li   %[ret], 1      \n"
307     "2: nop               \n"
308     ".set reorder           \n"
309     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
310     : [old] "r" (old_val), [new_val] "r" (new_val)
311     : "memory");
312
313     return(ret);
314
315 }
316
317 /**
318  * Atomically compares the old value with the value at ptr, and if they match,
319  * stores new_val to ptr.
320  * If *ptr and old don't match, function returns failure immediately.
321  * If *ptr and old match, function spins until *ptr updated to new atomically, or
322  *  until *ptr and old no longer match
323  *
324  * Does memory synchronization that is required to use this as a locking primitive.
325  *
326  * @return 1 on success (match and store)
327  *         0 on no match
328  */
329 static inline uint64_t cvmx_atomic_compare_and_store64(uint64_t *ptr, uint64_t old_val, uint64_t new_val)
330 {
331     uint64_t ret;
332     CVMX_SYNCWS;
333     ret = cvmx_atomic_compare_and_store64_nosync(ptr, old_val, new_val);
334     CVMX_SYNCWS;
335     return ret;
336 }
337
338 /**
339  * Atomically adds a signed value to a 64 bit (aligned) memory location,
340  * and returns previous value.
341  *
342  * This version does not perform 'sync' operations to enforce memory
343  * operations.  This should only be used when there are no memory operation
344  * ordering constraints.  (This should NOT be used for reference counting -
345  * use the standard version instead.)
346  *
347  * @param ptr    address in memory to add incr to
348  * @param incr   amount to increment memory location by (signed)
349  *
350  * @return Value of memory location before increment
351  */
352 static inline int64_t cvmx_atomic_fetch_and_add64_nosync(int64_t *ptr, int64_t incr)
353 {
354     uint64_t tmp, ret;
355
356     __asm__ __volatile__(
357     ".set noreorder          \n"
358     "1: lld   %[tmp], %[val] \n"
359     "   move  %[ret], %[tmp] \n"
360     "   daddu %[tmp], %[inc] \n"
361     "   scd   %[tmp], %[val] \n"
362     "   beqz  %[tmp], 1b     \n"
363     "   nop                  \n"
364     ".set reorder            \n"
365     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
366     : [inc] "r" (incr)
367     : "memory");
368
369     return (ret);
370 }
371
372 /**
373  * Atomically adds a signed value to a 64 bit (aligned) memory location,
374  * and returns previous value.
375  *
376  * Memory access ordering is enforced before/after the atomic operation,
377  * so no additional 'sync' instructions are required.
378  *
379  * @param ptr    address in memory to add incr to
380  * @param incr   amount to increment memory location by (signed)
381  *
382  * @return Value of memory location before increment
383  */
384 static inline int64_t cvmx_atomic_fetch_and_add64(int64_t *ptr, int64_t incr)
385 {
386     uint64_t ret;
387     CVMX_SYNCWS;
388     ret = cvmx_atomic_fetch_and_add64_nosync(ptr, incr);
389     CVMX_SYNCWS;
390     return ret;
391 }
392
393 /**
394  * Atomically adds a signed value to a 32 bit (aligned) memory location,
395  * and returns previous value.
396  *
397  * This version does not perform 'sync' operations to enforce memory
398  * operations.  This should only be used when there are no memory operation
399  * ordering constraints.  (This should NOT be used for reference counting -
400  * use the standard version instead.)
401  *
402  * @param ptr    address in memory to add incr to
403  * @param incr   amount to increment memory location by (signed)
404  *
405  * @return Value of memory location before increment
406  */
407 static inline int32_t cvmx_atomic_fetch_and_add32_nosync(int32_t *ptr, int32_t incr)
408 {
409     uint32_t tmp, ret;
410
411     __asm__ __volatile__(
412     ".set noreorder         \n"
413     "1: ll   %[tmp], %[val] \n"
414     "   move %[ret], %[tmp] \n"
415     "   addu %[tmp], %[inc] \n"
416     "   sc   %[tmp], %[val] \n"
417     "   beqz %[tmp], 1b     \n"
418     "   nop                 \n"
419     ".set reorder           \n"
420     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
421     : [inc] "r" (incr)
422     : "memory");
423
424     return (ret);
425 }
426
427 /**
428  * Atomically adds a signed value to a 32 bit (aligned) memory location,
429  * and returns previous value.
430  *
431  * Memory access ordering is enforced before/after the atomic operation,
432  * so no additional 'sync' instructions are required.
433  *
434  * @param ptr    address in memory to add incr to
435  * @param incr   amount to increment memory location by (signed)
436  *
437  * @return Value of memory location before increment
438  */
439 static inline int32_t cvmx_atomic_fetch_and_add32(int32_t *ptr, int32_t incr)
440 {
441     uint32_t ret;
442     CVMX_SYNCWS;
443     ret = cvmx_atomic_fetch_and_add32_nosync(ptr, incr);
444     CVMX_SYNCWS;
445     return ret;
446 }
447
448 /**
449  * Atomically set bits in a 64 bit (aligned) memory location,
450  * and returns previous value.
451  *
452  * This version does not perform 'sync' operations to enforce memory
453  * operations.  This should only be used when there are no memory operation
454  * ordering constraints.
455  *
456  * @param ptr    address in memory
457  * @param mask   mask of bits to set
458  *
459  * @return Value of memory location before setting bits
460  */
461 static inline uint64_t cvmx_atomic_fetch_and_bset64_nosync(uint64_t *ptr, uint64_t mask)
462 {
463     uint64_t tmp, ret;
464
465     __asm__ __volatile__(
466     ".set noreorder         \n"
467     "1: lld  %[tmp], %[val] \n"
468     "   move %[ret], %[tmp] \n"
469     "   or   %[tmp], %[msk] \n"
470     "   scd  %[tmp], %[val] \n"
471     "   beqz %[tmp], 1b     \n"
472     "   nop                 \n"
473     ".set reorder           \n"
474     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
475     : [msk] "r" (mask)
476     : "memory");
477
478     return (ret);
479 }
480
481 /**
482  * Atomically set bits in a 32 bit (aligned) memory location,
483  * and returns previous value.
484  *
485  * This version does not perform 'sync' operations to enforce memory
486  * operations.  This should only be used when there are no memory operation
487  * ordering constraints.
488  *
489  * @param ptr    address in memory
490  * @param mask   mask of bits to set
491  *
492  * @return Value of memory location before setting bits
493  */
494 static inline uint32_t cvmx_atomic_fetch_and_bset32_nosync(uint32_t *ptr, uint32_t mask)
495 {
496     uint32_t tmp, ret;
497
498     __asm__ __volatile__(
499     ".set noreorder         \n"
500     "1: ll   %[tmp], %[val] \n"
501     "   move %[ret], %[tmp] \n"
502     "   or   %[tmp], %[msk] \n"
503     "   sc   %[tmp], %[val] \n"
504     "   beqz %[tmp], 1b     \n"
505     "   nop                 \n"
506     ".set reorder           \n"
507     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
508     : [msk] "r" (mask)
509     : "memory");
510
511     return (ret);
512 }
513
514 /**
515  * Atomically clear bits in a 64 bit (aligned) memory location,
516  * and returns previous value.
517  *
518  * This version does not perform 'sync' operations to enforce memory
519  * operations.  This should only be used when there are no memory operation
520  * ordering constraints.
521  *
522  * @param ptr    address in memory
523  * @param mask   mask of bits to clear
524  *
525  * @return Value of memory location before clearing bits
526  */
527 static inline uint64_t cvmx_atomic_fetch_and_bclr64_nosync(uint64_t *ptr, uint64_t mask)
528 {
529     uint64_t tmp, ret;
530
531     __asm__ __volatile__(
532     ".set noreorder         \n"
533     "   nor  %[msk], 0      \n"
534     "1: lld  %[tmp], %[val] \n"
535     "   move %[ret], %[tmp] \n"
536     "   and  %[tmp], %[msk] \n"
537     "   scd  %[tmp], %[val] \n"
538     "   beqz %[tmp], 1b     \n"
539     "   nop                 \n"
540     ".set reorder           \n"
541     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
542     : [msk] "r" (mask)
543     : "memory");
544
545     return (ret);
546 }
547
548 /**
549  * Atomically clear bits in a 32 bit (aligned) memory location,
550  * and returns previous value.
551  *
552  * This version does not perform 'sync' operations to enforce memory
553  * operations.  This should only be used when there are no memory operation
554  * ordering constraints.
555  *
556  * @param ptr    address in memory
557  * @param mask   mask of bits to clear
558  *
559  * @return Value of memory location before clearing bits
560  */
561 static inline uint32_t cvmx_atomic_fetch_and_bclr32_nosync(uint32_t *ptr, uint32_t mask)
562 {
563     uint32_t tmp, ret;
564
565     __asm__ __volatile__(
566     ".set noreorder         \n"
567     "   nor  %[msk], 0      \n"
568     "1: ll   %[tmp], %[val] \n"
569     "   move %[ret], %[tmp] \n"
570     "   and  %[tmp], %[msk] \n"
571     "   sc   %[tmp], %[val] \n"
572     "   beqz %[tmp], 1b     \n"
573     "   nop                 \n"
574     ".set reorder           \n"
575     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
576     : [msk] "r" (mask)
577     : "memory");
578
579     return (ret);
580 }
581
582 /**
583  * Atomically swaps value in 64 bit (aligned) memory location,
584  * and returns previous value.
585  *
586  * This version does not perform 'sync' operations to enforce memory
587  * operations.  This should only be used when there are no memory operation
588  * ordering constraints.
589  *
590  * @param ptr       address in memory
591  * @param new_val   new value to write
592  *
593  * @return Value of memory location before swap operation
594  */
595 static inline uint64_t cvmx_atomic_swap64_nosync(uint64_t *ptr, uint64_t new_val)
596 {
597     uint64_t tmp, ret;
598
599     __asm__ __volatile__(
600     ".set noreorder         \n"
601     "1: lld  %[ret], %[val] \n"
602     "   move %[tmp], %[new_val] \n"
603     "   scd  %[tmp], %[val] \n"
604     "   beqz %[tmp],  1b    \n"
605     "   nop                 \n"
606     ".set reorder           \n"
607     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
608     : [new_val] "r"  (new_val)
609     : "memory");
610
611     return (ret);
612 }
613
614 /**
615  * Atomically swaps value in 32 bit (aligned) memory location,
616  * and returns previous value.
617  *
618  * This version does not perform 'sync' operations to enforce memory
619  * operations.  This should only be used when there are no memory operation
620  * ordering constraints.
621  *
622  * @param ptr       address in memory
623  * @param new_val   new value to write
624  *
625  * @return Value of memory location before swap operation
626  */
627 static inline uint32_t cvmx_atomic_swap32_nosync(uint32_t *ptr, uint32_t new_val)
628 {
629     uint32_t tmp, ret;
630
631     __asm__ __volatile__(
632     ".set noreorder         \n"
633     "1: ll   %[ret], %[val] \n"
634     "   move %[tmp], %[new_val] \n"
635     "   sc   %[tmp], %[val] \n"
636     "   beqz %[tmp],  1b    \n"
637     "   nop                 \n"
638     ".set reorder           \n"
639     : [val] "+m" (*ptr), [tmp] "=&r" (tmp), [ret] "=&r" (ret)
640     : [new_val] "r"  (new_val)
641     : "memory");
642
643     return (ret);
644 }
645
646 /**
647  * This atomic operation is now named cvmx_atomic_compare_and_store32_nosync
648  * and the (deprecated) macro is provided for backward compatibility.
649  * @deprecated
650  */
651 #define cvmx_atomic_compare_and_store_nosync32 cvmx_atomic_compare_and_store32_nosync
652
653 /**
654  * This atomic operation is now named cvmx_atomic_compare_and_store64_nosync
655  * and the (deprecated) macro is provided for backward compatibility.
656  * @deprecated
657  */
658 #define cvmx_atomic_compare_and_store_nosync64 cvmx_atomic_compare_and_store64_nosync
659
660
661
662 #ifdef  __cplusplus
663 }
664 #endif
665
666 #endif /* __CVMX_ATOMIC_H__ */