summaryrefslogtreecommitdiff
path: root/include/linux/bitfield.h
diff options
context:
space:
mode:
authorNicolas Saenz Julienne <nsaenzjulienne@suse.de>2020-05-25 13:39:56 +0200
committerMatthias Brugger <mbrugger@suse.com>2020-07-10 11:47:12 +0200
commitc92921bb52a7e104e0a48740d518c41ec4c86097 (patch)
treed9db1710eb621a94ee13765c1b1385084bbb69cd /include/linux/bitfield.h
parentd69ddf24944162745665a45fef00a2115d371dbe (diff)
linux/bitfield.h: Add primitives for manipulating bitfields both in host- and fixed-endian
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> [mb: squash fix including byteorder.h] Signed-off-by: Matthias Brugger <mbrugger@suse.com>
Diffstat (limited to 'include/linux/bitfield.h')
-rw-r--r--include/linux/bitfield.h53
1 files changed, 53 insertions, 0 deletions
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 8b9d6fff00..7ad02f8cbb 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -16,6 +16,7 @@
#define _LINUX_BITFIELD_H
#include <linux/bug.h>
+#include <asm/byteorder.h>
/*
* Bitfield access macros
@@ -103,4 +104,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