bitops.h 7.0 KB
Newer Older
W
Wolfgang Denk 已提交
1 2 3
/*
 * U-boot - bitops.h Routines for bit operations
 *
4
 * Copyright (c) 2005-2007 Analog Devices Inc.
W
Wolfgang Denk 已提交
5
 *
6
 * SPDX-License-Identifier:	GPL-2.0+
W
Wolfgang Denk 已提交
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
 */

#ifndef _BLACKFIN_BITOPS_H
#define _BLACKFIN_BITOPS_H

/*
 * Copyright 1992, Linus Torvalds.
 */

#include <asm/byteorder.h>
#include <asm/system.h>

#ifdef __KERNEL__
/*
 * Function prototypes to keep gcc -Wall happy
 */

/*
 * The __ functions are not atomic
 */

/*
 * 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 = 0;

	while (word & 1) {
		result++;
		word >>= 1;
	}
	return result;
}

static __inline__ void set_bit(int nr, volatile void *addr)
{
45
	int *a = (int *)addr;
W
Wolfgang Denk 已提交
46 47 48 49 50
	int mask;
	unsigned long flags;

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
51
	local_irq_save(flags);
W
Wolfgang Denk 已提交
52
	*a |= mask;
53
	local_irq_restore(flags);
W
Wolfgang Denk 已提交
54 55 56 57
}

static __inline__ void __set_bit(int nr, volatile void *addr)
{
58
	int *a = (int *)addr;
W
Wolfgang Denk 已提交
59 60 61 62 63 64
	int mask;

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
	*a |= mask;
}
65
#define PLATFORM__SET_BIT
W
Wolfgang Denk 已提交
66 67 68 69 70 71 72 73 74

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

static __inline__ void clear_bit(int nr, volatile void *addr)
{
75
	int *a = (int *)addr;
W
Wolfgang Denk 已提交
76 77 78 79 80
	int mask;
	unsigned long flags;

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
81
	local_irq_save(flags);
W
Wolfgang Denk 已提交
82
	*a &= ~mask;
83
	local_irq_restore(flags);
W
Wolfgang Denk 已提交
84 85 86 87 88
}

static __inline__ void change_bit(int nr, volatile void *addr)
{
	int mask, flags;
89
	unsigned long *ADDR = (unsigned long *)addr;
W
Wolfgang Denk 已提交
90 91 92

	ADDR += nr >> 5;
	mask = 1 << (nr & 31);
93
	local_irq_save(flags);
W
Wolfgang Denk 已提交
94
	*ADDR ^= mask;
95
	local_irq_restore(flags);
W
Wolfgang Denk 已提交
96 97 98 99 100
}

static __inline__ void __change_bit(int nr, volatile void *addr)
{
	int mask;
101
	unsigned long *ADDR = (unsigned long *)addr;
W
Wolfgang Denk 已提交
102 103 104 105 106 107 108 109 110

	ADDR += nr >> 5;
	mask = 1 << (nr & 31);
	*ADDR ^= mask;
}

static __inline__ int test_and_set_bit(int nr, volatile void *addr)
{
	int mask, retval;
111
	volatile unsigned int *a = (volatile unsigned int *)addr;
W
Wolfgang Denk 已提交
112 113 114 115
	unsigned long flags;

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
116
	local_irq_save(flags);
W
Wolfgang Denk 已提交
117 118
	retval = (mask & *a) != 0;
	*a |= mask;
119
	local_irq_restore(flags);
W
Wolfgang Denk 已提交
120 121 122 123 124 125 126

	return retval;
}

static __inline__ int __test_and_set_bit(int nr, volatile void *addr)
{
	int mask, retval;
127
	volatile unsigned int *a = (volatile unsigned int *)addr;
W
Wolfgang Denk 已提交
128 129 130 131 132 133 134 135 136 137 138

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
	retval = (mask & *a) != 0;
	*a |= mask;
	return retval;
}

static __inline__ int test_and_clear_bit(int nr, volatile void *addr)
{
	int mask, retval;
139
	volatile unsigned int *a = (volatile unsigned int *)addr;
W
Wolfgang Denk 已提交
140 141 142 143
	unsigned long flags;

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
144
	local_irq_save(flags);
W
Wolfgang Denk 已提交
145 146
	retval = (mask & *a) != 0;
	*a &= ~mask;
147
	local_irq_restore(flags);
W
Wolfgang Denk 已提交
148 149 150 151 152 153 154

	return retval;
}

static __inline__ int __test_and_clear_bit(int nr, volatile void *addr)
{
	int mask, retval;
155
	volatile unsigned int *a = (volatile unsigned int *)addr;
W
Wolfgang Denk 已提交
156 157 158 159 160 161 162 163 164 165 166

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
	retval = (mask & *a) != 0;
	*a &= ~mask;
	return retval;
}

static __inline__ int test_and_change_bit(int nr, volatile void *addr)
{
	int mask, retval;
167
	volatile unsigned int *a = (volatile unsigned int *)addr;
W
Wolfgang Denk 已提交
168 169 170 171
	unsigned long flags;

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
172
	local_irq_save(flags);
W
Wolfgang Denk 已提交
173 174
	retval = (mask & *a) != 0;
	*a ^= mask;
175
	local_irq_restore(flags);
W
Wolfgang Denk 已提交
176 177 178 179 180 181 182

	return retval;
}

static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
{
	int mask, retval;
183
	volatile unsigned int *a = (volatile unsigned int *)addr;
W
Wolfgang Denk 已提交
184 185 186 187 188 189 190 191 192 193 194

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
	retval = (mask & *a) != 0;
	*a ^= mask;
	return retval;
}

/*
 * This routine doesn't need to be atomic.
 */
