xref: /illumos-gate/usr/src/uts/common/io/bge/bge_atomic.c (revision 75d94465)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include "bge_impl.h"
28 
29 /*
30  * Atomically decrement a counter, but only if it will remain
31  * strictly positive (greater than zero) afterwards.  We return
32  * the decremented value if so, otherwise zero (in which case
33  * the counter is unchanged).
34  *
35  * This is used for keeping track of available resources such
36  * as transmit ring slots ...
37  */
38 uint64_t
bge_atomic_reserve(uint64_t * count_p,uint64_t n)39 bge_atomic_reserve(uint64_t *count_p, uint64_t n)
40 {
41 	uint64_t oldval;
42 	uint64_t newval;
43 
44 	/* ATOMICALLY */
45 	do {
46 		oldval = *count_p;
47 		newval = oldval - n;
48 		if (oldval <= n)
49 			return (0);		/* no resources left	*/
50 	} while (atomic_cas_64(count_p, oldval, newval) != oldval);
51 
52 	return (newval);
53 }
54 
55 /*
56  * Atomically increment a counter
57  */
58 void
bge_atomic_renounce(uint64_t * count_p,uint64_t n)59 bge_atomic_renounce(uint64_t *count_p, uint64_t n)
60 {
61 	uint64_t oldval;
62 	uint64_t newval;
63 
64 	/* ATOMICALLY */
65 	do {
66 		oldval = *count_p;
67 		newval = oldval + n;
68 	} while (atomic_cas_64(count_p, oldval, newval) != oldval);
69 }
70 
71 /*
72  * Atomically claim a slot in a descriptor ring
73  */
74 uint64_t
bge_atomic_claim(uint64_t * count_p,uint64_t limit)75 bge_atomic_claim(uint64_t *count_p, uint64_t limit)
76 {
77 	uint64_t oldval;
78 	uint64_t newval;
79 
80 	/* ATOMICALLY */
81 	do {
82 		oldval = *count_p;
83 		newval = NEXT(oldval, limit);
84 	} while (atomic_cas_64(count_p, oldval, newval) != oldval);
85 
86 	return (oldval);
87 }
88 
89 /*
90  * Atomically NEXT a 64-bit integer, returning the
91  * value it had *before* the NEXT was applied
92  */
93 uint64_t
bge_atomic_next(uint64_t * sp,uint64_t limit)94 bge_atomic_next(uint64_t *sp, uint64_t limit)
95 {
96 	uint64_t oldval;
97 	uint64_t newval;
98 
99 	/* ATOMICALLY */
100 	do {
101 		oldval = *sp;
102 		newval = NEXT(oldval, limit);
103 	} while (atomic_cas_64(sp, oldval, newval) != oldval);
104 
105 	return (oldval);
106 }
107 
108 /*
109  * Atomically decrement a counter
110  */
111 void
bge_atomic_sub64(uint64_t * count_p,uint64_t n)112 bge_atomic_sub64(uint64_t *count_p, uint64_t n)
113 {
114 	uint64_t oldval;
115 	uint64_t newval;
116 
117 	/* ATOMICALLY */
118 	do {
119 		oldval = *count_p;
120 		newval = oldval - n;
121 	} while (atomic_cas_64(count_p, oldval, newval) != oldval);
122 }
123 
124 /*
125  * Atomically clear bits in a 64-bit word, returning
126  * the value it had *before* the bits were cleared.
127  */
128 uint64_t
bge_atomic_clr64(uint64_t * sp,uint64_t bits)129 bge_atomic_clr64(uint64_t *sp, uint64_t bits)
130 {
131 	uint64_t oldval;
132 	uint64_t newval;
133 
134 	/* ATOMICALLY */
135 	do {
136 		oldval = *sp;
137 		newval = oldval & ~bits;
138 	} while (atomic_cas_64(sp, oldval, newval) != oldval);
139 
140 	return (oldval);
141 }
142 
143 /*
144  * Atomically shift a 32-bit word left, returning
145  * the value it had *before* the shift was applied
146  */
147 uint32_t
bge_atomic_shl32(uint32_t * sp,uint_t count)148 bge_atomic_shl32(uint32_t *sp, uint_t count)
149 {
150 	uint32_t oldval;
151 	uint32_t newval;
152 
153 	/* ATOMICALLY */
154 	do {
155 		oldval = *sp;
156 		newval = oldval << count;
157 	} while (atomic_cas_32(sp, oldval, newval) != oldval);
158 
159 	return (oldval);
160 }
161