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 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include "bge_impl.h"
  30 
  31 /*
  32  * Atomically decrement a counter, but only if it will remain
  33  * strictly positive (greater than zero) afterwards.  We return
  34  * the decremented value if so, otherwise zero (in which case
  35  * the counter is unchanged).
  36  *
  37  * This is used for keeping track of available resources such
  38  * as transmit ring slots ...
  39  */
  40 uint64_t
  41 bge_atomic_reserve(uint64_t *count_p, uint64_t n)
  42 {
  43         uint64_t oldval;
  44         uint64_t newval;
  45 
  46         /* ATOMICALLY */
  47         do {
  48                 oldval = *count_p;
  49                 newval = oldval - n;
  50                 if (oldval <= n)
  51                         return (0);             /* no resources left    */
  52         } while (cas64(count_p, oldval, newval) != oldval);
  53 
  54         return (newval);
  55 }
  56 
  57 /*
  58  * Atomically increment a counter
  59  */
  60 void
  61 bge_atomic_renounce(uint64_t *count_p, uint64_t n)
  62 {
  63         uint64_t oldval;
  64         uint64_t newval;
  65 
  66         /* ATOMICALLY */
  67         do {
  68                 oldval = *count_p;
  69                 newval = oldval + n;
  70         } while (cas64(count_p, oldval, newval) != oldval);
  71 }
  72 
  73 /*
  74  * Atomically claim a slot in a descriptor ring
  75  */
  76 uint64_t
  77 bge_atomic_claim(uint64_t *count_p, uint64_t limit)
  78 {
  79         uint64_t oldval;
  80         uint64_t newval;
  81 
  82         /* ATOMICALLY */
  83         do {
  84                 oldval = *count_p;
  85                 newval = NEXT(oldval, limit);
  86         } while (cas64(count_p, oldval, newval) != oldval);
  87 
  88         return (oldval);
  89 }
  90 
  91 /*
  92  * Atomically NEXT a 64-bit integer, returning the
  93  * value it had *before* the NEXT was applied
  94  */
  95 uint64_t
  96 bge_atomic_next(uint64_t *sp, uint64_t limit)
  97 {
  98         uint64_t oldval;
  99         uint64_t newval;
 100 
 101         /* ATOMICALLY */
 102         do {
 103                 oldval = *sp;
 104                 newval = NEXT(oldval, limit);
 105         } while (cas64(sp, oldval, newval) != oldval);
 106 
 107         return (oldval);
 108 }
 109 
 110 /*
 111  * Atomically decrement a counter
 112  */
 113 void
 114 bge_atomic_sub64(uint64_t *count_p, uint64_t n)
 115 {
 116         uint64_t oldval;
 117         uint64_t newval;
 118 
 119         /* ATOMICALLY */
 120         do {
 121                 oldval = *count_p;
 122                 newval = oldval - n;
 123         } while (cas64(count_p, oldval, newval) != oldval);
 124 }
 125 
 126 /*
 127  * Atomically clear bits in a 64-bit word, returning
 128  * the value it had *before* the bits were cleared.
 129  */
 130 uint64_t
 131 bge_atomic_clr64(uint64_t *sp, uint64_t bits)
 132 {
 133         uint64_t oldval;
 134         uint64_t newval;
 135 
 136         /* ATOMICALLY */
 137         do {
 138                 oldval = *sp;
 139                 newval = oldval & ~bits;
 140         } while (cas64(sp, oldval, newval) != oldval);
 141 
 142         return (oldval);
 143 }
 144 
 145 /*
 146  * Atomically shift a 32-bit word left, returning
 147  * the value it had *before* the shift was applied
 148  */
 149 uint32_t
 150 bge_atomic_shl32(uint32_t *sp, uint_t count)
 151 {
 152         uint32_t oldval;
 153         uint32_t newval;
 154 
 155         /* ATOMICALLY */
 156         do {
 157                 oldval = *sp;
 158                 newval = oldval << count;
 159         } while (cas32(sp, oldval, newval) != oldval);
 160 
 161         return (oldval);
 162 }