From: Yury Norov <yury.norov@gmail.com>
To: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: "Michael Turquette" <mturquette@baylibre.com>,
"Stephen Boyd" <sboyd@kernel.org>,
"Nicolas Ferre" <nicolas.ferre@microchip.com>,
"Alexandre Belloni" <alexandre.belloni@bootlin.com>,
"Claudiu Beznea" <claudiu.beznea@tuxon.dev>,
"Giovanni Cabiddu" <giovanni.cabiddu@intel.com>,
"Herbert Xu" <herbert@gondor.apana.org.au>,
"David Miller" <davem@davemloft.net>,
"Linus Walleij" <linus.walleij@linaro.org>,
"Bartosz Golaszewski" <brgl@bgdev.pl>,
"Joel Stanley" <joel@jms.id.au>,
"Andrew Jeffery" <andrew@codeconstruct.com.au>,
"Crt Mori" <cmo@melexis.com>,
"Jonathan Cameron" <jic23@kernel.org>,
"Lars-Peter Clausen" <lars@metafoo.de>,
"Jacky Huang" <ychuang3@nuvoton.com>,
"Shan-Chun Hung" <schung@nuvoton.com>,
"Rasmus Villemoes" <linux@rasmusvillemoes.dk>,
"Jaroslav Kysela" <perex@perex.cz>,
"Takashi Iwai" <tiwai@suse.com>,
"Johannes Berg" <johannes@sipsolutions.net>,
"Jakub Kicinski" <kuba@kernel.org>, "Alex Elder" <elder@ieee.org>,
"David Laight" <david.laight.linux@gmail.com>,
"Vincent Mailhol" <mailhol.vincent@wanadoo.fr>,
"Jason Baron" <jbaron@akamai.com>,
"Borislav Petkov" <bp@alien8.de>,
"Tony Luck" <tony.luck@intel.com>,
"Michael Hennerich" <Michael.Hennerich@analog.com>,
"Kim Seer Paller" <kimseer.paller@analog.com>,
"David Lechner" <dlechner@baylibre.com>,
"Nuno Sá" <nuno.sa@analog.com>,
"Andy Shevchenko" <andy@kernel.org>,
"Richard Genoud" <richard.genoud@bootlin.com>,
"Cosmin Tanislav" <demonsingur@gmail.com>,
"Biju Das" <biju.das.jz@bp.renesas.com>,
"Jianping Shen" <Jianping.Shen@de.bosch.com>,
linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-renesas-soc@vger.kernel.org, linux-crypto@vger.kernel.org,
linux-edac@vger.kernel.org, qat-linux@intel.com,
linux-gpio@vger.kernel.org, linux-aspeed@lists.ozlabs.org,
linux-iio@vger.kernel.org, linux-sound@vger.kernel.org,
linux-kernel@vger.kernel.org,
"Jonathan Cameron" <Jonathan.Cameron@huawei.com>
Subject: Re: [PATCH v4 2/4] bitfield: Add non-constant field_{prep,get}() helpers
Date: Wed, 22 Oct 2025 00:20:21 -0400 [thread overview]
Message-ID: <aPhbhQEWAel4aD9t@yury> (raw)
In-Reply-To: <CAMuHMdXq7xubX4a6SZWcC1HX+_TsKeQigDVQrWvA=js5bhaUiQ@mail.gmail.com>
On Mon, Oct 20, 2025 at 03:00:24PM +0200, Geert Uytterhoeven wrote:
> Hi Yury,
>
> On Fri, 17 Oct 2025 at 20:51, Yury Norov <yury.norov@gmail.com> wrote:
> > On Fri, Oct 17, 2025 at 12:54:10PM +0200, Geert Uytterhoeven wrote:
> > > The existing FIELD_{GET,PREP}() macros are limited to compile-time
> > > constants. However, it is very common to prepare or extract bitfield
> > > elements where the bitfield mask is not a compile-time constant.
> > >
> > > To avoid this limitation, the AT91 clock driver and several other
> > > drivers already have their own non-const field_{prep,get}() macros.
> > > Make them available for general use by consolidating them in
> > > <linux/bitfield.h>, and improve them slightly:
> > > 1. Avoid evaluating macro parameters more than once,
> > > 2. Replace "ffs() - 1" by "__ffs()",
> > > 3. Support 64-bit use on 32-bit architectures.
> > >
> > > This is deliberately not merged into the existing FIELD_{GET,PREP}()
> > > macros, as people expressed the desire to keep stricter variants for
> > > increased safety, or for performance critical paths.
> > >
> > > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
> > > Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> > > Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > > Acked-by: Crt Mori <cmo@melexis.com>
> > > ---
> > > v4:
> > > - Add Acked-by,
> > > - Rebase on top of commit 7c68005a46108ffa ("crypto: qat - relocate
> > > power management debugfs helper APIs") in v6.17-rc1,
> > > - Convert more recently introduced upstream copies:
> > > - drivers/edac/ie31200_edac.c
> > > - drivers/iio/dac/ad3530r.c
> >
> > Can you split out the part that actually introduces the new API?
>
> Unfortunately not, as that would cause build warnings/failures due
> to conflicting redefinitions.
> That is a reason why I want to apply this patch ASAP: new copies show
> up all the time.
In a preparation patch, for each driver:
+#ifndef field_prep
#define field_prep() ...
+#endif
Or simply
+#undef field_prep
#define field_prep() ...
Then add the generic field_prep() in a separate patch. Then you can drop
ifdefery in the drivers.
Yeah, more patches, but the result is cleaner.
> > > --- a/include/linux/bitfield.h
> > > +++ b/include/linux/bitfield.h
> > > @@ -220,4 +220,40 @@ __MAKE_OP(64)
> > > #undef __MAKE_OP
> > > #undef ____MAKE_OP
> > >
> > > +/**
> > > + * 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.
> > > + * Unlike FIELD_PREP(), @mask is not limited to a compile-time constant.
> > > + */
> > > +#define field_prep(mask, val) \
> > > + ({ \
> > > + __auto_type __mask = (mask); \
> > > + typeof(mask) __val = (val); \
> > > + unsigned int __shift = sizeof(mask) <= 4 ? \
> > > + __ffs(__mask) : __ffs64(__mask); \
> > > + (__val << __shift) & __mask; \
> >
> > __ffs(0) is undef. The corresponding comment in
> > include/asm-generic/bitops/__ffs.h explicitly says: "code should check
> > against 0 first".
>
> An all zeroes mask is a bug in the code that calls field_{get,prep}().
It's a bug in FIELD_GET() - for sure. Because it's enforced in
__BF_FIELD_CHECK(). field_get() doesn't enforce it, doesn't even
mention that in the comment.
I'm not fully convinced that empty runtime mask should be a bug.
Consider memcpy(dst, src, 0). This is a no-op, but not a bug as
soon as the pointers are valid. If you _think_ it's a bug - please
enforce it.
> > I think mask = 0 is a sign of error here. Can you add a code catching
> > it at compile time, and maybe at runtime too? Something like:
> >
> > #define __field_prep(mask, val)
> > ({
> > unsigned __shift = sizeof(mask) <= 4 ? __ffs(mask) : __ffs64(mask);
> > (val << __shift) & mask;
> > })
> >
> > #define field_prep(mask, val)
> > ({
> > unsigned int __shift;
> > __auto_type __mask = (mask), __ret = 0;
> > typeof(mask) __val = (val);
> >
> > BUILD_BUG_ON_ZERO(const_true(mask == 0));
>
> Futile, as code with a constant mask should use FIELD_PREP() instead.
It's a weak argument. Sometimes compiler is smart enough to realize
that something is a constant, while people won't. Sometimes code gets
refactored. Sometimes people build complex expressions that should
work both in run-time and compile time cases. Sometimes variables are
compile- or run-time depending on config (nr_cpu_ids is an example).
The field_prep() must handle const case just as good as capitalized
version does.
> > if (WARN_ON_ONCE(mask == 0))
> > goto out;
> >
> > __ret = __field_prep(__mask, __val);
> > out:
> > ret;
> > })
>
> Should we penalize all users (this is a macro, thus inlined everywhere)
> to protect against something that is clearly a bug in the caller?
No. But we can wrap it with a config:
#ifdef CONFIG_BITFIELD_HARDENING
if (WARN_ON_ONCE(mask == 0))
goto out;
#endif
The real question here: do you want to help people to catch their bugs,
or you want them to fight it alone?
The _BF_FIELD_CHECK() authors are nice people and provide helpful guides.
(I don't insist, it's up to you.)
> E.g. do_div() does not check for a zero divisor either.
>
> > > +/**
> > > + * 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.
> > > + * Unlike FIELD_GET(), @mask is not limited to a compile-time constant.
> > > + */
> > > +#define field_get(mask, reg) \
> > > + ({ \
> > > + __auto_type __mask = (mask); \
> > > + typeof(mask) __reg = (reg); \
> >
> > This would trigger Wconversion warning. Consider
> > unsigned reg = 0xfff;
> > field_get(0xf, reg);
> >
> > <source>:6:26: warning: conversion to 'int' from 'unsigned int' may change the sign of the result [-Wsign-conversion]
> > 6 | typeof(mask) __reg = reg;
> > | ^~~
> >
> > Notice, the __auto_type makes the __mask to be int, while the reg is
>
> Apparently using typeof(mask) has the same "issue"...
>
> > unsigned int. You need to do:
> >
> > typeof(mask) __reg = (typeof(mask))(reg);
>
> ... so the cast is just hiding the issue? Worse, the cast may prevent the
> compiler from flagging other issues, e.g. when accidentally passing
> a pointer for reg.
Ok, makes sense.
> > Please enable higher warning levels for the next round.
>
> Enabling -Wsign-conversion gives lots of other (false positive?)
> warnings.
>
> > Also, because for numerals __auto_type is int, when char is enough - are
> > you sure that the macro generates the optimal code? User can workaround it
> > with:
> >
> > field_get((u8)0xf, reg)
> >
> > but it may not be trivial. Can you add an example and explanation please?
>
> These new macros are intended for the case where mask is not a constant.
> So typically it is a variable of type u32 or u64.
You never mentioned that. Anyways, it's again a weak argument.
> > > + unsigned int __shift = sizeof(mask) <= 4 ? \
> > > + __ffs(__mask) : __ffs64(__mask); \
> >
> > Can you use BITS_PER_TYPE() here?
>
> Yes, I could use BITS_PER_TYPE(unsigned long) here, to match the
> parameter type of __ffs() (on 64-bit platforms, __ffs() can be used
> unconditionally anyway), at the expense of making the line much longer
> so it has to be split. Is that worthwhile?
Not sure I understand... The
"unsigned int __shift = BITS_PER_TYPE(mask) < 64 ?"
is 49 chars long vs 42 in your version. Even if you add two tabs, it's
still way below limits. And yes,
unsigned int __shift = sizeof(mask) <= 4 ? \
__ffs(__mask) : __ffs64(__mask); \
is worse than
unsigned int __shift = BITS_PER_TYPE(mask) < 64 ? \
__ffs(__mask) : __ffs64(__mask); \
> > > + (__reg & __mask) >> __shift; \
> > > + })
> > > +
> >
> > When mask == 0, we shouldn't touch 'val' at all. Consider
> >
> > field_get(0, get_user(ptr))
> >
> > In this case, evaluating 'reg' is an error, similarly to memcpy().
>
> Again, a zero mask is a bug.
>
> Thanks!
>
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
> -- Linus Torvalds
next prev parent reply other threads:[~2025-10-22 22:46 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-17 10:54 [PATCH v4 0/4] Non-const bitfield helpers Geert Uytterhoeven
2025-10-17 10:54 ` [PATCH v4 1/4] bitfield: Drop underscores from macro parameters Geert Uytterhoeven
2025-10-17 16:37 ` Yury Norov
2025-10-20 12:13 ` Geert Uytterhoeven
2025-10-20 14:56 ` Yury Norov
2025-10-17 10:54 ` [PATCH v4 2/4] bitfield: Add non-constant field_{prep,get}() helpers Geert Uytterhoeven
2025-10-17 12:33 ` Nuno Sá
2025-10-17 12:43 ` Richard GENOUD
2025-10-17 18:51 ` Yury Norov
2025-10-20 13:00 ` Geert Uytterhoeven
2025-10-22 4:20 ` Yury Norov [this message]
2025-10-22 10:01 ` Geert Uytterhoeven
2025-10-22 15:50 ` Yury Norov
2025-10-23 11:38 ` Geert Uytterhoeven
2025-10-17 10:54 ` [PATCH v4 3/4] clk: renesas: Use bitfield helpers Geert Uytterhoeven
2025-10-17 10:54 ` [PATCH v4 4/4] soc: " Geert Uytterhoeven
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=aPhbhQEWAel4aD9t@yury \
--to=yury.norov@gmail.com \
--cc=Jianping.Shen@de.bosch.com \
--cc=Jonathan.Cameron@huawei.com \
--cc=Michael.Hennerich@analog.com \
--cc=alexandre.belloni@bootlin.com \
--cc=andrew@codeconstruct.com.au \
--cc=andy@kernel.org \
--cc=biju.das.jz@bp.renesas.com \
--cc=bp@alien8.de \
--cc=brgl@bgdev.pl \
--cc=claudiu.beznea@tuxon.dev \
--cc=cmo@melexis.com \
--cc=davem@davemloft.net \
--cc=david.laight.linux@gmail.com \
--cc=demonsingur@gmail.com \
--cc=dlechner@baylibre.com \
--cc=elder@ieee.org \
--cc=geert@linux-m68k.org \
--cc=giovanni.cabiddu@intel.com \
--cc=herbert@gondor.apana.org.au \
--cc=jbaron@akamai.com \
--cc=jic23@kernel.org \
--cc=joel@jms.id.au \
--cc=johannes@sipsolutions.net \
--cc=kimseer.paller@analog.com \
--cc=kuba@kernel.org \
--cc=lars@metafoo.de \
--cc=linus.walleij@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-aspeed@lists.ozlabs.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-edac@vger.kernel.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-renesas-soc@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=linux@rasmusvillemoes.dk \
--cc=mailhol.vincent@wanadoo.fr \
--cc=mturquette@baylibre.com \
--cc=nicolas.ferre@microchip.com \
--cc=nuno.sa@analog.com \
--cc=perex@perex.cz \
--cc=qat-linux@intel.com \
--cc=richard.genoud@bootlin.com \
--cc=sboyd@kernel.org \
--cc=schung@nuvoton.com \
--cc=tiwai@suse.com \
--cc=tony.luck@intel.com \
--cc=ychuang3@nuvoton.com \
/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.