xref: /kernel/linux/linux-6.6/arch/arm/lib/findbit.S (revision 62306a36)
162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/arch/arm/lib/findbit.S
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 1995-2000 Russell King
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * 16th March 2001 - John Ripley <jripley@sonicblue.com>
862306a36Sopenharmony_ci *   Fixed so that "size" is an exclusive not an inclusive quantity.
962306a36Sopenharmony_ci *   All users of these functions expect exclusive sizes, and may
1062306a36Sopenharmony_ci *   also call with zero size.
1162306a36Sopenharmony_ci * Reworked by rmk.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include <linux/linkage.h>
1462306a36Sopenharmony_ci#include <asm/assembler.h>
1562306a36Sopenharmony_ci#include <asm/unwind.h>
1662306a36Sopenharmony_ci                .text
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#ifdef __ARMEB__
1962306a36Sopenharmony_ci#define SWAB_ENDIAN le
2062306a36Sopenharmony_ci#else
2162306a36Sopenharmony_ci#define SWAB_ENDIAN be
2262306a36Sopenharmony_ci#endif
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci		.macro	find_first, endian, set, name
2562306a36Sopenharmony_ciENTRY(_find_first_\name\()bit_\endian)
2662306a36Sopenharmony_ci	UNWIND(	.fnstart)
2762306a36Sopenharmony_ci		teq	r1, #0
2862306a36Sopenharmony_ci		beq	3f
2962306a36Sopenharmony_ci		mov	r2, #0
3062306a36Sopenharmony_ci1:		ldr	r3, [r0], #4
3162306a36Sopenharmony_ci		.ifeq \set
3262306a36Sopenharmony_ci		mvns	r3, r3			@ invert/test bits
3362306a36Sopenharmony_ci		.else
3462306a36Sopenharmony_ci		movs	r3, r3			@ test bits
3562306a36Sopenharmony_ci		.endif
3662306a36Sopenharmony_ci		.ifc \endian, SWAB_ENDIAN
3762306a36Sopenharmony_ci		bne	.L_found_swab
3862306a36Sopenharmony_ci		.else
3962306a36Sopenharmony_ci		bne	.L_found		@ found the bit?
4062306a36Sopenharmony_ci		.endif
4162306a36Sopenharmony_ci		add	r2, r2, #32		@ next index
4262306a36Sopenharmony_ci2:		cmp	r2, r1			@ any more?
4362306a36Sopenharmony_ci		blo	1b
4462306a36Sopenharmony_ci3:		mov	r0, r1			@ no more bits
4562306a36Sopenharmony_ci		ret	lr
4662306a36Sopenharmony_ci	UNWIND(	.fnend)
4762306a36Sopenharmony_ciENDPROC(_find_first_\name\()bit_\endian)
4862306a36Sopenharmony_ci		.endm
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci		.macro	find_next, endian, set, name
5162306a36Sopenharmony_ciENTRY(_find_next_\name\()bit_\endian)
5262306a36Sopenharmony_ci	UNWIND(	.fnstart)
5362306a36Sopenharmony_ci		cmp	r2, r1
5462306a36Sopenharmony_ci		bhs	3b
5562306a36Sopenharmony_ci		mov	ip, r2, lsr #5		@ word index
5662306a36Sopenharmony_ci		add	r0, r0, ip, lsl #2
5762306a36Sopenharmony_ci		ands	ip, r2, #31		@ bit position
5862306a36Sopenharmony_ci		beq	1b
5962306a36Sopenharmony_ci		ldr	r3, [r0], #4
6062306a36Sopenharmony_ci		.ifeq \set
6162306a36Sopenharmony_ci		mvn	r3, r3			@ invert bits
6262306a36Sopenharmony_ci		.endif
6362306a36Sopenharmony_ci		.ifc \endian, SWAB_ENDIAN
6462306a36Sopenharmony_ci		rev_l	r3, ip
6562306a36Sopenharmony_ci		.if	.Lrev_l_uses_tmp
6662306a36Sopenharmony_ci		@ we need to recompute ip because rev_l will have overwritten
6762306a36Sopenharmony_ci		@ it.
6862306a36Sopenharmony_ci		and	ip, r2, #31		@ bit position
6962306a36Sopenharmony_ci		.endif
7062306a36Sopenharmony_ci		.endif
7162306a36Sopenharmony_ci		movs	r3, r3, lsr ip		@ shift off unused bits
7262306a36Sopenharmony_ci		bne	.L_found
7362306a36Sopenharmony_ci		orr	r2, r2, #31		@ no zero bits
7462306a36Sopenharmony_ci		add	r2, r2, #1		@ align bit pointer
7562306a36Sopenharmony_ci		b	2b			@ loop for next bit
7662306a36Sopenharmony_ci	UNWIND(	.fnend)
7762306a36Sopenharmony_ciENDPROC(_find_next_\name\()bit_\endian)
7862306a36Sopenharmony_ci		.endm
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci		.macro	find_bit, endian, set, name
8162306a36Sopenharmony_ci		find_first \endian, \set, \name
8262306a36Sopenharmony_ci		find_next  \endian, \set, \name
8362306a36Sopenharmony_ci		.endm
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* _find_first_zero_bit_le and _find_next_zero_bit_le */
8662306a36Sopenharmony_ci		find_bit le, 0, zero_
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* _find_first_bit_le and _find_next_bit_le */
8962306a36Sopenharmony_ci		find_bit le, 1
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#ifdef __ARMEB__
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* _find_first_zero_bit_be and _find_next_zero_bit_be */
9462306a36Sopenharmony_ci		find_bit be, 0, zero_
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* _find_first_bit_be and _find_next_bit_be */
9762306a36Sopenharmony_ci		find_bit be, 1
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#endif
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/*
10262306a36Sopenharmony_ci * One or more bits in the LSB of r3 are assumed to be set.
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_ci.L_found_swab:
10562306a36Sopenharmony_ci	UNWIND(	.fnstart)
10662306a36Sopenharmony_ci		rev_l	r3, ip
10762306a36Sopenharmony_ci.L_found:
10862306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 7
10962306a36Sopenharmony_ci		rbit	r3, r3			@ reverse bits
11062306a36Sopenharmony_ci		clz	r3, r3			@ count high zero bits
11162306a36Sopenharmony_ci		add	r0, r2, r3		@ add offset of first set bit
11262306a36Sopenharmony_ci#elif __LINUX_ARM_ARCH__ >= 5
11362306a36Sopenharmony_ci		rsb	r0, r3, #0
11462306a36Sopenharmony_ci		and	r3, r3, r0		@ mask out lowest bit set
11562306a36Sopenharmony_ci		clz	r3, r3			@ count high zero bits
11662306a36Sopenharmony_ci		rsb	r3, r3, #31		@ offset of first set bit
11762306a36Sopenharmony_ci		add	r0, r2, r3		@ add offset of first set bit
11862306a36Sopenharmony_ci#else
11962306a36Sopenharmony_ci		mov	ip, #~0
12062306a36Sopenharmony_ci		tst	r3, ip, lsr #16		@ test bits 0-15
12162306a36Sopenharmony_ci		addeq	r2, r2, #16
12262306a36Sopenharmony_ci		moveq	r3, r3, lsr #16
12362306a36Sopenharmony_ci		tst	r3, #0x00ff
12462306a36Sopenharmony_ci		addeq	r2, r2, #8
12562306a36Sopenharmony_ci		moveq	r3, r3, lsr #8
12662306a36Sopenharmony_ci		tst	r3, #0x000f
12762306a36Sopenharmony_ci		addeq	r2, r2, #4
12862306a36Sopenharmony_ci		moveq	r3, r3, lsr #4
12962306a36Sopenharmony_ci		tst	r3, #0x0003
13062306a36Sopenharmony_ci		addeq	r2, r2, #2
13162306a36Sopenharmony_ci		moveq	r3, r3, lsr #2
13262306a36Sopenharmony_ci		tst	r3, #0x0001
13362306a36Sopenharmony_ci		addeq	r2, r2, #1
13462306a36Sopenharmony_ci		mov	r0, r2
13562306a36Sopenharmony_ci#endif
13662306a36Sopenharmony_ci		cmp	r1, r0			@ Clamp to maxbit
13762306a36Sopenharmony_ci		movlo	r0, r1
13862306a36Sopenharmony_ci		ret	lr
13962306a36Sopenharmony_ci	UNWIND(	.fnend)
140