195
static __inline__ int __constant_test_bit(int nr, const volatile void *addr)
W
Wolfgang Denk 已提交
196 197
{
	return ((1UL << (nr & 31)) &
198
		(((const volatile unsigned int *)addr)[nr >> 5])) != 0;
W
Wolfgang Denk 已提交
199 200 201 202
}

static __inline__ int __test_bit(int nr, volatile void *addr)
{
203
	int *a = (int *)addr;
W
Wolfgang Denk 已提交
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
	int mask;

	a += nr >> 5;
	mask = 1 << (nr & 0x1f);
	return ((mask & *a) != 0);
}

#define	test_bit(nr,addr) \
(__builtin_constant_p(nr) ? \
 __constant_test_bit((nr),(addr)) : \
 __test_bit((nr),(addr)))

#define	find_first_zero_bit(addr, size) \
	find_next_zero_bit((addr), (size), 0)

static __inline__ int find_next_zero_bit(void *addr, int size, int offset)
{
221
	unsigned long *p = ((unsigned long *)addr) + (offset >> 5);
W
Wolfgang Denk 已提交
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
	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 & ~31UL) {
		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);
}

/*
 * hweightN: returns the hamming weight (i.e. the number
 * of bits set) of a N-bit word
 */

#define hweight32(x)	generic_hweight32(x)
#define hweight16(x)	generic_hweight16(x)
#define hweight8(x)	generic_hweight8(x)

static __inline__ int ext2_set_bit(int nr, volatile void *addr)
{
	int mask, retval;
	unsigned long flags;
268
	volatile unsigned char *ADDR = (unsigned char *)addr;
W
Wolfgang Denk 已提交
269 270 271

	ADDR += nr >> 3;
	mask = 1 << (nr & 0x07);
272
	local_irq_save(flags);
W
Wolfgang Denk 已提交
273 274
	retval = (mask & *ADDR) != 0;
	*ADDR |= mask;
275
	local_irq_restore(flags);
W
Wolfgang Denk 已提交
276 277 278 279 280 281 282
	return retval;
}

static __inline__ int ext2_clear_bit(int nr, volatile void *addr)
{
	int mask, retval;
	unsigned long flags;
283
	volatile unsigned char *ADDR = (unsigned char *)addr;
W
Wolfgang Denk 已提交
284 285 286

	ADDR += nr >> 3;
	mask = 1 << (nr & 0x07);
287
	local_irq_save(flags);
W
Wolfgang Denk 已提交
288 289
	retval = (mask & *ADDR) != 0;
	*ADDR &= ~mask;
290
	local_irq_restore(flags);
W
Wolfgang Denk 已提交
291 292 293 294 295 296
	return retval;
}

static __inline__ int ext2_test_bit(int nr, const volatile void *addr)
{
	int mask;
297
	const volatile unsigned char *ADDR = (const unsigned char *)addr;
W
Wolfgang Denk 已提交
298 299 300 301 302 303 304 305 306 307 308

	ADDR += nr >> 3;
	mask = 1 << (nr & 0x07);
	return ((mask & *ADDR) != 0);
}

#define ext2_find_first_zero_bit(addr, size) \
	ext2_find_next_zero_bit((addr), (size), 0)

static __inline__ unsigned long ext2_find_next_zero_bit(void *addr,
							unsigned long size,
309
							unsigned long offset)
W
Wolfgang Denk 已提交
310
{
311
	unsigned long *p = ((unsigned long *)addr) + (offset >> 5);
W
Wolfgang Denk 已提交
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
	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 & ~31UL) {
		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);
}

/* Bitmap functions for the minix filesystem. */
#define minix_test_and_set_bit(nr,addr)		test_and_set_bit(nr,addr)
#define minix_set_bit(nr,addr)			set_bit(nr,addr)
#define minix_test_and_clear_bit(nr,addr)	test_and_clear_bit(nr,addr)
#define minix_test_bit(nr,addr)			test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size)	find_first_zero_bit(addr,size)

#endif

#endif