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 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 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 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 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 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 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 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