All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Borkmann <daniel@iogearbox.net>
To: Jakub Kicinski <jakub.kicinski@netronome.com>, netdev@vger.kernel.org
Cc: ast@kernel.org, dinan.gunawardena@netronome.com,
	jiri@resnulli.us, john.fastabend@gmail.com, kubakici@wp.pl
Subject: Re: [RFCv2 01/16] add basic register-field manipulation macros
Date: Mon, 29 Aug 2016 16:34:25 +0200	[thread overview]
Message-ID: <57C447F1.60807@iogearbox.net> (raw)
In-Reply-To: <1472234775-29453-2-git-send-email-jakub.kicinski@netronome.com>

On 08/26/2016 08:06 PM, Jakub Kicinski wrote:
> Common approach to accessing register fields is to define
> structures or sets of macros containing mask and shift pair.
> Operations on the register are then performed as follows:
>
>   field = (reg >> shift) & mask;
>
>   reg &= ~(mask << shift);
>   reg |= (field & mask) << shift;
>
> Defining shift and mask separately is tedious.  Ivo van Doorn
> came up with an idea of computing them at compilation time
> based on a single shifted mask (later refined by Felix) which
> can be used like this:
>
>   #define REG_FIELD 0x000ff000
>
>   field = FIELD_GET(REG_FIELD, reg);
>
>   reg &= ~REG_FIELD;
>   reg |= FIELD_PREP(REG_FIELD, field);
>
> FIELD_{GET,PREP} macros take care of finding out what the
> appropriate shift is based on compilation time ffs operation.
>
> GENMASK can be used to define registers (which is usually
> less error-prone and easier to match with datasheets).
>
> This approach is the most convenient I've seen so to limit code
> multiplication let's move the macros to a global header file.
> Attempts to use static inlines instead of macros failed due
> to false positive triggering of BUILD_BUG_ON()s, especially with
> GCC < 6.0.
>
> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
[...]
> + * 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 _BF_FIELD_CHECK(_mask, _reg, _val, _pfx)			\

Nit: if possible, please always use "__" instead of "_" as prefix, which is
more common coding style in the kernel.

> +	({								\
> +		BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask),		\
> +				 _pfx "mask is not constant");		\
> +		BUILD_BUG_ON_MSG(!(_mask), _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((_mask) > (typeof(_reg))~0ull,		\
> +				 _pfx "type of reg too small for mask"); \
> +		__BUILD_BUG_ON_NOT_POWER_OF_2((_mask) +			\
> +					      (1ULL << _bf_shf(_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:  32bit 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));	\
> +	})

No strong opinion, but FIELD_PREP() sounds a bit weird. Maybe rather a
FIELD_GEN() (aka "generate") and FIELD_GET() pair?

> +#endif
> diff --git a/include/linux/bug.h b/include/linux/bug.h
> index e51b0709e78d..292d6a10b0c2 100644
> --- a/include/linux/bug.h
> +++ b/include/linux/bug.h
> @@ -13,6 +13,7 @@ enum bug_trap_type {
>   struct pt_regs;
>
>   #ifdef __CHECKER__
> +#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) (0)
>   #define BUILD_BUG_ON_NOT_POWER_OF_2(n) (0)
>   #define BUILD_BUG_ON_ZERO(e) (0)
>   #define BUILD_BUG_ON_NULL(e) ((void*)0)
> @@ -24,6 +25,8 @@ struct pt_regs;
>   #else /* __CHECKER__ */
>
>   /* Force a compilation error if a constant expression is not a power of 2 */
> +#define __BUILD_BUG_ON_NOT_POWER_OF_2(n)	\
> +	BUILD_BUG_ON(((n) & ((n) - 1)) != 0)

Is there a reason BUILD_BUG_ON_NOT_POWER_OF_2(n) cannot be reused?

Because the (n) == 0 check would trigger (although it shouldn't ...)?

>   #define BUILD_BUG_ON_NOT_POWER_OF_2(n)			\
>   	BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
>
>

  reply	other threads:[~2016-08-29 14:34 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-26 18:05 [RFCv2 00/16] BPF hardware offload (cls_bpf for now) Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 01/16] add basic register-field manipulation macros Jakub Kicinski
2016-08-29 14:34   ` Daniel Borkmann [this message]
2016-08-29 15:07     ` Jakub Kicinski
2016-08-29 15:40       ` Daniel Borkmann
2016-08-26 18:06 ` [RFCv2 02/16] net: cls_bpf: add hardware offload Jakub Kicinski
2016-08-29 14:51   ` Daniel Borkmann
2016-08-26 18:06 ` [RFCv2 03/16] net: cls_bpf: limit hardware offload by software-only flag Jakub Kicinski
2016-08-29 15:06   ` Daniel Borkmann
2016-08-29 15:15     ` Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 04/16] net: cls_bpf: add support for marking filters as hardware-only Jakub Kicinski
2016-08-29 15:28   ` Daniel Borkmann
2016-08-26 18:06 ` [RFCv2 05/16] bpf: recognize 64bit immediate loads as consts Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 06/16] bpf: verifier: recognize rN ^ rN as load of 0 Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 07/16] bpf: enable non-core use of the verfier Jakub Kicinski
2016-08-26 23:29   ` Alexei Starovoitov
2016-08-27 11:40     ` Jakub Kicinski
2016-08-27 17:32       ` Alexei Starovoitov
2016-08-29 20:13         ` Daniel Borkmann
2016-08-29 20:17           ` Daniel Borkmann
2016-08-30 10:48             ` Jakub Kicinski
2016-08-30 19:07               ` Daniel Borkmann
2016-08-30 20:22                 ` Jakub Kicinski
2016-08-30 20:48                   ` Alexei Starovoitov
2016-08-30 21:00                     ` Daniel Borkmann
2016-08-31  1:18                       ` Alexei Starovoitov
2016-08-26 18:06 ` [RFCv2 08/16] bpf: export bpf_prog_clone functions Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 09/16] nfp: add BPF to NFP code translator Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 10/16] nfp: bpf: add hardware bpf offload Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 11/16] net: cls_bpf: allow offloaded filters to update stats Jakub Kicinski
2016-08-29 20:43   ` Daniel Borkmann
2016-08-26 18:06 ` [RFCv2 12/16] net: bpf: " Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 13/16] nfp: bpf: add packet marking support Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 14/16] net: act_mirred: allow statistic updates from offloaded actions Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 15/16] nfp: bpf: add support for legacy redirect action Jakub Kicinski
2016-08-26 18:06 ` [RFCv2 16/16] nfp: bpf: add offload of TC direct action mode Jakub Kicinski
2016-08-29 21:09   ` Daniel Borkmann
2016-08-30 10:52     ` Jakub Kicinski
2016-08-30 20:02       ` Daniel Borkmann
2016-08-30 20:50         ` Jakub Kicinski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=57C447F1.60807@iogearbox.net \
    --to=daniel@iogearbox.net \
    --cc=ast@kernel.org \
    --cc=dinan.gunawardena@netronome.com \
    --cc=jakub.kicinski@netronome.com \
    --cc=jiri@resnulli.us \
    --cc=john.fastabend@gmail.com \
    --cc=kubakici@wp.pl \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.