This source file includes following definitions.
- __xchg_small
- __cmpxchg_small
1
2
3
4
5
6
7 #include <linux/bitops.h>
8 #include <asm/cmpxchg.h>
9
10 unsigned long __xchg_small(volatile void *ptr, unsigned long val, unsigned int size)
11 {
12 u32 old32, new32, load32, mask;
13 volatile u32 *ptr32;
14 unsigned int shift;
15
16
17 WARN_ON((unsigned long)ptr & (size - 1));
18
19
20 mask = GENMASK((size * BITS_PER_BYTE) - 1, 0);
21 val &= mask;
22
23
24
25
26
27
28 shift = (unsigned long)ptr & 0x3;
29 if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
30 shift ^= sizeof(u32) - size;
31 shift *= BITS_PER_BYTE;
32 mask <<= shift;
33
34
35
36
37
38 ptr32 = (volatile u32 *)((unsigned long)ptr & ~0x3);
39 load32 = *ptr32;
40
41 do {
42 old32 = load32;
43 new32 = (load32 & ~mask) | (val << shift);
44 load32 = cmpxchg(ptr32, old32, new32);
45 } while (load32 != old32);
46
47 return (load32 & mask) >> shift;
48 }
49
50 unsigned long __cmpxchg_small(volatile void *ptr, unsigned long old,
51 unsigned long new, unsigned int size)
52 {
53 u32 mask, old32, new32, load32, load;
54 volatile u32 *ptr32;
55 unsigned int shift;
56
57
58 WARN_ON((unsigned long)ptr & (size - 1));
59
60
61 mask = GENMASK((size * BITS_PER_BYTE) - 1, 0);
62 old &= mask;
63 new &= mask;
64
65
66
67
68
69
70 shift = (unsigned long)ptr & 0x3;
71 if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
72 shift ^= sizeof(u32) - size;
73 shift *= BITS_PER_BYTE;
74 mask <<= shift;
75
76
77
78
79
80 ptr32 = (volatile u32 *)((unsigned long)ptr & ~0x3);
81 load32 = *ptr32;
82
83 while (true) {
84
85
86
87
88 load = (load32 & mask) >> shift;
89 if (load != old)
90 return load;
91
92
93
94
95
96
97
98 old32 = (load32 & ~mask) | (old << shift);
99 new32 = (load32 & ~mask) | (new << shift);
100 load32 = cmpxchg(ptr32, old32, new32);
101 if (load32 == old32)
102 return old;
103 }
104 }