xref: /openbmc/linux/lib/dec_and_lock.c (revision 4f64a6c9)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
28bc3bcc9SPaul Gortmaker #include <linux/export.h>
31da177e4SLinus Torvalds #include <linux/spinlock.h>
460063497SArun Sharma #include <linux/atomic.h>
51da177e4SLinus Torvalds 
64db2ce01SDavid S. Miller /*
74db2ce01SDavid S. Miller  * This is an implementation of the notion of "decrement a
84db2ce01SDavid S. Miller  * reference count, and return locked if it decremented to zero".
94db2ce01SDavid S. Miller  *
101da177e4SLinus Torvalds  * NOTE NOTE NOTE! This is _not_ equivalent to
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *	if (atomic_dec_and_test(&atomic)) {
131da177e4SLinus Torvalds  *		spin_lock(&lock);
141da177e4SLinus Torvalds  *		return 1;
151da177e4SLinus Torvalds  *	}
161da177e4SLinus Torvalds  *	return 0;
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  * because the spin-lock and the decrement must be
191da177e4SLinus Torvalds  * "atomic".
201da177e4SLinus Torvalds  */
_atomic_dec_and_lock(atomic_t * atomic,spinlock_t * lock)211da177e4SLinus Torvalds int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
221da177e4SLinus Torvalds {
23a57004e1SNick Piggin 	/* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
24a57004e1SNick Piggin 	if (atomic_add_unless(atomic, -1, 1))
25a57004e1SNick Piggin 		return 0;
26417dcdf9SJan Blunck 
27a57004e1SNick Piggin 	/* Otherwise do it the slow way */
281da177e4SLinus Torvalds 	spin_lock(lock);
291da177e4SLinus Torvalds 	if (atomic_dec_and_test(atomic))
301da177e4SLinus Torvalds 		return 1;
311da177e4SLinus Torvalds 	spin_unlock(lock);
321da177e4SLinus Torvalds 	return 0;
331da177e4SLinus Torvalds }
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds EXPORT_SYMBOL(_atomic_dec_and_lock);
36ccfbb5beSAnna-Maria Gleixner 
_atomic_dec_and_lock_irqsave(atomic_t * atomic,spinlock_t * lock,unsigned long * flags)37ccfbb5beSAnna-Maria Gleixner int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
38ccfbb5beSAnna-Maria Gleixner 				 unsigned long *flags)
39ccfbb5beSAnna-Maria Gleixner {
40ccfbb5beSAnna-Maria Gleixner 	/* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
41ccfbb5beSAnna-Maria Gleixner 	if (atomic_add_unless(atomic, -1, 1))
42ccfbb5beSAnna-Maria Gleixner 		return 0;
43ccfbb5beSAnna-Maria Gleixner 
44ccfbb5beSAnna-Maria Gleixner 	/* Otherwise do it the slow way */
45ccfbb5beSAnna-Maria Gleixner 	spin_lock_irqsave(lock, *flags);
46ccfbb5beSAnna-Maria Gleixner 	if (atomic_dec_and_test(atomic))
47ccfbb5beSAnna-Maria Gleixner 		return 1;
48ccfbb5beSAnna-Maria Gleixner 	spin_unlock_irqrestore(lock, *flags);
49ccfbb5beSAnna-Maria Gleixner 	return 0;
50ccfbb5beSAnna-Maria Gleixner }
51ccfbb5beSAnna-Maria Gleixner EXPORT_SYMBOL(_atomic_dec_and_lock_irqsave);
52*4f64a6c9SJames Clark 
_atomic_dec_and_raw_lock(atomic_t * atomic,raw_spinlock_t * lock)53*4f64a6c9SJames Clark int _atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock)
54*4f64a6c9SJames Clark {
55*4f64a6c9SJames Clark 	/* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
56*4f64a6c9SJames Clark 	if (atomic_add_unless(atomic, -1, 1))
57*4f64a6c9SJames Clark 		return 0;
58*4f64a6c9SJames Clark 
59*4f64a6c9SJames Clark 	/* Otherwise do it the slow way */
60*4f64a6c9SJames Clark 	raw_spin_lock(lock);
61*4f64a6c9SJames Clark 	if (atomic_dec_and_test(atomic))
62*4f64a6c9SJames Clark 		return 1;
63*4f64a6c9SJames Clark 	raw_spin_unlock(lock);
64*4f64a6c9SJames Clark 	return 0;
65*4f64a6c9SJames Clark }
66*4f64a6c9SJames Clark EXPORT_SYMBOL(_atomic_dec_and_raw_lock);
67*4f64a6c9SJames Clark 
_atomic_dec_and_raw_lock_irqsave(atomic_t * atomic,raw_spinlock_t * lock,unsigned long * flags)68*4f64a6c9SJames Clark int _atomic_dec_and_raw_lock_irqsave(atomic_t *atomic, raw_spinlock_t *lock,
69*4f64a6c9SJames Clark 				     unsigned long *flags)
70*4f64a6c9SJames Clark {
71*4f64a6c9SJames Clark 	/* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
72*4f64a6c9SJames Clark 	if (atomic_add_unless(atomic, -1, 1))
73*4f64a6c9SJames Clark 		return 0;
74*4f64a6c9SJames Clark 
75*4f64a6c9SJames Clark 	/* Otherwise do it the slow way */
76*4f64a6c9SJames Clark 	raw_spin_lock_irqsave(lock, *flags);
77*4f64a6c9SJames Clark 	if (atomic_dec_and_test(atomic))
78*4f64a6c9SJames Clark 		return 1;
79*4f64a6c9SJames Clark 	raw_spin_unlock_irqrestore(lock, *flags);
80*4f64a6c9SJames Clark 	return 0;
81*4f64a6c9SJames Clark }
82*4f64a6c9SJames Clark EXPORT_SYMBOL(_atomic_dec_and_raw_lock_irqsave);
83