1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
#ifndef _SPARC_BITOPS_H
#define _SPARC_BITOPS_H
/*
* Copyright 1994, David S. Miller (davem@caip.rutgers.edu).
*/
/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
* is in the highest of the four bytes and bit '31' is the high bit
* within the first byte. Sparc is BIG-Endian. Unless noted otherwise
* all bit-ops return 0 if bit was previously clear and != 0 otherwise.
*/
/* For now, the sun4c implementation will disable and enable traps
* in order to insure atomicity. Things will have to be different
* for sun4m (ie. SMP) no doubt.
*/
extern __inline__ unsigned int set_bit(unsigned int nr, void *addr)
{
register unsigned long retval, tmp, mask, psr;
__asm__ __volatile__("or %%g0, 0x1, %3\n\t" /* produce the mask */
"sll %3, %4, %3\n\t"
"rd %%psr, %5\n\t" /* read the psr */
"wr %5, 0x20, %%psr\n\t" /* traps disabled */
"ld [%1], %2\n\t" /* critical section */
"and %3, %2, %0\n\t"
"or %3, %2, %2\n\t"
"st %2, [%1]\n\t"
"wr %5, 0x0, %%psr\n\t" : /* re-enable traps */
"=r" (retval) :
"r" (addr), "r" (tmp=0), "r" (mask=0),
"r" (nr), "r" (psr=0));
return retval; /* confuse gcc :-) */
}
extern __inline__ unsigned int clear_bit(unsigned int nr, void *addr)
{
register unsigned long retval, tmp, mask, psr;
__asm__ __volatile__("or %%g0, 0x1, %3\n\t"
"sll %3, %4, %3\n\t"
"rd %%psr, %5\n\t"
"wr %5, 0x20, %%psr\n\t" /* disable traps */
"ld [%1], %2\n\t"
"and %2, %3, %0\n\t" /* get old bit */
"andn %2, %3, %2\n\t" /* set new val */
"st %2, [%1]\n\t"
"wr %5, 0x0, %%psr\n\t" : /* enable traps */
"=r" (retval) :
"r" (addr), "r" (tmp=0), "r" (mask=0),
"r" (nr), "r" (psr=0));
return retval; /* confuse gcc ;-) */
}
extern __inline__ unsigned int change_bit(unsigned int nr, void *addr)
{
register unsigned long retval, tmp, mask, psr;
__asm__ __volatile__("or %%g0, 0x1, %3\n\t"
"sll %3, %4, %3\n\t"
"rd %%psr, %5\n\t"
"wr %5, 0x20, %%psr\n\t" /* disable traps */
"ld [%1], %2\n\t"
"and %3, %2, %0\n\t" /* get old bit val */
"xor %3, %2, %2\n\t" /* set new val */
"st %2, [%1]\n\t"
"wr %5, 0x0, %%psr\n\t" : /* enable traps */
"=r" (retval) :
"r" (addr), "r" (tmp=0), "r" (mask=0),
"r" (nr), "r" (psr=0));
return retval; /* confuse gcc ;-) */
}
/* The following routine need not be atomic. */
extern __inline__ unsigned int test_bit(int nr, void *addr)
{
register unsigned long retval, tmp;
__asm__ __volatile__("ld [%1], %2\n\t"
"or %%g0, 0x1, %0\n\t"
"sll %0, %3, %0\n\t"
"and %0, %2, %0\n\t" :
"=r" (retval) :
"r" (addr), "r" (tmp=0),
"r" (nr));
return retval; /* confuse gcc :> */
}
/* There has to be a faster way to do this, sigh... */
extern __inline__ unsigned long ffz(unsigned long word)
{
register unsigned long cnt, tmp, tmp2;
cnt = 0;
__asm__("or %%g0, %3, %2\n\t"
"1: and %2, 0x1, %1\n\t"
"srl %2, 0x1, %2\n\t"
"cmp %1, 0\n\t"
"bne,a 1b\n\t"
"add %0, 0x1, %0\n\t" :
"=r" (cnt) :
"r" (tmp=0), "r" (tmp2=0), "r" (word));
return cnt;
}
/* find_next_zero_bit() finds the first zero bit in a bit string of length
* 'size' bits, starting the search at bit 'offset'. This is largely based
* on Linus's ALPHA routines, which are pretty portable BTW.
*/
extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
{
unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
unsigned long result = offset & ~31UL;
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset &= 31UL;
if (offset)
{
tmp = *(p++);
tmp |= ~0UL >> (32-offset);
if (size < 32)
goto found_first;
if (~tmp)
goto found_middle;
size -= 32;
result += 32;
}
while (size & ~32UL)
{
if (~(tmp = *(p++)))
goto found_middle;
result += 32;
size -= 32;
}
if (!size)
return result;
tmp = *p;
found_first:
tmp |= ~0UL << size;
found_middle:
return result + ffz(tmp);
}
/* Linus sez that gcc can optimize the following correctly, we'll see if this
* holds on the Sparc as it does for the ALPHA.
*/
#define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0)
#endif /* defined(_SPARC_BITOPS_H) */
|