1170431Spjd/*-
2170431Spjd * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3170431Spjd * All rights reserved.
4170431Spjd *
5170431Spjd * Redistribution and use in source and binary forms, with or without
6170431Spjd * modification, are permitted provided that the following conditions
7170431Spjd * are met:
8170431Spjd * 1. Redistributions of source code must retain the above copyright
9170431Spjd *    notice, this list of conditions and the following disclaimer.
10170431Spjd * 2. Redistributions in binary form must reproduce the above copyright
11170431Spjd *    notice, this list of conditions and the following disclaimer in the
12170431Spjd *    documentation and/or other materials provided with the distribution.
13170431Spjd *
14170431Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15170431Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16170431Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17170431Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18170431Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19170431Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20170431Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21170431Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22170431Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23170431Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24170431Spjd * SUCH DAMAGE.
25170431Spjd */
26170431Spjd
27170431Spjd#include <sys/cdefs.h>
28170431Spjd__FBSDID("$FreeBSD$");
29170431Spjd
30170431Spjd#include <sys/param.h>
31170431Spjd#include <sys/lock.h>
32170431Spjd#include <sys/mutex.h>
33170431Spjd#include <sys/atomic.h>
34170431Spjd
35170431Spjd#ifdef _KERNEL
36170431Spjd#include <sys/kernel.h>
37170431Spjd
38170431Spjdstruct mtx atomic_mtx;
39170431SpjdMTX_SYSINIT(atomic, &atomic_mtx, "atomic", MTX_DEF);
40170431Spjd#else
41170431Spjd#include <pthread.h>
42170431Spjd
43170431Spjd#define	mtx_lock(lock)		pthread_mutex_lock(lock)
44170431Spjd#define	mtx_unlock(lock)	pthread_mutex_unlock(lock)
45170431Spjd
46170431Spjdstatic pthread_mutex_t atomic_mtx;
47170431Spjd
48170431Spjdstatic __attribute__((constructor)) void
49170431Spjdatomic_init(void)
50170431Spjd{
51170431Spjd	pthread_mutex_init(&atomic_mtx, NULL);
52170431Spjd}
53170431Spjd#endif
54170431Spjd
55218007Sjchandra#if !defined(__LP64__) && !defined(__mips_n32)
56170431Spjdvoid
57170431Spjdatomic_add_64(volatile uint64_t *target, int64_t delta)
58170431Spjd{
59170431Spjd
60170431Spjd	mtx_lock(&atomic_mtx);
61170431Spjd	*target += delta;
62170431Spjd	mtx_unlock(&atomic_mtx);
63170431Spjd}
64185029Spjd
65185029Spjdvoid
66185029Spjdatomic_dec_64(volatile uint64_t *target)
67185029Spjd{
68185029Spjd
69185029Spjd	mtx_lock(&atomic_mtx);
70185029Spjd	*target -= 1;
71185029Spjd	mtx_unlock(&atomic_mtx);
72185029Spjd}
73170431Spjd#endif
74170431Spjd
75170431Spjduint64_t
76170431Spjdatomic_add_64_nv(volatile uint64_t *target, int64_t delta)
77170431Spjd{
78170431Spjd	uint64_t newval;
79170431Spjd
80170431Spjd	mtx_lock(&atomic_mtx);
81170431Spjd	newval = (*target += delta);
82170431Spjd	mtx_unlock(&atomic_mtx);
83170431Spjd	return (newval);
84170431Spjd}
85170431Spjd
86219089Spjd#if defined(__powerpc__) || defined(__arm__) || defined(__mips__)
87170431Spjdvoid
88170431Spjdatomic_or_8(volatile uint8_t *target, uint8_t value)
89170431Spjd{
90170431Spjd	mtx_lock(&atomic_mtx);
91170431Spjd	*target |= value;
92170431Spjd	mtx_unlock(&atomic_mtx);
93170431Spjd}
94170431Spjd#endif
95170431Spjd
96170431Spjduint8_t
97170431Spjdatomic_or_8_nv(volatile uint8_t *target, uint8_t value)
98170431Spjd{
99170431Spjd	uint8_t newval;
100170431Spjd
101170431Spjd	mtx_lock(&atomic_mtx);
102170431Spjd	newval = (*target |= value);
103170431Spjd	mtx_unlock(&atomic_mtx);
104170431Spjd	return (newval);
105170431Spjd}
106170431Spjd
107219089Spjduint64_t
108219089Spjdatomic_cas_64(volatile uint64_t *target, uint64_t cmp, uint64_t newval)
109170431Spjd{
110219089Spjd	uint64_t oldval;
111170431Spjd
112170431Spjd	mtx_lock(&atomic_mtx);
113219089Spjd	oldval = *target;
114170431Spjd	if (oldval == cmp)
115219089Spjd		*target = newval;
116170431Spjd	mtx_unlock(&atomic_mtx);
117170431Spjd	return (oldval);
118170431Spjd}
119170431Spjd
120219089Spjduint32_t
121219089Spjdatomic_cas_32(volatile uint32_t *target, uint32_t cmp, uint32_t newval)
122170431Spjd{
123219089Spjd	uint32_t oldval;
124170431Spjd
125170431Spjd	mtx_lock(&atomic_mtx);
126170431Spjd	oldval = *target;
127170431Spjd	if (oldval == cmp)
128170431Spjd		*target = newval;
129170431Spjd	mtx_unlock(&atomic_mtx);
130170431Spjd	return (oldval);
131170431Spjd}
132170431Spjd
133170431Spjdvoid
134170431Spjdmembar_producer(void)
135170431Spjd{
136170431Spjd	/* nothing */
137170431Spjd}
138