diff options
30 files changed, 168 insertions, 111 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 4017b5f721e3..8f5ed869c792 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4578,7 +4578,9 @@ F: arch/*/lib/bitops.c F: include/asm-generic/bitops F: include/asm-generic/bitops.h F: include/linux/bitops.h +F: include/linux/bitrev.h F: include/linux/count_zeros.h +F: lib/bitrev.c F: lib/hweight.c F: lib/test_bitops.c F: lib/tests/bitops_kunit.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 73e6647bea46..9d3fe7ee97a8 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -83,7 +83,7 @@ config ARM select HARDIRQS_SW_RESEND select HAS_IOPORT select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT - select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 + select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 && BITREVERSE select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU && (!PREEMPT_RT || !SMP) select HAVE_ARCH_KFENCE if MMU && !XIP_KERNEL select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 5f5597141c15..b3afe0688919 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -149,7 +149,7 @@ config ARM64 select HAVE_ACPI_APEI if (ACPI && EFI) select HAVE_ALIGNED_STRUCT_PAGE select HAVE_ARCH_AUDITSYSCALL - select HAVE_ARCH_BITREVERSE + select HAVE_ARCH_BITREVERSE if BITREVERSE select HAVE_ARCH_COMPILER_H select HAVE_ARCH_HUGE_VMALLOC select HAVE_ARCH_HUGE_VMAP diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 3f69c5d7e48e..bec7cc1d72ee 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -114,7 +114,7 @@ config LOONGARCH select HAS_IOPORT select HAVE_ALIGNED_STRUCT_PAGE if 64BIT select HAVE_ARCH_AUDITSYSCALL - select HAVE_ARCH_BITREVERSE if 64BIT + select HAVE_ARCH_BITREVERSE if 64BIT && BITREVERSE select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN if 64BIT diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 323ca084e79a..700a8612ff67 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2020,7 +2020,7 @@ config CPU_MIPSR6 default y if CPU_MIPS32_R6 || CPU_MIPS64_R6 select CPU_HAS_RIXI select CPU_HAS_DIEI if !CPU_DIEI_BROKEN - select HAVE_ARCH_BITREVERSE + select HAVE_ARCH_BITREVERSE if BITREVERSE select MIPS_ASID_BITS_VARIABLE select MIPS_SPRAM diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a25830da9640..33d532c86182 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -103,6 +103,7 @@ config RISCV select FUNCTION_ALIGNMENT_8B if DYNAMIC_FTRACE_WITH_CALL_OPS select GENERIC_ARCH_TOPOLOGY select GENERIC_ATOMIC64 if !64BIT + select GENERIC_BITREVERSE if HAVE_ARCH_BITREVERSE select GENERIC_CLOCKEVENTS_BROADCAST if SMP select GENERIC_CPU_DEVICES select GENERIC_CPU_VULNERABILITIES @@ -126,6 +127,7 @@ config RISCV select HAS_IOPORT if MMU select HAVE_ALIGNED_STRUCT_PAGE select HAVE_ARCH_AUDITSYSCALL + select HAVE_ARCH_BITREVERSE if RISCV_ISA_ZBKB && BITREVERSE select HAVE_ARCH_HUGE_VMALLOC if HAVE_ARCH_HUGE_VMAP select HAVE_ARCH_HUGE_VMAP if MMU && 64BIT select HAVE_ARCH_JUMP_LABEL diff --git a/arch/riscv/include/asm/bitrev.h b/arch/riscv/include/asm/bitrev.h new file mode 100644 index 000000000000..4b9b8d34cc3b --- /dev/null +++ b/arch/riscv/include/asm/bitrev.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_BITREV_H +#define __ASM_BITREV_H + +#include <linux/types.h> +#include <asm/cpufeature-macros.h> +#include <asm/hwcap.h> +#include <asm-generic/bitops/__bitrev.h> + +static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x) +{ + unsigned long result; + + if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZBKB)) + return generic___bitrev32(x); + + asm volatile( + ".option push\n" + ".option arch,+zbkb\n" + "rev8 %0, %1\n" + "brev8 %0, %0\n" + ".option pop" + : "=r" (result) : "r" ((long)x) + ); + + return result >> (__riscv_xlen - 32); +} + +static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x) +{ + return __arch_bitrev32(x) >> 16; +} + +static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x) +{ + unsigned long result; + + if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZBKB)) + return generic___bitrev8(x); + + asm volatile( + ".option push\n" + ".option arch,+zbkb\n" + "brev8 %0, %1\n" + ".option pop" + : "=r" (result) : "r" ((long)x) + ); + + return result; +} +#endif diff --git a/arch/x86/include/asm/extable_fixup_types.h b/arch/x86/include/asm/extable_fixup_types.h index 906b0d5541e8..fd0cfb472103 100644 --- a/arch/x86/include/asm/extable_fixup_types.h +++ b/arch/x86/include/asm/extable_fixup_types.h @@ -2,15 +2,10 @@ #ifndef _ASM_X86_EXTABLE_FIXUP_TYPES_H #define _ASM_X86_EXTABLE_FIXUP_TYPES_H -/* - * Our IMM is signed, as such it must live at the top end of the word. Also, - * since C99 hex constants are of ambiguous type, force cast the mask to 'int' - * so that FIELD_GET() will DTRT and sign extend the value when it extracts it. - */ -#define EX_DATA_TYPE_MASK ((int)0x000000FF) -#define EX_DATA_REG_MASK ((int)0x00000F00) -#define EX_DATA_FLAG_MASK ((int)0x0000F000) -#define EX_DATA_IMM_MASK ((int)0xFFFF0000) +#define EX_DATA_TYPE_MASK (0x000000FF) +#define EX_DATA_REG_MASK (0x00000F00) +#define EX_DATA_FLAG_MASK (0x0000F000) +#define EX_DATA_IMM_MASK (0xFFFF0000) #define EX_DATA_REG_SHIFT 8 #define EX_DATA_FLAG_SHIFT 12 diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index 6b9ff1c6cafa..ceb8d03191ab 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -322,7 +322,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code, type = FIELD_GET(EX_DATA_TYPE_MASK, e->data); reg = FIELD_GET(EX_DATA_REG_MASK, e->data); - imm = FIELD_GET(EX_DATA_IMM_MASK, e->data); + imm = FIELD_GET_SIGNED(EX_DATA_IMM_MASK, e->data); switch (type) { case EX_TYPE_DEFAULT: diff --git a/drivers/iio/adc/intel_dc_ti_adc.c b/drivers/iio/adc/intel_dc_ti_adc.c index 0fe34f1c338e..b5afad713e2d 100644 --- a/drivers/iio/adc/intel_dc_ti_adc.c +++ b/drivers/iio/adc/intel_dc_ti_adc.c @@ -290,8 +290,8 @@ static int dc_ti_adc_probe(struct platform_device *pdev) if (ret) return ret; - info->vbat_zse = sign_extend32(FIELD_GET(DC_TI_VBAT_ZSE, val), 3); - info->vbat_ge = sign_extend32(FIELD_GET(DC_TI_VBAT_GE, val), 3); + info->vbat_zse = FIELD_GET_SIGNED(DC_TI_VBAT_ZSE, val); + info->vbat_ge = FIELD_GET_SIGNED(DC_TI_VBAT_GE, val); dev_dbg(dev, "vbat-zse %d vbat-ge %d\n", info->vbat_zse, info->vbat_ge); diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 140c422773f6..c8a04f185dbb 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -859,9 +859,9 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx) c->f[0] = FIELD_GET(GENMASK(22, 21), val); c->f[1] = FIELD_GET(GENMASK(14, 13), val); c->f[2] = FIELD_GET(GENMASK(6, 5), val); - c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5); - c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5); - c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5); + c->r[0] = FIELD_GET_SIGNED(GENMASK(28, 23), val); + c->r[1] = FIELD_GET_SIGNED(GENMASK(20, 15), val); + c->r[2] = FIELD_GET_SIGNED(GENMASK(12, 7), val); return 0; } @@ -914,9 +914,9 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx) c->f[0] = FIELD_GET(GENMASK(24, 23), val); c->f[1] = FIELD_GET(GENMASK(16, 15), val); c->f[2] = FIELD_GET(GENMASK(8, 7), val); - c->r[0] = sign_extend32(FIELD_GET(GENMASK(30, 25), val), 5); - c->r[1] = sign_extend32(FIELD_GET(GENMASK(22, 17), val), 5); - c->r[2] = sign_extend32(FIELD_GET(GENMASK(14, 7), val), 5); + c->r[0] = FIELD_GET_SIGNED(GENMASK(30, 25), val); + c->r[1] = FIELD_GET_SIGNED(GENMASK(22, 17), val); + c->r[2] = FIELD_GET_SIGNED(GENMASK(14, 7), val); return 0; } diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 9b489766e457..2f2771096ed7 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -392,7 +392,7 @@ static int bme280_read_calib(struct bmp280_data *data) h4_lower = FIELD_GET(BME280_COMP_H4_MASK_LOW, tmp_1); calib->H4 = sign_extend32(h4_upper | h4_lower, 11); tmp_3 = get_unaligned_le16(&data->bme280_humid_cal_buf[H5]); - calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, tmp_3), 11); + calib->H5 = FIELD_GET_SIGNED(BME280_COMP_H5_MASK, tmp_3); calib->H6 = data->bme280_humid_cal_buf[H6]; return 0; diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index aa42c2b1a369..69baf654c9c0 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -297,7 +297,7 @@ static int mcp9600_read_thresh(struct iio_dev *indio_dev, * Temperature is stored in two’s complement format in * bits(15:2), LSB is 0.25 degree celsius. */ - *val = sign_extend32(FIELD_GET(MCP9600_ALERT_LIMIT_MASK, ret), 13); + *val = FIELD_GET_SIGNED(MCP9600_ALERT_LIMIT_MASK, ret); *val2 = 4; return IIO_VAL_FRACTIONAL; case IIO_EV_INFO_HYSTERESIS: diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c index 463399413318..8679b21fd3fd 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c @@ -334,8 +334,8 @@ static void _check_addc(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) for (i = 0; i < ADDC_T_AVG; i++) { tmp = rtw89_phy_read32_mask(rtwdev, R_DBG32_D, MASKDWORD); - dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11); - dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11); + dc_re += FIELD_GET_SIGNED(0xfff000, tmp); + dc_im += FIELD_GET_SIGNED(0xfff, tmp); } dc_re /= ADDC_T_AVG; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index 65b839323e3e..df5fbae50ff5 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -206,9 +206,9 @@ static void rtw8852bx_efuse_parsing_tssi(struct rtw89_dev *rtwdev, static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low) { if (high) - *high = sign_extend32(FIELD_GET(GENMASK(7, 4), data), 3); + *high = FIELD_GET_SIGNED(GENMASK(7, 4), data); if (low) - *low = sign_extend32(FIELD_GET(GENMASK(3, 0), data), 3); + *low = FIELD_GET_SIGNED(GENMASK(3, 0), data); return data != 0xff; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c index 0d443edfe259..5cfacc10e7c8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c @@ -497,8 +497,8 @@ static void _check_addc(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) for (i = 0; i < ADDC_T_AVG; i++) { tmp = rtw89_phy_read32_mask(rtwdev, R_DBG32_D, MASKDWORD); - dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11); - dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11); + dc_re += FIELD_GET_SIGNED(0xfff000, tmp); + dc_im += FIELD_GET_SIGNED(0xfff, tmp); } dc_re /= ADDC_T_AVG; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 3861cce42b1b..80821885b08e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -565,9 +565,9 @@ static void rtw8852c_efuse_parsing_tssi(struct rtw89_dev *rtwdev, static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low) { if (high) - *high = sign_extend32(FIELD_GET(GENMASK(7, 4), data), 3); + *high = FIELD_GET_SIGNED(GENMASK(7, 4), data); if (low) - *low = sign_extend32(FIELD_GET(GENMASK(3, 0), data), 3); + *low = FIELD_GET_SIGNED(GENMASK(3, 0), data); return data != 0xff; } diff --git a/drivers/ptp/ptp_fc3.c b/drivers/ptp/ptp_fc3.c index 70002500170e..f0e000428a3f 100644 --- a/drivers/ptp/ptp_fc3.c +++ b/drivers/ptp/ptp_fc3.c @@ -55,8 +55,8 @@ static s64 tdc_meas2offset(struct idtfc3 *idtfc3, u64 meas_read) { s64 coarse, fine; - fine = sign_extend64(FIELD_GET(FINE_MEAS_MASK, meas_read), 12); - coarse = sign_extend64(FIELD_GET(COARSE_MEAS_MASK, meas_read), (39 - 13)); + fine = FIELD_GET_SIGNED(FINE_MEAS_MASK, meas_read); + coarse = FIELD_GET_SIGNED(COARSE_MEAS_MASK, meas_read); fine = div64_s64(fine * NSEC_PER_SEC, idtfc3->tdc_apll_freq * 62LL); coarse = div64_s64(coarse * NSEC_PER_SEC, idtfc3->time_ref_freq); diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index 6c09da7738e1..6bafdec637ae 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -376,7 +376,7 @@ static int rv3032_read_offset(struct device *dev, long *offset) if (ret < 0) return ret; - steps = sign_extend32(FIELD_GET(RV3032_OFFSET_MSK, value), 5); + steps = FIELD_GET_SIGNED(RV3032_OFFSET_MSK, value); *offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000); diff --git a/include/asm-generic/bitops/__bitrev.h b/include/asm-generic/bitops/__bitrev.h new file mode 100644 index 000000000000..4addbde14050 --- /dev/null +++ b/include/asm-generic/bitops/__bitrev.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_GENERIC_BITOPS___BITREV_H_ +#define _ASM_GENERIC_BITOPS___BITREV_H_ + +#include <asm/types.h> + +extern u8 const byte_rev_table[256]; +static __always_inline __attribute_const__ u8 generic___bitrev8(u8 byte) +{ + return byte_rev_table[byte]; +} + +static __always_inline __attribute_const__ u16 generic___bitrev16(u16 x) +{ + return (generic___bitrev8(x & 0xff) << 8) | generic___bitrev8(x >> 8); +} + +static __always_inline __attribute_const__ u32 generic___bitrev32(u32 x) +{ + return (generic___bitrev16(x & 0xffff) << 16) | generic___bitrev16(x >> 16); +} + +#endif /* _ASM_GENERIC_BITOPS___BITREV_H_ */ diff --git a/include/asm-generic/bitops/lock.h b/include/asm-generic/bitops/lock.h index 14d4ec8c5152..ffb73b6129e7 100644 --- a/include/asm-generic/bitops/lock.h +++ b/include/asm-generic/bitops/lock.h @@ -16,16 +16,16 @@ * It can be used to implement bit locks. */ static __always_inline int -arch_test_and_set_bit_lock(unsigned int nr, volatile unsigned long *p) +arch_test_and_set_bit_lock(unsigned int nr, volatile unsigned long *addr) { long old; unsigned long mask = BIT_MASK(nr); - p += BIT_WORD(nr); - if (READ_ONCE(*p) & mask) + addr += BIT_WORD(nr); + if (READ_ONCE(*addr) & mask) return 1; - old = raw_atomic_long_fetch_or_acquire(mask, (atomic_long_t *)p); + old = raw_atomic_long_fetch_or_acquire(mask, (atomic_long_t *)addr); return !!(old & mask); } @@ -38,10 +38,10 @@ arch_test_and_set_bit_lock(unsigned int nr, volatile unsigned long *p) * This operation is atomic and provides release barrier semantics. */ static __always_inline void -arch_clear_bit_unlock(unsigned int nr, volatile unsigned long *p) +arch_clear_bit_unlock(unsigned int nr, volatile unsigned long *addr) { - p += BIT_WORD(nr); - raw_atomic_long_fetch_andnot_release(BIT_MASK(nr), (atomic_long_t *)p); + addr += BIT_WORD(nr); + raw_atomic_long_fetch_andnot_release(BIT_MASK(nr), (atomic_long_t *)addr); } /** @@ -56,14 +56,14 @@ arch_clear_bit_unlock(unsigned int nr, volatile unsigned long *p) * See for example x86's implementation. */ static inline void -arch___clear_bit_unlock(unsigned int nr, volatile unsigned long *p) +arch___clear_bit_unlock(unsigned int nr, volatile unsigned long *addr) { unsigned long old; - p += BIT_WORD(nr); - old = READ_ONCE(*p); + addr += BIT_WORD(nr); + old = READ_ONCE(*addr); old &= ~BIT_MASK(nr); - raw_atomic_long_set_release((atomic_long_t *)p, old); + raw_atomic_long_set_release((atomic_long_t *)addr, old); } #ifndef arch_xor_unlock_is_negative_byte diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index 54aeeef1f0ec..14f86e455a67 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -44,7 +44,7 @@ * FIELD_MODIFY(REG_FIELD_C, ®, c); */ -#define __bf_shf(x) (__builtin_ffsll(x) - 1) +#define __bf_shf __builtin_ctzll #define __scalar_type_to_unsigned_cases(type) \ unsigned type: (unsigned type)0, \ @@ -179,6 +179,22 @@ }) /** + * FIELD_GET_SIGNED() - extract a signed bitfield element + * @mask: shifted mask defining the field's length and position + * @reg: value of entire bitfield + * + * Returns the sign-extended field specified by @_mask from the + * bitfield passed in as @reg by masking and shifting it down. + */ +#define FIELD_GET_SIGNED(mask, reg) \ + ({ \ + __BF_FIELD_CHECK(mask, reg, 0U, "FIELD_GET_SIGNED: "); \ + ((__signed_scalar_typeof(mask)) \ + (((long long)(reg) << __builtin_clzll(mask)) >> \ + (__builtin_clzll(mask) + __builtin_ctzll(mask)))); \ + }) + +/** * FIELD_MODIFY() - modify a bitfield element * @_mask: shifted mask defining the field's length and position * @_reg_p: pointer to the memory that should be updated diff --git a/include/linux/bitmap-str.h b/include/linux/bitmap-str.h index 53d3e1b32d3d..abe7a69a846f 100644 --- a/include/linux/bitmap-str.h +++ b/include/linux/bitmap-str.h @@ -5,7 +5,6 @@ #include <linux/types.h> int bitmap_parse_user(const char __user *ubuf, unsigned int ulen, unsigned long *dst, int nbits); -int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, int nmaskbits); int bitmap_print_bitmask_to_buf(char *buf, const unsigned long *maskp, int nmaskbits, loff_t off, size_t count); int bitmap_print_list_to_buf(char *buf, const unsigned long *maskp, int nmaskbits, diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h index d35b8ec1c485..11620a70e776 100644 --- a/include/linux/bitrev.h +++ b/include/linux/bitrev.h @@ -12,22 +12,10 @@ #define __bitrev8 __arch_bitrev8 #else -extern u8 const byte_rev_table[256]; -static inline u8 __bitrev8(u8 byte) -{ - return byte_rev_table[byte]; -} - -static inline u16 __bitrev16(u16 x) -{ - return (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8); -} - -static inline u32 __bitrev32(u32 x) -{ - return (__bitrev16(x & 0xffff) << 16) | __bitrev16(x >> 16); -} - +#include <asm-generic/bitops/__bitrev.h> +#define __bitrev32 generic___bitrev32 +#define __bitrev16 generic___bitrev16 +#define __bitrev8 generic___bitrev8 #endif /* CONFIG_HAVE_ARCH_BITREVERSE */ #define __bitrev8x4(x) (__bitrev32(swab32(x))) diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 80211900f373..d3cda0544954 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -13,8 +13,10 @@ #include <linux/cpumask_types.h> #include <linux/gfp_types.h> #include <linux/numa.h> +#include <linux/sprintf.h> #include <linux/threads.h> #include <linux/types.h> +#include <vdso/page.h> #include <asm/bug.h> @@ -1326,8 +1328,9 @@ static __always_inline bool cpu_dying(unsigned int cpu) static __always_inline ssize_t cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) { - return bitmap_print_to_pagebuf(list, buf, cpumask_bits(mask), - nr_cpu_ids); + /* Opencode offset_in_page(buf) to not include linux/mm.h */ + return scnprintf(buf, PAGE_SIZE - ((unsigned long)buf & ~PAGE_MASK), + list ? "%*pbl\n" : "%*pb\n", cpumask_pr_args(mask)); } /** diff --git a/include/linux/find.h b/include/linux/find.h index 6c2be8ca615d..a129f8205fb6 100644 --- a/include/linux/find.h +++ b/include/linux/find.h @@ -249,7 +249,7 @@ unsigned long find_nth_bit(const unsigned long *addr, unsigned long size, unsign * @n: The number of set bit, which position is needed, counting from 0 * * Returns the bit number of the N'th set bit. - * If no such, returns @size. + * If no such, returns >= @size. */ static __always_inline unsigned long find_nth_and_bit(const unsigned long *addr1, const unsigned long *addr2, @@ -277,7 +277,7 @@ unsigned long find_nth_and_bit(const unsigned long *addr1, const unsigned long * * @n: The number of set bit, which position is needed, counting from 0 * * Returns the bit number of the N'th set bit. - * If no such, returns @size. + * If no such, returns >= @size. */ static __always_inline unsigned long find_nth_and_andnot_bit(const unsigned long *addr1, @@ -655,8 +655,8 @@ unsigned long find_next_bit_le(const void *addr, unsigned /** * for_each_clear_bitrange_from - iterate over all unset bit ranges [b; e) - * @b: bit offset of start of current bitrange (first set bit); must be initialized - * @e: bit offset of end of current bitrange (first unset bit) + * @b: bit offset of start of current bitrange (first unset bit); must be initialized + * @e: bit offset of end of current bitrange (first set bit) * @addr: bitmap address to base the search on * @size: bitmap size in number of bits */ diff --git a/lib/Kconfig b/lib/Kconfig index 00a9509636c1..a33988adfaa3 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -54,14 +54,27 @@ config PACKING_KUNIT_TEST config BITREVERSE tristate + select GENERIC_BITREVERSE if !HAVE_ARCH_BITREVERSE config HAVE_ARCH_BITREVERSE bool default n + depends on BITREVERSE help This option enables the use of hardware bit-reversal instructions on architectures which support such operations. +config GENERIC_BITREVERSE + tristate + depends on BITREVERSE + help + Generic bit reversal implementation. Drivers should never enable + it explicitly. Instead, enable BITREVERSE. + + Architectures may want to select it as a fall-back option for + HAVE_ARCH_BITREVERSE, when the hardware-accelerated bit reverse + instruction set is optional, like RISC-V ZBKB extension. + config ARCH_HAS_STRNCPY_FROM_USER bool diff --git a/lib/Makefile b/lib/Makefile index f33a24bf1c19..23e07d19d01c 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -145,7 +145,7 @@ obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o obj-$(CONFIG_LIST_HARDENED) += list_debug.o obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o -obj-$(CONFIG_BITREVERSE) += bitrev.o +obj-$(CONFIG_GENERIC_BITREVERSE) += bitrev.o obj-$(CONFIG_LINEAR_RANGES) += linear_ranges.o obj-$(CONFIG_PACKING) += packing.o obj-$(CONFIG_PACKING_KUNIT_TEST) += packing_test.o diff --git a/lib/bitmap-str.c b/lib/bitmap-str.c index be745209507a..26d36c938c6a 100644 --- a/lib/bitmap-str.c +++ b/lib/bitmap-str.c @@ -40,32 +40,6 @@ int bitmap_parse_user(const char __user *ubuf, EXPORT_SYMBOL(bitmap_parse_user); /** - * bitmap_print_to_pagebuf - convert bitmap to list or hex format ASCII string - * @list: indicates whether the bitmap must be list - * @buf: page aligned buffer into which string is placed - * @maskp: pointer to bitmap to convert - * @nmaskbits: size of bitmap, in bits - * - * Output format is a comma-separated list of decimal numbers and - * ranges if list is specified or hex digits grouped into comma-separated - * sets of 8 digits/set. Returns the number of characters written to buf. - * - * It is assumed that @buf is a pointer into a PAGE_SIZE, page-aligned - * area and that sufficient storage remains at @buf to accommodate the - * bitmap_print_to_pagebuf() output. Returns the number of characters - * actually printed to @buf, excluding terminating '\0'. - */ -int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, - int nmaskbits) -{ - ptrdiff_t len = PAGE_SIZE - offset_in_page(buf); - - return list ? scnprintf(buf, len, "%*pbl\n", nmaskbits, maskp) : - scnprintf(buf, len, "%*pb\n", nmaskbits, maskp); -} -EXPORT_SYMBOL(bitmap_print_to_pagebuf); - -/** * bitmap_print_to_buf - convert bitmap to list or hex format ASCII string * @list: indicates whether the bitmap must be list * true: print in decimal list format @@ -101,7 +75,7 @@ static int bitmap_print_to_buf(bool list, char *buf, const unsigned long *maskp, * @off: in the string from which we are copying, We copy to @buf * @count: the maximum number of bytes to print * - * The bitmap_print_to_pagebuf() is used indirectly via its cpumap wrapper + * The sprintf("%*pb[l]") is used indirectly via its cpumap wrapper * cpumap_print_to_pagebuf() or directly by drivers to export hexadecimal * bitmask and decimal list to userspace by sysfs ABI. * Drivers might be using a normal attribute for this kind of ABIs. A @@ -111,18 +85,11 @@ static int bitmap_print_to_buf(bool list, char *buf, const unsigned long *maskp, * struct device_attribute *attr, char *buf) * { * ... - * return bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max); + * return scnprintf(buf, PAGE_SIZE - offset_in_page(buf), nr_trig_max, &mask); * } * * show entry of attribute has no offset and count parameters and this * means the file is limited to one page only. - * bitmap_print_to_pagebuf() API works terribly well for this kind of - * normal attribute with buf parameter and without offset, count:: - * - * bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, - * int nmaskbits) - * { - * } * * The problem is once we have a large bitmap, we have a chance to get a * bitmask or list more than one page. Especially for list, it could be @@ -149,7 +116,7 @@ static int bitmap_print_to_buf(bool list, char *buf, const unsigned long *maskp, * * The role of cpumap_print_bitmask_to_buf() and cpumap_print_list_to_buf() * is similar with cpumap_print_to_pagebuf(), the difference is that - * bitmap_print_to_pagebuf() mainly serves sysfs attribute with the assumption + * scnprintf("%*pb[l]") mainly serves sysfs attribute with the assumption * the destination buffer is exactly one page and won't be more than one page. * cpumap_print_bitmask_to_buf() and cpumap_print_list_to_buf(), on the other * hand, mainly serves bin_attribute which doesn't work with exact one page, @@ -158,7 +125,8 @@ static int bitmap_print_to_buf(bool list, char *buf, const unsigned long *maskp, * * WARNING! * - * This function is not a replacement for sprintf() or bitmap_print_to_pagebuf(). + * This function is not a replacement for sprintf(). + * * It is intended to workaround sysfs limitations discussed above and should be * used carefully in general case for the following reasons: * diff --git a/lib/bitrev.c b/lib/bitrev.c index 81b56e0a7f32..05088231f31f 100644 --- a/lib/bitrev.c +++ b/lib/bitrev.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0-only -#ifndef CONFIG_HAVE_ARCH_BITREVERSE #include <linux/types.h> #include <linux/module.h> #include <linux/bitrev.h> @@ -43,5 +42,3 @@ const u8 byte_rev_table[256] = { 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, }; EXPORT_SYMBOL_GPL(byte_rev_table); - -#endif /* CONFIG_HAVE_ARCH_BITREVERSE */ |
