summaryrefslogtreecommitdiff
path: root/arch/h8300/include/asm/bitops.h
blob: 05999aba1d6ab3647ad67966c6b984b8de17e053 (plain)
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
174
175
176
177
178
179
180
181
182
183
184
185
#ifndef _H8300_BITOPS_H
#define _H8300_BITOPS_H

/*
 * Copyright 1992, Linus Torvalds.
 * Copyright 2002, Yoshinori Sato
 */

#include <linux/compiler.h>

#ifdef __KERNEL__

#ifndef _LINUX_BITOPS_H
#error only <linux/bitops.h> can be included directly
#endif

/*
 * Function prototypes to keep gcc -Wall happy
 */

/*
 * ffz = Find First Zero in word. Undefined if no zero exists,
 * so code should check against ~0UL first..
 */
static inline unsigned long ffz(unsigned long word)
{
	unsigned long result;

	result = -1;
	__asm__("1:\n\t"
		"shlr.l %2\n\t"
		"adds #1,%0\n\t"
		"bcs 1b"
		: "=r"(result)
		: "0"(result), "r"(word));
	return result;
}

#define H8300_GEN_BITOP(FNAME, OP)				\
static inline void FNAME(int nr, volatile unsigned long *addr)	\
{								\
	unsigned char *b_addr;					\
	unsigned char bit = nr & 7;				\
								\
	b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3);	\
	if (__builtin_constant_p(nr)) {				\
		__asm__(OP " %1,%0" : "+WU"(*b_addr) : "i"(nr & 7));	\
	} else {						\
		__asm__(OP " %s1,%0" : "+WU"(*b_addr) : "r"(bit));	\
	}							\
}

/*
 * clear_bit() doesn't provide any barrier for the compiler.
 */
#define smp_mb__before_clear_bit()	barrier()
#define smp_mb__after_clear_bit()	barrier()

H8300_GEN_BITOP(set_bit,    "bset")
H8300_GEN_BITOP(clear_bit,  "bclr")
H8300_GEN_BITOP(change_bit, "bnot")
#define __set_bit(nr, addr)    set_bit((nr), (addr))
#define __clear_bit(nr, addr)  clear_bit((nr), (addr))
#define __change_bit(nr, addr) change_bit((nr), (addr))

#undef H8300_GEN_BITOP

static inline int test_bit(int nr, const unsigned long *addr)
{
	int ret = 0;
	unsigned char *b_addr;
	unsigned char bit = nr & 7;

	b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3);
	if (__builtin_constant_p(nr)) {
		__asm__("bld %Z2,%1\n\t"
			"rotxl %0\n\t"
			: "=r"(ret)
			: "WU"(*b_addr), "i"(nr & 7), "0"(ret) : "cc");
	} else {
		__asm__("btst %w2,%1\n\t"
			"beq 1f\n\t"
			"inc.l #1,%0\n"
			"1:"
			: "=r"(ret)
			: "WU"(*b_addr), "r"(bit), "0"(ret) : "cc");
	}
	return ret;
}

#define __test_bit(nr, addr) test_bit(nr, addr)

#define H8300_GEN_TEST_BITOP(FNNAME, OP)				\
static inline int FNNAME(int nr, void *addr)				\
{									\
	int retval = 0;							\
	char ccrsave;							\
	unsigned char *b_addr;						\
	unsigned char bit = nr & 7;					\
									\
	b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3);		\
	if (__builtin_constant_p(nr)) {					\
		__asm__("stc ccr,%s2\n\t"				\
			"orc #0x80,ccr\n\t"				\
			"bld %4,%1\n\t"					\
			OP " %4,%1\n\t"					\
			"rotxl.l %0\n\t"				\
			"ldc %s2,ccr"					\
			: "=r"(retval), "+WU" (*b_addr), "=&r"(ccrsave)	\
			: "0"(retval), "i"(nr & 7) : "cc");		\
	} else {							\
		__asm__("stc ccr,%t3\n\t"				\
			"orc #0x80,ccr\n\t"				\
			"btst %s3,%1\n\t"				\
			OP " %s3,%1\n\t"				\
			"beq 1f\n\t"					\
			"inc.l #1,%0\n\t"				\
			"1:\n"						\
			"ldc %t3,ccr"					\
			: "=r"(retval), "+WU" (*b_addr)			\
			: "0" (retval), "r"(bit) : "cc");		\
	}								\
	return retval;							\
}									\
									\
static inline int __ ## FNNAME(int nr, void *addr)			\
{									\
	int retval = 0;							\
	unsigned char *b_addr;						\
	unsigned char bit = nr & 7;					\
									\
	b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3);		\
	if (__builtin_constant_p(nr)) {					\
		__asm__("bld %3,%1\n\t"					\
			OP " %3,%1\n\t"					\
			"rotxl.l %0\n\t"				\
			: "=r"(retval), "+WU"(*b_addr)			\
			: "0" (retval), "i"(nr & 7));			\
	} else {							\
		__asm__("btst %s3,%1\n\t"				\
			OP " %s3,%1\n\t"				\
			"beq 1f\n\t"					\
			"inc.l #1,%0\n\t"				\
			"1:"						\
			: "=r"(retval), "+WU"(*b_addr)			\
			: "0" (retval), "r"(bit));			\
	}								\
	return retval;							\
}

H8300_GEN_TEST_BITOP(test_and_set_bit,	  "bset")
H8300_GEN_TEST_BITOP(test_and_clear_bit,  "bclr")
H8300_GEN_TEST_BITOP(test_and_change_bit, "bnot")
#undef H8300_GEN_TEST_BITOP

#include <asm-generic/bitops/ffs.h>

static inline unsigned long __ffs(unsigned long word)
{
	unsigned long result;

	result = -1;
	__asm__("1:\n\t"
		"shlr.l %2\n\t"
		"adds #1,%0\n\t"
		"bcc 1b"
		: "=r" (result)
		: "0"(result), "r"(word));
	return result;
}

#include <asm-generic/bitops/find.h>
#include <asm-generic/bitops/sched.h>
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/lock.h>
#include <asm-generic/bitops/le.h>
#include <asm-generic/bitops/ext2-atomic.h>

#endif /* __KERNEL__ */

#include <asm-generic/bitops/fls.h>
#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>

#endif /* _H8300_BITOPS_H */