bitops_mm.h 11 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10
#ifndef _M68K_BITOPS_H
#define _M68K_BITOPS_H
/*
 * Copyright 1992, Linus Torvalds.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 */

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

Linus Torvalds's avatar
Linus Torvalds committed
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
#include <linux/compiler.h>

/*
 * Require 68020 or better.
 *
 * They use the standard big-endian m680x0 bit ordering.
 */

#define test_and_set_bit(nr,vaddr) \
  (__builtin_constant_p(nr) ? \
   __constant_test_and_set_bit(nr, vaddr) : \
   __generic_test_and_set_bit(nr, vaddr))

#define __test_and_set_bit(nr,vaddr) test_and_set_bit(nr,vaddr)

static inline int __constant_test_and_set_bit(int nr, unsigned long *vaddr)
{
	char *p = (char *)vaddr + (nr ^ 31) / 8;
	char retval;

	__asm__ __volatile__ ("bset %2,%1; sne %0"
			: "=d" (retval), "+m" (*p)
			: "di" (nr & 7));

	return retval;
}

static inline int __generic_test_and_set_bit(int nr, unsigned long *vaddr)
{
	char retval;

	__asm__ __volatile__ ("bfset %2{%1:#1}; sne %0"
			: "=d" (retval) : "d" (nr^31), "o" (*vaddr) : "memory");

	return retval;
}

#define set_bit(nr,vaddr) \
  (__builtin_constant_p(nr) ? \
   __constant_set_bit(nr, vaddr) : \
   __generic_set_bit(nr, vaddr))

#define __set_bit(nr,vaddr) set_bit(nr,vaddr)

static inline void __constant_set_bit(int nr, volatile unsigned long *vaddr)
{
	char *p = (char *)vaddr + (nr ^ 31) / 8;
	__asm__ __volatile__ ("bset %1,%0"
			: "+m" (*p) : "di" (nr & 7));
}

static inline void __generic_set_bit(int nr, volatile unsigned long *vaddr)
{
	__asm__ __volatile__ ("bfset %1{%0:#1}"
			: : "d" (nr^31), "o" (*vaddr) : "memory");
}

#define test_and_clear_bit(nr,vaddr) \
  (__builtin_constant_p(nr) ? \
   __constant_test_and_clear_bit(nr, vaddr) : \
   __generic_test_and_clear_bit(nr, vaddr))

#define __test_and_clear_bit(nr,vaddr) test_and_clear_bit(nr,vaddr)

static inline int __constant_test_and_clear_bit(int nr, unsigned long *vaddr)
{
	char *p = (char *)vaddr + (nr ^ 31) / 8;
	char retval;

	__asm__ __volatile__ ("bclr %2,%1; sne %0"
			: "=d" (retval), "+m" (*p)
			: "di" (nr & 7));

	return retval;
}

static inline int __generic_test_and_clear_bit(int nr, unsigned long *vaddr)
{
	char retval;

	__asm__ __volatile__ ("bfclr %2{%1:#1}; sne %0"
			: "=d" (retval) : "d" (nr^31), "o" (*vaddr) : "memory");

	return retval;
}

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

#define clear_bit(nr,vaddr) \
  (__builtin_constant_p(nr) ? \
   __constant_clear_bit(nr, vaddr) : \
   __generic_clear_bit(nr, vaddr))
#define __clear_bit(nr,vaddr) clear_bit(nr,vaddr)

static inline void __constant_clear_bit(int nr, volatile unsigned long *vaddr)
{
	char *p = (char *)vaddr + (nr ^ 31) / 8;
	__asm__ __volatile__ ("bclr %1,%0"
			: "+m" (*p) : "di" (nr & 7));
}

static inline void __generic_clear_bit(int nr, volatile unsigned long *vaddr)
{
	__asm__ __volatile__ ("bfclr %1{%0:#1}"
			: : "d" (nr^31), "o" (*vaddr) : "memory");
}

#define test_and_change_bit(nr,vaddr) \
  (__builtin_constant_p(nr) ? \
   __constant_test_and_change_bit(nr, vaddr) : \
   __generic_test_and_change_bit(nr, vaddr))

