A lot of drivers are open-coding the "replace these bits in __be32 with
the following value" kind of primitives.  Let's add them to byteorder.h.

Primitives:
        {be,le}{16,32,64}_replace_bits(old, v, bit, nbits)
        {be,le}{16,32,64}_get_bits(val, bit, nbits)

Essentially, it gives helpers for work with bitfields in fixed-endian.
Suppose we have e.g. a little-endian 32bit value with fixed layout;
expressing that as a bitfield would go like
        struct foo {
                unsigned foo:4;         /* bits 0..3 */
                unsigned :2;
                unsigned bar:12;        /* bits 6..17 */
                unsigned baz:14;        /* bits 18..31 */
        }
Even for host-endian it doesn't work all that well - you end up with
ifdefs in structure definition and generated code stinks.  For fixed-endian
it gets really painful, and people tend to use explicit shift-and-mask
kind of macros for accessing the fields (and often enough get the
endianness conversions wrong, at that).  With these primitives

struct foo v            <=>     __le32 v
v.foo = i ? 1 : 2       <=>     v = le32_replace_bits(v, i ? 1 : 2, 0, 4)
f(4 + v.baz)            <=>     f(4 + le32_get_bits(v, 18, 14))

Signed-off-by: Al Viro <v...@zeniv.linux.org.uk>
---
diff --git a/include/linux/byteorder/generic.h 
b/include/linux/byteorder/generic.h
index 451aaa0786ae..d8f169a7104a 100644
--- a/include/linux/byteorder/generic.h
+++ b/include/linux/byteorder/generic.h
@@ -187,4 +187,26 @@ static inline void be32_to_cpu_array(u32 *dst, const 
__be32 *src, size_t len)
                dst[i] = be32_to_cpu(src[i]);
 }
 
+#define ____MASK(bit, nbits) ((((1ULL << ((nbits) - 1)) << 1) - 1) << (bit))
+#define ____MAKE_OP(type,base)                                         \
+static inline __##type type##_replace_bits(__##type old,               \
+                                       base val, int bit, int nbits)   \
+{                                                                      \
+       __##type mask = cpu_to_##type(____MASK(bit, nbits));            \
+       return (old & ~mask) | (cpu_to_##type(val << bit) & mask);      \
+}                                                                      \
+static inline base type##_get_bits(__##type val, int bit, int nbits)   \
+{                                                                      \
+       return (type##_to_cpu(val) >> bit) & ____MASK(0, nbits);        \
+}
+
+____MAKE_OP(le16,u16)
+____MAKE_OP(le32,u32)
+____MAKE_OP(le64,u64)
+____MAKE_OP(be16,u16)
+____MAKE_OP(be32,u32)
+____MAKE_OP(be64,u64)
+#undef ____MAKE_OP
+#undef ____MASK
+
 #endif /* _LINUX_BYTEORDER_GENERIC_H */

Reply via email to