xref: /kvm-unit-tests/lib/arm/bitops.c (revision c2a95639b4cc7eb7f4f05a92c965e6ce5c39bccb)
1 /*
2  * Adapted from
3  *   include/asm-generic/bitops/atomic.h
4  *
5  * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
6  *
7  * This work is licensed under the terms of the GNU GPL, version 2.
8  */
9 #include "libcflat.h"
10 #include <bitops.h>
11 #include <asm/barrier.h>
12 #include <asm/mmu.h>
13 
set_bit(int nr,volatile unsigned long * addr)14 void set_bit(int nr, volatile unsigned long *addr)
15 {
16 	volatile unsigned long *word = addr + BIT_WORD(nr);
17 	unsigned long mask = BIT_MASK(nr);
18 
19 	if (mmu_enabled())
20 		ATOMIC_BITOP("orr", mask, word);
21 	else
22 		*word |= mask;
23 	smp_mb();
24 }
25 
clear_bit(int nr,volatile unsigned long * addr)26 void clear_bit(int nr, volatile unsigned long *addr)
27 {
28 	volatile unsigned long *word = addr + BIT_WORD(nr);
29 	unsigned long mask = BIT_MASK(nr);
30 
31 	if (mmu_enabled())
32 		ATOMIC_BITOP("bic", mask, word);
33 	else
34 		*word &= ~mask;
35 	smp_mb();
36 }
37 
test_bit(int nr,const volatile unsigned long * addr)38 int test_bit(int nr, const volatile unsigned long *addr)
39 {
40 	const volatile unsigned long *word = addr + BIT_WORD(nr);
41 	unsigned long mask = BIT_MASK(nr);
42 
43 	return (*word & mask) != 0;
44 }
45 
test_and_set_bit(int nr,volatile unsigned long * addr)46 int test_and_set_bit(int nr, volatile unsigned long *addr)
47 {
48 	volatile unsigned long *word = addr + BIT_WORD(nr);
49 	unsigned long mask = BIT_MASK(nr);
50 	unsigned long old;
51 
52 	smp_mb();
53 
54 	if (mmu_enabled()) {
55 		ATOMIC_TESTOP("orr", mask, word, old);
56 	} else {
57 		old = *word;
58 		*word = old | mask;
59 	}
60 	smp_mb();
61 
62 	return (old & mask) != 0;
63 }
64 
test_and_clear_bit(int nr,volatile unsigned long * addr)65 int test_and_clear_bit(int nr, volatile unsigned long *addr)
66 {
67 	volatile unsigned long *word = addr + BIT_WORD(nr);
68 	unsigned long mask = BIT_MASK(nr);
69 	unsigned long old;
70 
71 	smp_mb();
72 
73 	if (mmu_enabled()) {
74 		ATOMIC_TESTOP("bic", mask, word, old);
75 	} else {
76 		old = *word;
77 		*word = old & ~mask;
78 	}
79 	smp_mb();
80 
81 	return (old & mask) != 0;
82 }
83