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 }