Skip to content

Commit ddd31f5

Browse files
vincent-mailholgregkh
authored andcommitted
bits: introduce fixed-type GENMASK_U*()
[ Upstream commit 1940820 ] Add GENMASK_TYPE() which generalizes __GENMASK() to support different types, and implement fixed-types versions of GENMASK() based on it. The fixed-type version allows more strict checks to the min/max values accepted, which is useful for defining registers like implemented by i915 and xe drivers with their REG_GENMASK*() macros. The strict checks rely on shift-count-overflow compiler check to fail the build if a number outside of the range allowed is passed. Example: #define FOO_MASK GENMASK_U32(33, 4) will generate a warning like: include/linux/bits.h:51:27: error: right shift count >= width of type [-Werror=shift-count-overflow] 51 | type_max(t) >> (BITS_PER_TYPE(t) - 1 - (h))))) | ^~ The result is casted to the corresponding fixed width type. For example, GENMASK_U8() returns an u8. Note that because of the C promotion rules, GENMASK_U8() and GENMASK_U16() will immediately be promoted to int if used in an expression. Regardless, the main goal is not to get the correct type, but rather to enforce more checks at compile time. While GENMASK_TYPE() is crafted to cover all variants, including the already existing GENMASK(), GENMASK_ULL() and GENMASK_U128(), for the moment, only use it for the newly introduced GENMASK_U*(). The consolidation will be done in a separate change. Co-developed-by: Yury Norov <yury.norov@gmail.com> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com> Acked-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Yury Norov <yury.norov@gmail.com> Stable-dep-of: 2ba5772 ("gpio: idio-16: Define fixed direction of the GPIO lines") Signed-off-by: William Breathitt Gray <wbg@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 739aa67 commit ddd31f5

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

include/linux/bitops.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
# define aligned_byte_mask(n) (~0xffUL << (BITS_PER_LONG - 8 - 8*(n)))
1616
#endif
1717

18-
#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
1918
#define BITS_TO_LONGS(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(long))
2019
#define BITS_TO_U64(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u64))
2120
#define BITS_TO_U32(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u32))

include/linux/bits.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define BIT_ULL_MASK(nr) (ULL(1) << ((nr) % BITS_PER_LONG_LONG))
1212
#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG)
1313
#define BITS_PER_BYTE 8
14+
#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
1415

1516
/*
1617
* Create a contiguous bitmask starting at bit position @l and ending at
@@ -19,11 +20,40 @@
1920
*/
2021
#if !defined(__ASSEMBLY__)
2122

23+
/*
24+
* Missing asm support
25+
*
26+
* GENMASK_U*() depend on BITS_PER_TYPE() which relies on sizeof(),
27+
* something not available in asm. Nevertheless, fixed width integers is a C
28+
* concept. Assembly code can rely on the long and long long versions instead.
29+
*/
30+
2231
#include <linux/build_bug.h>
32+
#include <linux/overflow.h>
2333
#define GENMASK_INPUT_CHECK(h, l) \
2434
(BUILD_BUG_ON_ZERO(__builtin_choose_expr( \
2535
__is_constexpr((l) > (h)), (l) > (h), 0)))
2636

37+
/*
38+
* Generate a mask for the specified type @t. Additional checks are made to
39+
* guarantee the value returned fits in that type, relying on
40+
* -Wshift-count-overflow compiler check to detect incompatible arguments.
41+
* For example, all these create build errors or warnings:
42+
*
43+
* - GENMASK(15, 20): wrong argument order
44+
* - GENMASK(72, 15): doesn't fit unsigned long
45+
* - GENMASK_U32(33, 15): doesn't fit in a u32
46+
*/
47+
#define GENMASK_TYPE(t, h, l) \
48+
((t)(GENMASK_INPUT_CHECK(h, l) + \
49+
(type_max(t) << (l) & \
50+
type_max(t) >> (BITS_PER_TYPE(t) - 1 - (h)))))
51+
52+
#define GENMASK_U8(h, l) GENMASK_TYPE(u8, h, l)
53+
#define GENMASK_U16(h, l) GENMASK_TYPE(u16, h, l)
54+
#define GENMASK_U32(h, l) GENMASK_TYPE(u32, h, l)
55+
#define GENMASK_U64(h, l) GENMASK_TYPE(u64, h, l)
56+
2757
#else /* defined(__ASSEMBLY__) */
2858

2959
/*

0 commit comments

Comments
 (0)