atomic-long.h revision 337896
1142425Snectar/*-
2160814Ssimon * Copyright (c) 2010 Isilon Systems, Inc.
3142425Snectar * Copyright (c) 2010 iX Systems, Inc.
4142425Snectar * Copyright (c) 2010 Panasas, Inc.
5142425Snectar * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
6142425Snectar * All rights reserved.
7142425Snectar *
8142425Snectar * Redistribution and use in source and binary forms, with or without
9142425Snectar * modification, are permitted provided that the following conditions
10142425Snectar * are met:
11142425Snectar * 1. Redistributions of source code must retain the above copyright
12142425Snectar *    notice unmodified, this list of conditions, and the following
13142425Snectar *    disclaimer.
14142425Snectar * 2. Redistributions in binary form must reproduce the above copyright
15142425Snectar *    notice, this list of conditions and the following disclaimer in the
16142425Snectar *    documentation and/or other materials provided with the distribution.
17142425Snectar *
18142425Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19142425Snectar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20194206Ssimon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21194206Ssimon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22142425Snectar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23142425Snectar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24142425Snectar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25142425Snectar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26142425Snectar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27142425Snectar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28142425Snectar *
29142425Snectar * $FreeBSD: stable/11/sys/compat/linuxkpi/common/include/asm/atomic-long.h 337896 2018-08-16 08:10:11Z hselasky $
30142425Snectar */
31142425Snectar#ifndef	_ATOMIC_LONG_H_
32142425Snectar#define	_ATOMIC_LONG_H_
33142425Snectar
34142425Snectar#include <linux/compiler.h>
35142425Snectar#include <sys/types.h>
36238405Sjkim#include <machine/atomic.h>
37142425Snectar
38142425Snectar#define	ATOMIC_LONG_INIT(x)	{ .counter = (x) }
39142425Snectar
40142425Snectartypedef struct {
41142425Snectar	volatile long counter;
42142425Snectar} atomic_long_t;
43142425Snectar
44142425Snectar#define	atomic_long_add(i, v)		atomic_long_add_return((i), (v))
45142425Snectar#define	atomic_long_inc_return(v)	atomic_long_add_return(1, (v))
46142425Snectar#define	atomic_long_inc_not_zero(v)	atomic_long_add_unless((v), 1, 0)
47142425Snectar
48142425Snectarstatic inline long
49160814Ssimonatomic_long_add_return(long i, atomic_long_t *v)
50160814Ssimon{
51142425Snectar	return i + atomic_fetchadd_long(&v->counter, i);
52142425Snectar}
53142425Snectar
54142425Snectarstatic inline void
55142425Snectaratomic_long_set(atomic_long_t *v, long i)
56142425Snectar{
57142425Snectar	WRITE_ONCE(v->counter, i);
58142425Snectar}
59142425Snectar
60142425Snectarstatic inline long
61142425Snectaratomic_long_read(atomic_long_t *v)
62142425Snectar{
63142425Snectar	return READ_ONCE(v->counter);
64284283Sjkim}
65284283Sjkim
66142425Snectarstatic inline long
67160814Ssimonatomic_long_inc(atomic_long_t *v)
68142425Snectar{
69142425Snectar	return atomic_fetchadd_long(&v->counter, 1) + 1;
70142425Snectar}
71142425Snectar
72142425Snectarstatic inline long
73142425Snectaratomic_long_dec(atomic_long_t *v)
74142425Snectar{
75142425Snectar	return atomic_fetchadd_long(&v->counter, -1) - 1;
76142425Snectar}
77142425Snectar
78142425Snectarstatic inline long
79142425Snectaratomic_long_xchg(atomic_long_t *v, long val)
80142425Snectar{
81142425Snectar	return atomic_swap_long(&v->counter, val);
82142425Snectar}
83160814Ssimon
84160814Ssimonstatic inline long
85160814Ssimonatomic_long_cmpxchg(atomic_long_t *v, long old, long new)
86194206Ssimon{
87194206Ssimon	long ret = old;
88194206Ssimon
89194206Ssimon	for (;;) {
90194206Ssimon		if (atomic_cmpset_long(&v->counter, old, new))
91194206Ssimon			break;
92194206Ssimon		ret = READ_ONCE(v->counter);
93142425Snectar		if (ret != old)
94142425Snectar			break;
95142425Snectar	}
96142425Snectar	return (ret);
97160814Ssimon}
98160814Ssimon
99160814Ssimonstatic inline int
100atomic_long_add_unless(atomic_long_t *v, long a, long u)
101{
102	long c;
103
104	for (;;) {
105		c = atomic_long_read(v);
106		if (unlikely(c == u))
107			break;
108		if (likely(atomic_cmpset_long(&v->counter, c, c + a)))
109			break;
110	}
111	return (c != u);
112}
113
114static inline long
115atomic_long_dec_and_test(atomic_long_t *v)
116{
117	long i = atomic_long_add(-1, v);
118	return i == 0 ;
119}
120
121#endif	/* _ATOMIC_LONG_H_ */
122