diff options
Diffstat (limited to 'tools/include/linux/bitfield.h')
| -rw-r--r-- | tools/include/linux/bitfield.h | 176 | 
1 files changed, 176 insertions, 0 deletions
diff --git a/tools/include/linux/bitfield.h b/tools/include/linux/bitfield.h new file mode 100644 index 000000000000..6093fa6db260 --- /dev/null +++ b/tools/include/linux/bitfield.h @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@nbd.name> + * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> + */ + +#ifndef _LINUX_BITFIELD_H +#define _LINUX_BITFIELD_H + +#include <linux/build_bug.h> +#include <asm/byteorder.h> + +/* + * Bitfield access macros + * + * FIELD_{GET,PREP} macros take as first parameter shifted mask + * from which they extract the base mask and shift amount. + * Mask must be a compilation time constant. + * + * Example: + * + *  #define REG_FIELD_A  GENMASK(6, 0) + *  #define REG_FIELD_B  BIT(7) + *  #define REG_FIELD_C  GENMASK(15, 8) + *  #define REG_FIELD_D  GENMASK(31, 16) + * + * Get: + *  a = FIELD_GET(REG_FIELD_A, reg); + *  b = FIELD_GET(REG_FIELD_B, reg); + * + * Set: + *  reg = FIELD_PREP(REG_FIELD_A, 1) | + *	  FIELD_PREP(REG_FIELD_B, 0) | + *	  FIELD_PREP(REG_FIELD_C, c) | + *	  FIELD_PREP(REG_FIELD_D, 0x40); + * + * Modify: + *  reg &= ~REG_FIELD_C; + *  reg |= FIELD_PREP(REG_FIELD_C, c); + */ + +#define __bf_shf(x) (__builtin_ffsll(x) - 1) + +#define __scalar_type_to_unsigned_cases(type)				\ +		unsigned type:	(unsigned type)0,			\ +		signed type:	(unsigned type)0 + +#define __unsigned_scalar_typeof(x) typeof(				\ +		_Generic((x),						\ +			char:	(unsigned char)0,			\ +			__scalar_type_to_unsigned_cases(char),		\ +			__scalar_type_to_unsigned_cases(short),		\ +			__scalar_type_to_unsigned_cases(int),		\ +			__scalar_type_to_unsigned_cases(long),		\ +			__scalar_type_to_unsigned_cases(long long),	\ +			default: (x))) + +#define __bf_cast_unsigned(type, x)	((__unsigned_scalar_typeof(type))(x)) + +#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx)			\ +	({								\ +		BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask),		\ +				 _pfx "mask is not constant");		\ +		BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero");	\ +		BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ?		\ +				 ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \ +				 _pfx "value too large for the field"); \ +		BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) >	\ +				 __bf_cast_unsigned(_reg, ~0ull),	\ +				 _pfx "type of reg too small for mask"); \ +		__BUILD_BUG_ON_NOT_POWER_OF_2((_mask) +			\ +					      (1ULL << __bf_shf(_mask))); \ +	}) + +/** + * FIELD_MAX() - produce the maximum value representable by a field + * @_mask: shifted mask defining the field's length and position + * + * FIELD_MAX() returns the maximum value that can be held in the field + * specified by @_mask. + */ +#define FIELD_MAX(_mask)						\ +	({								\ +		__BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_MAX: ");	\ +		(typeof(_mask))((_mask) >> __bf_shf(_mask));		\ +	}) + +/** + * FIELD_FIT() - check if value fits in the field + * @_mask: shifted mask defining the field's length and position + * @_val:  value to test against the field + * + * Return: true if @_val can fit inside @_mask, false if @_val is too big. + */ +#define FIELD_FIT(_mask, _val)						\ +	({								\ +		__BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: ");	\ +		!((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ +	}) + +/** + * FIELD_PREP() - prepare a bitfield element + * @_mask: shifted mask defining the field's length and position + * @_val:  value to put in the field + * + * FIELD_PREP() masks and shifts up the value.  The result should + * be combined with other fields of the bitfield using logical OR. + */ +#define FIELD_PREP(_mask, _val)						\ +	({								\ +		__BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: ");	\ +		((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask);	\ +	}) + +/** + * FIELD_GET() - extract a bitfield element + * @_mask: shifted mask defining the field's length and position + * @_reg:  value of entire bitfield + * + * FIELD_GET() extracts the field specified by @_mask from the + * bitfield passed in as @_reg by masking and shifting it down. + */ +#define FIELD_GET(_mask, _reg)						\ +	({								\ +		__BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: ");	\ +		(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 field_max(field)	((typeof(field))field_mask(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  | 