#define __test_and_change_bit(nr,vaddr) test_and_change_bit(nr,vaddr)
#define __change_bit(nr,vaddr) change_bit(nr,vaddr)

static inline int __constant_test_and_change_bit(int nr, unsigned long *vaddr)
{
	char *p = (char *)vaddr + (nr ^ 31) / 8;
	char retval;

	__asm__ __volatile__ ("bchg %2,%1; sne %0"
			: "=d" (retval), "+m" (*p)
			: "di" (nr & 7));

	return retval;
}

static inline int __generic_test_and_change_bit(int nr, unsigned long *vaddr)
{
	char retval;

	__asm__ __volatile__ ("bfchg %2{%1:#1}; sne %0"
			: "=d" (retval) : "d" (nr^31), "o" (*vaddr) : "memory");

	return retval;
}

#define change_bit(nr,vaddr) \
  (__builtin_constant_p(nr) ? \
   __constant_change_bit(nr, vaddr) : \
   __generic_change_bit(nr, vaddr))

static inline void __constant_change_bit(int nr, unsigned long *vaddr)
{
	char *p = (char *)vaddr + (nr ^ 31) / 8;
	__asm__ __volatile__ ("bchg %1,%0"
			: "+m" (*p) : "di" (nr & 7));
}

static inline void __generic_change_bit(int nr, unsigned long *vaddr)
{
	__asm__ __volatile__ ("bfchg %1{%0:#1}"
			: : "d" (nr^31), "o" (*vaddr) : "memory");
}

static inline int test_bit(int nr, const unsigned long *vaddr)
{
	return (vaddr[nr >> 5] & (1UL << (nr & 31))) != 0;
}

static inline int find_first_zero_bit(const unsigned long *vaddr,
				      unsigned size)
{
	const unsigned long *p = vaddr;
	int res = 32;
184
	unsigned int words;
Linus Torvalds's avatar
Linus Torvalds committed
185 186 187 188 189
	unsigned long num;

	if (!size)
		return 0;

190
	words = (size + 31) >> 5;
Linus Torvalds's avatar
Linus Torvalds committed
191
	while (!(num = ~*p++)) {
192
		if (!--words)
Linus Torvalds's avatar
Linus Torvalds committed
193 194 195 196 197 198 199
			goto out;
	}

	__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
			      : "=d" (res) : "d" (num & -num));
	res ^= 31;
out:
200 201
	res += ((long)p - (long)vaddr - 4) * 8;
	return res < size ? res : size;
Linus Torvalds's avatar
Linus Torvalds committed
202
}
203
#define find_first_zero_bit find_first_zero_bit
Linus Torvalds's avatar
Linus Torvalds committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220

static inline int find_next_zero_bit(const unsigned long *vaddr, int size,
				     int offset)
{
	const unsigned long *p = vaddr + (offset >> 5);
	int bit = offset & 31UL, res;

	if (offset >= size)
		return size;

	if (bit) {
		unsigned long num = ~*p++ & (~0UL << bit);
		offset -= bit;

		/* Look for zero in first longword */
		__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
				      : "=d" (res) : "d" (num & -num));
221 222 223 224
		if (res < 32) {
			offset += res ^ 31;
			return offset < size ? offset : size;
		}
Linus Torvalds's avatar
Linus Torvalds committed
225
		offset += 32;
226 227 228

		if (offset >= size)
			return size;
Linus Torvalds's avatar
Linus Torvalds committed
229 230
	}
	/* No zero yet, search remaining full bytes for a zero */
231
	return offset + find_first_zero_bit(p, size - offset);
Linus Torvalds's avatar
Linus Torvalds committed
232
}
233
#define find_next_zero_bit find_next_zero_bit
Linus Torvalds's avatar
Linus Torvalds committed
234 235 236 237 238

