Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750836AbdLKPyZ (ORCPT ); Mon, 11 Dec 2017 10:54:25 -0500 Received: from zeniv.linux.org.uk ([195.92.253.2]:47206 "EHLO ZenIV.linux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751543AbdLKPyY (ORCPT ); Mon, 11 Dec 2017 10:54:24 -0500 Date: Mon, 11 Dec 2017 15:54:22 +0000 From: Al Viro To: Linus Torvalds Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC][PATCH] new byteorder primitives - ..._{replace,get}_bits() Message-ID: <20171211155422.GA12326@ZenIV.linux.org.uk> References: <20171210045326.GO21978@ZenIV.linux.org.uk> <420a198d-61f8-81cf-646d-10446cb41def@synopsys.com> <20171211050520.GV21978@ZenIV.linux.org.uk> <20171211053803.GW21978@ZenIV.linux.org.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20171211053803.GW21978@ZenIV.linux.org.uk> User-Agent: Mutt/1.9.1 (2017-09-22) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2192 Lines: 59 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 --- 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 */