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