static inline int find_first_bit(const unsigned long *vaddr, unsigned size)
{
	const unsigned long *p = vaddr;
	int res = 32;
239
	unsigned int words;
Linus Torvalds's avatar
Linus Torvalds committed
240 241 242 243 244
	unsigned long num;

	if (!size)
		return 0;

245
	words = (size + 31) >> 5;
Linus Torvalds's avatar
Linus Torvalds committed
246
	while (!(num = *p++)) {
247
		if (!--words)
Linus Torvalds's avatar
Linus Torvalds committed
248 249 250 251 252 253 254
			goto out;
	}

	__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
			      : "=d" (res) : "d" (num & -num));
	res ^= 31;
out:
255 256
	res += ((long)p - (long)vaddr - 4) * 8;
	return res < size ? res : size;
Linus Torvalds's avatar
Linus Torvalds committed
257
}
258
#define find_first_bit find_first_bit
Linus Torvalds's avatar
Linus Torvalds committed
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

static inline int find_next_bit(const unsigned long *vaddr, int size,
				int offset)
{
	const unsigned long *p = vaddr + (offset >> 5);
	int bit = offset & 31UL, res;

	if (offset >= size)
		return size;

	if (bit) {
		unsigned long num = *p++ & (~0UL << bit);
		offset -= bit;

		/* Look for one in first longword */
		__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
				      : "=d" (res) : "d" (num & -num));
276 277 278 279
		if (res < 32) {
			offset += res ^ 31;
			return offset < size ? offset : size;
		}
Linus Torvalds's avatar
Linus Torvalds committed
280
		offset += 32;
281 282 283

		if (offset >= size)
			return size;
Linus Torvalds's avatar
Linus Torvalds committed
284 285
	}
	/* No one yet, search remaining full bytes for a one */
286
	return offset + find_first_bit(p, size - offset);
Linus Torvalds's avatar
Linus Torvalds committed
287
}
288
#define find_next_bit find_next_bit
Linus Torvalds's avatar
Linus Torvalds committed
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333

/*
 * 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)
{
	int res;

	__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
			      : "=d" (res) : "d" (~word & -~word));
	return res ^ 31;
}

#ifdef __KERNEL__

/*
 * ffs: find first bit set. This is defined the same way as
 * the libc and compiler builtin ffs routines, therefore
 * differs in spirit from the above ffz (man ffs).
 */

static inline int ffs(int x)
{
	int cnt;

	asm ("bfffo %1{#0:#0},%0" : "=d" (cnt) : "dm" (x & -x));

	return 32 - cnt;
}
#define __ffs(x) (ffs(x) - 1)

/*
 * fls: find last bit set.
 */

static inline int fls(int x)
{
	int cnt;

	asm ("bfffo %1{#0,#0},%0" : "=d" (cnt) : "dm" (x));

	return 32 - cnt;
}

Rusty Russell's avatar
Rusty Russell committed
334 335 336 337 338
static inline int __fls(int x)
{
	return fls(x) - 1;
}

339 340 341
#include <asm-generic/bitops/fls64.h>
#include <asm-generic/bitops/sched.h>
#include <asm-generic/bitops/hweight.h>
Nick Piggin's avatar
Nick Piggin committed
342
#include <asm-generic/bitops/lock.h>
Linus Torvalds's avatar
Linus Torvalds committed
343

344 345 346 347 348 349
/* Bitmap functions for the little endian bitmap. */

static inline void __set_bit_le(int nr, void *addr)
{
	__set_bit(nr ^ 24, addr);
}
Linus Torvalds's avatar
Linus Torvalds committed
350

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
static inline void __clear_bit_le(int nr, void *addr)
{
	__clear_bit(nr ^ 24, addr);
}

static inline int __test_and_set_bit_le(int nr, void *addr)
{
	return __test_and_set_bit(nr ^ 24, addr);
}

static inline int test_and_set_bit_le(int nr, void *addr)
{
	return test_and_set_bit(nr ^ 24, addr);
}

static inline int __test_and_clear_bit_le(int nr, void *addr)
{
	return __test_and_clear_bit(nr ^ 24, addr);
}
Linus Torvalds's avatar
Linus Torvalds committed
370

