18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * MSB0 numbered special bitops handling.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * The bits are numbered:
68c2ecf20Sopenharmony_ci *   |0..............63|64............127|128...........191|192...........255|
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * The reason for this bit numbering is the fact that the hardware sets bits
98c2ecf20Sopenharmony_ci * in a bitmap starting at bit 0 (MSB) and we don't want to scan the bitmap
108c2ecf20Sopenharmony_ci * from the 'wrong end'.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/compiler.h>
148c2ecf20Sopenharmony_ci#include <linux/bitops.h>
158c2ecf20Sopenharmony_ci#include <linux/export.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ciunsigned long find_first_bit_inv(const unsigned long *addr, unsigned long size)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	const unsigned long *p = addr;
208c2ecf20Sopenharmony_ci	unsigned long result = 0;
218c2ecf20Sopenharmony_ci	unsigned long tmp;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	while (size & ~(BITS_PER_LONG - 1)) {
248c2ecf20Sopenharmony_ci		if ((tmp = *(p++)))
258c2ecf20Sopenharmony_ci			goto found;
268c2ecf20Sopenharmony_ci		result += BITS_PER_LONG;
278c2ecf20Sopenharmony_ci		size -= BITS_PER_LONG;
288c2ecf20Sopenharmony_ci	}
298c2ecf20Sopenharmony_ci	if (!size)
308c2ecf20Sopenharmony_ci		return result;
318c2ecf20Sopenharmony_ci	tmp = (*p) & (~0UL << (BITS_PER_LONG - size));
328c2ecf20Sopenharmony_ci	if (!tmp)		/* Are any bits set? */
338c2ecf20Sopenharmony_ci		return result + size;	/* Nope. */
348c2ecf20Sopenharmony_cifound:
358c2ecf20Sopenharmony_ci	return result + (__fls(tmp) ^ (BITS_PER_LONG - 1));
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(find_first_bit_inv);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciunsigned long find_next_bit_inv(const unsigned long *addr, unsigned long size,
408c2ecf20Sopenharmony_ci				unsigned long offset)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	const unsigned long *p = addr + (offset / BITS_PER_LONG);
438c2ecf20Sopenharmony_ci	unsigned long result = offset & ~(BITS_PER_LONG - 1);
448c2ecf20Sopenharmony_ci	unsigned long tmp;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	if (offset >= size)
478c2ecf20Sopenharmony_ci		return size;
488c2ecf20Sopenharmony_ci	size -= result;
498c2ecf20Sopenharmony_ci	offset %= BITS_PER_LONG;
508c2ecf20Sopenharmony_ci	if (offset) {
518c2ecf20Sopenharmony_ci		tmp = *(p++);
528c2ecf20Sopenharmony_ci		tmp &= (~0UL >> offset);
538c2ecf20Sopenharmony_ci		if (size < BITS_PER_LONG)
548c2ecf20Sopenharmony_ci			goto found_first;
558c2ecf20Sopenharmony_ci		if (tmp)
568c2ecf20Sopenharmony_ci			goto found_middle;
578c2ecf20Sopenharmony_ci		size -= BITS_PER_LONG;
588c2ecf20Sopenharmony_ci		result += BITS_PER_LONG;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci	while (size & ~(BITS_PER_LONG-1)) {
618c2ecf20Sopenharmony_ci		if ((tmp = *(p++)))
628c2ecf20Sopenharmony_ci			goto found_middle;
638c2ecf20Sopenharmony_ci		result += BITS_PER_LONG;
648c2ecf20Sopenharmony_ci		size -= BITS_PER_LONG;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci	if (!size)
678c2ecf20Sopenharmony_ci		return result;
688c2ecf20Sopenharmony_ci	tmp = *p;
698c2ecf20Sopenharmony_cifound_first:
708c2ecf20Sopenharmony_ci	tmp &= (~0UL << (BITS_PER_LONG - size));
718c2ecf20Sopenharmony_ci	if (!tmp)		/* Are any bits set? */
728c2ecf20Sopenharmony_ci		return result + size;	/* Nope. */
738c2ecf20Sopenharmony_cifound_middle:
748c2ecf20Sopenharmony_ci	return result + (__fls(tmp) ^ (BITS_PER_LONG - 1));
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(find_next_bit_inv);
77