diff mbox series

[v4,6/9] linux/bitfield.h: Add primitives for manipulating bitfields both in host- and fixed-endian

Message ID 20200525113959.11886-7-s.nawrocki@samsung.com
State Accepted
Delegated to: Matthias Brugger
Headers show
Series USB host support for Raspberry Pi 4 board (64-bit) | expand

Commit Message

Sylwester Nawrocki May 25, 2020, 11:39 a.m. UTC
From: Nicolas Saenz Julienne <nsaenzjulienne@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@suse.de>
[s.nawrocki: added empty lines between functions and macros]
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
Changes since v3:
 - none.
Changes since v2:
 - added some more missing whitespaces as pointed out by checkpatch.pl.
Changes since v1:
 - added empty lines between functions and macros.
Changes since RFC:
 - new patch.
---
 include/linux/bitfield.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

Comments

Matthias Brugger July 9, 2020, 3:35 p.m. UTC | #1
On 25/05/2020 13:39, Sylwester Nawrocki wrote:
> From: Nicolas Saenz Julienne <nsaenzjulienne@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@suse.de>
> [s.nawrocki: added empty lines between functions and macros]
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>

This seems to break compilation of
arch/arm/mach-uniphier/clk/pll-base-ld20.c

https://gitlab.denx.de/u-boot/custodians/u-boot-raspberrypi/-/jobs/121248

Nicolas, Sylwester, can you please have a look.

Regards,
Matthias

> ---
> Changes since v3:
>   - none.
> Changes since v2:
>   - added some more missing whitespaces as pointed out by checkpatch.pl.
> Changes since v1:
>   - added empty lines between functions and macros.
> Changes since RFC:
>   - new patch.
> ---
>   include/linux/bitfield.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 52 insertions(+)
> 
> diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
> index 8b9d6ff..7ad8b08 100644
> --- a/include/linux/bitfield.h
> +++ b/include/linux/bitfield.h
> @@ -103,4 +103,56 @@
>   		(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
>
Matthias Brugger July 9, 2020, 3:37 p.m. UTC | #2
On 09/07/2020 17:35, Matthias Brugger wrote:
> 
> 
> On 25/05/2020 13:39, Sylwester Nawrocki wrote:
>> From: Nicolas Saenz Julienne <nsaenzjulienne@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@suse.de>
>> [s.nawrocki: added empty lines between functions and macros]
>> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> 
> This seems to break compilation of
> arch/arm/mach-uniphier/clk/pll-base-ld20.c
> 
> https://gitlab.denx.de/u-boot/custodians/u-boot-raspberrypi/-/jobs/121248
> 
> Nicolas, Sylwester, can you please have a look.
> 

Just in case you can't access the URL:
https://pastebin.com/KhDHf8e1

> Regards,
> Matthias
> 
>> ---
>> Changes since v3:
>>   - none.
>> Changes since v2:
>>   - added some more missing whitespaces as pointed out by checkpatch.pl.
>> Changes since v1:
>>   - added empty lines between functions and macros.
>> Changes since RFC:
>>   - new patch.
>> ---
>>   include/linux/bitfield.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 52 insertions(+)
>>
>> diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
>> index 8b9d6ff..7ad8b08 100644
>> --- a/include/linux/bitfield.h
>> +++ b/include/linux/bitfield.h
>> @@ -103,4 +103,56 @@
>>           (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
>>
diff mbox series

Patch

diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 8b9d6ff..7ad8b08 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -103,4 +103,56 @@ 
 		(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