371 372 373 374 375 376
static inline int test_and_clear_bit_le(int nr, void *addr)
{
	return test_and_clear_bit(nr ^ 24, addr);
}

static inline int test_bit_le(int nr, const void *vaddr)
377 378 379 380 381
{
	const unsigned char *p = vaddr;
	return (p[nr >> 3] & (1U << (nr & 7))) != 0;
}

382
static inline int find_first_zero_bit_le(const void *vaddr, unsigned size)
383 384
{
	const unsigned long *p = vaddr, *addr = vaddr;
385 386
	int res = 0;
	unsigned int words;
387 388 389 390

	if (!size)
		return 0;

391 392 393 394
	words = (size >> 5) + ((size & 31) > 0);
	while (*p++ == ~0UL) {
		if (--words == 0)
			goto out;
395 396 397 398
	}

	--p;
	for (res = 0; res < 32; res++)
399
		if (!test_bit_le(res, p))
400
			break;
401 402 403
out:
	res += (p - addr) * 32;
	return res < size ? res : size;
404
}
405
#define find_first_zero_bit_le find_first_zero_bit_le
406

407
static inline unsigned long find_next_zero_bit_le(const void *addr,
408
		unsigned long size, unsigned long offset)
409
{
410
	const unsigned long *p = addr;
411 412 413 414 415
	int bit = offset & 31UL, res;

	if (offset >= size)
		return size;

416 417
	p += offset >> 5;

418
	if (bit) {
419
		offset -= bit;
420 421
		/* Look for zero in first longword */
		for (res = bit; res < 32; res++)
422 423 424 425
			if (!test_bit_le(res, p)) {
				offset += res;
				return offset < size ? offset : size;
			}
426
		p++;
427
		offset += 32;
428 429 430

		if (offset >= size)
			return size;
431 432
	}
	/* No zero yet, search remaining full bytes for a zero */
433
	return offset + find_first_zero_bit_le(p, size - offset);
434
}
435
#define find_next_zero_bit_le find_next_zero_bit_le
436

437
static inline int find_first_bit_le(const void *vaddr, unsigned size)
438 439
{
	const unsigned long *p = vaddr, *addr = vaddr;
440 441
	int res = 0;
	unsigned int words;
442 443 444 445

	if (!size)
		return 0;

446
	words = (size >> 5) + ((size & 31) > 0);
447
	while (*p++ == 0UL) {
448 449
		if (--words == 0)
			goto out;
450 451 452 453
	}

	--p;
	for (res = 0; res < 32; res++)
454
		if (test_bit_le(res, p))
455
			break;
456 457 458
out:
	res += (p - addr) * 32;
	return res < size ? res : size;
459
}
460
#define find_first_bit_le find_first_bit_le
461

462
static inline unsigned long find_next_bit_le(const void *addr,
463
		unsigned long size, unsigned long offset)
464
{
465
	const unsigned long *p = addr;
466 467 468 469 470
	int bit = offset & 31UL, res;

	if (offset >= size)
		return size;

471 472
	p += offset >> 5;

473
	if (bit) {
474
		offset -= bit;
475 476
		/* Look for one in first longword */
		for (res = bit; res < 32; res++)
477 478 479 480
			if (test_bit_le(res, p)) {
				offset += res;
				return offset < size ? offset : size;
			}
481
		p++;
482
		offset += 32;
483 484 485

		if (offset >= size)
			return size;
486 487
	}
	/* No set bit yet, search remaining full bytes for a set bit */
488
	return offset + find_first_bit_le(p, size - offset);
489
}
490
#define find_next_bit_le find_next_bit_le
491

492 493 494 495 496 497 498
/* Bitmap functions for the ext2 filesystem. */

#define ext2_set_bit_atomic(lock, nr, addr)	\
	test_and_set_bit_le(nr, addr)
#define ext2_clear_bit_atomic(lock, nr, addr)	\
	test_and_clear_bit_le(nr, addr)

Linus Torvalds's avatar
Linus Torvalds committed
499 500 501
#endif /* __KERNEL__ */

#endif /* _M68K_BITOPS_H */