diff mbox series

[v1,07/10] linux/bitfield.h: Add primitives for manipulating bitfields both in host- and fixed-endian.

Message ID 20200424165012.31915-8-s.nawrocki@samsung.com
State Superseded
Headers show
Series USB host support for Raspberry Pi 4 board | expand

Commit Message

From: Nicolas Saenz Julienne <nsaenzjulienne at suse.de>

Imports Al Viro's original Linux commit 00b0c9b82663a, which contains
an in depth explanation and two fixes from Johannes Berg:
 e7d4a95da86e0 "bitfield: fix *_encode_bits()",
 37a3862e12382 "bitfield: add u8 helpers".

Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne at suse.de>
Signed-off-by: Sylwester Nawrocki <s.nawrocki at samsung.com>
---
Changes since RFC:
 - new patch.
---
 include/linux/bitfield.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

Comments

Bin Meng April 25, 2020, 1:43 a.m. UTC | #1
On Sat, Apr 25, 2020 at 12:52 AM Sylwester Nawrocki
<s.nawrocki at samsung.com> wrote:
>
> From: Nicolas Saenz Julienne <nsaenzjulienne at suse.de>
>
> Imports Al Viro's original Linux commit 00b0c9b82663a, which contains
> an in depth explanation and two fixes from Johannes Berg:
>  e7d4a95da86e0 "bitfield: fix *_encode_bits()",
>  37a3862e12382 "bitfield: add u8 helpers".
>
> Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne at suse.de>
> Signed-off-by: Sylwester Nawrocki <s.nawrocki at samsung.com>

nits: remove the ending period in the commit title

> ---
> Changes since RFC:
>  - new patch.
> ---
>  include/linux/bitfield.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 46 insertions(+)
>
> diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
> index 8b9d6ff..4964213 100644
> --- a/include/linux/bitfield.h
> +++ b/include/linux/bitfield.h
> @@ -103,4 +103,50 @@
>                 (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
>         })
>
> +extern void __compiletime_error("value doesn't fit into mask")
> +__field_overflow(void);
> +extern void __compiletime_error("bad bitfield mask")
> +__bad_mask(void);
> +static __always_inline u64 field_multiplier(u64 field)
> +{
> +       if ((field | (field - 1)) & ((field | (field - 1)) + 1))
> +               __bad_mask();
> +       return field & -field;
> +}
> +static __always_inline u64 field_mask(u64 field)
> +{
> +       return field / field_multiplier(field);
> +}
> +#define ____MAKE_OP(type,base,to,from)                                 \
> +static __always_inline __##type type##_encode_bits(base v, base field) \
> +{                                                                      \
> +       if (__builtin_constant_p(v) && (v & ~field_mask(field)))        \
> +               __field_overflow();                                     \
> +       return to((v & field_mask(field)) * field_multiplier(field));   \
> +}                                                                      \
> +static __always_inline __##type type##_replace_bits(__##type old,      \
> +                                       base val, base field)           \
> +{                                                                      \
> +       return (old & ~to(field)) | type##_encode_bits(val, field);     \
> +}                                                                      \
> +static __always_inline void type##p_replace_bits(__##type *p,          \
> +                                       base val, base field)           \
> +{                                                                      \
> +       *p = (*p & ~to(field)) | type##_encode_bits(val, field);        \
> +}                                                                      \
> +static __always_inline base type##_get_bits(__##type v, base field)    \
> +{                                                                      \
> +       return (from(v) & field)/field_multiplier(field);               \
> +}
> +#define __MAKE_OP(size)                                                        \
> +       ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \
> +       ____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu) \
> +       ____MAKE_OP(u##size,u##size,,)
> +____MAKE_OP(u8,u8,,)
> +__MAKE_OP(16)
> +__MAKE_OP(32)
> +__MAKE_OP(64)
> +#undef __MAKE_OP
> +#undef ____MAKE_OP
> +
>  #endif

Could we add blank line between macros and functions to improve some readablity?

Regards,
Bin
diff mbox series

Patch

diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 8b9d6ff..4964213 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -103,4 +103,50 @@ 
 		(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask));	\
 	})
 
+extern void __compiletime_error("value doesn't fit into mask")
+__field_overflow(void);
+extern void __compiletime_error("bad bitfield mask")
+__bad_mask(void);
+static __always_inline u64 field_multiplier(u64 field)
+{
+	if ((field | (field - 1)) & ((field | (field - 1)) + 1))
+		__bad_mask();
+	return field & -field;
+}
+static __always_inline u64 field_mask(u64 field)
+{
+	return field / field_multiplier(field);
+}
+#define ____MAKE_OP(type,base,to,from)					\
+static __always_inline __##type type##_encode_bits(base v, base field)	\
+{									\
+	if (__builtin_constant_p(v) && (v & ~field_mask(field)))	\
+		__field_overflow();					\
+	return to((v & field_mask(field)) * field_multiplier(field));	\
+}									\
+static __always_inline __##type type##_replace_bits(__##type old,	\
+					base val, base field)		\
+{									\
+	return (old & ~to(field)) | type##_encode_bits(val, field);	\
+}									\
+static __always_inline void type##p_replace_bits(__##type *p,		\
+					base val, base field)		\
+{									\
+	*p = (*p & ~to(field)) | type##_encode_bits(val, field);	\
+}									\
+static __always_inline base type##_get_bits(__##type v, base field)	\
+{									\
+	return (from(v) & field)/field_multiplier(field);		\
+}
+#define __MAKE_OP(size)							\
+	____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu)	\
+	____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu)	\
+	____MAKE_OP(u##size,u##size,,)
+____MAKE_OP(u8,u8,,)
+__MAKE_OP(16)
+__MAKE_OP(32)
+__MAKE_OP(64)
+#undef __MAKE_OP
+#undef ____MAKE_OP
+
 #endif