RFC: Support for U-Boot phases in Kconfig

Simon Glass sjg at chromium.org
Tue Aug 10 22:32:19 CEST 2021


Hi Sean,

On Mon, 9 Aug 2021 at 16:31, Sean Anderson <sean.anderson at seco.com> wrote:
>
>
>
> On 8/7/21 6:23 PM, Simon Glass wrote:
> > Hi,
> >
> > U-Boot can be configured to build the source multiple times to product
multiple
> > 'phases'. The main phase is the full U-Boot, but an 'SPL' (Secondary
Program
> > Loader) build can produce a cut-down image only suitable for loading
U-Boot
> > proper.
> >
> > SPL does not want to use the same Kconfig options, since that would
produce the
> > same binary. Instead we have two copies of some options, one with an
SPL prefix,
> > that can be configured independently. In the source code we can use a
macro to
> > see if code should be run:
> >
> >     if (CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER)) {
> >         ...
> >     }
> >
> > This expands to check either checking SYS_STDIO_DEREGISTER or
> > SPL_SYS_STDIO_DEREGISTER, depending on which phase is being built.
> >
> > U-Boot also has TPL (Tertiary Program Loader) which works a similar
way. This
> > is causing quite an expansion of the Kconfig source, with quite a bit of
> > duplication. Each time a new feature needs to be supported in SPL, it
involves
> > a patch to add the same options again but for SPL.
> >
> >
> > Here are some proposed changes to make it easier to deal with SPL/TPL:
> >
> > 1. Kconfig support

[..]

> > 4. Add macros to help avoid more #ifdefs
> >
> > We sometimes have to use #ifdefs in structs or drivers:
> >
> >      struct spl_image_loader {
> >      #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
> >          const char *name;
> >      #endif
> >          ...
> >      };
> >
> >      UCLASS_DRIVER(spi) = {
> >          .id      = UCLASS_SPI,
> >          .name      = "spi",
> >          .flags      = DM_UC_FLAG_SEQ_ALIAS,
> >      #if CONFIG_IS_ENABLED(OF_CONTROL) &&
!CONFIG_IS_ENABLED(OF_PLATDATA)
> >          .post_bind   = dm_scan_fdt_dev,
> >      #endif
> >          ...
> >      };
> >
> > This is a pain. We can add an IF_CONFIG macro to help with this:
> >
> >      struct spl_image_loader {
> >          IF_CONFIG(LIBCOMMON_SUPPORT, const char *name;)
> >          ...
> >      };
> >
> >      UCLASS_DRIVER(spi) = {
> >          .id      = UCLASS_SPI,
> >          .name      = "spi",
> >          .flags      = DM_UC_FLAG_SEQ_ALIAS,
> >          IF_CONFIG(REAL, .post_bind   = dm_scan_fdt_dev,)
>
> Wouldn't cpp eat the trailing comma here? This seems pretty tricky to
> use. And of course, you still need something like

Yes you're right. The comma is a pain. Needs more thought.

>
>         struct spl_image_loader *loader;
>         loader = ... ;
> #if CONFIG(LIBCOMMON_SUPPORT)
>         foo(loader->name);
> #endif
>
> unless you have some other macro to wrap the name access.

Yes that's the other side of it that I forgot. I think a macro that
converts the member to NULL or something might work. Needs more thought.

[..]

> > 6. Discarding static functions
> >
> > We sometimes see code like this:
> >
> >      #if CONFIG_IS_ENABLED(OF_REAL)
> >      static const struct udevice_id apl_ns16550_serial_ids[] = {
> >          { .compatible = "intel,apl-ns16550" },
> >          { },
> >          };
> >      #endif
> >
> >      U_BOOT_DRIVER(intel_apl_ns16550) = {
> >          .name   = "intel_apl_ns16550",
> >          .id   = UCLASS_SERIAL,
> >          .of_match = of_match_ptr(apl_ns16550_serial_ids),
> >          .plat_auto   = sizeof(struct apl_ns16550_plat),
> >          .priv_auto   = sizeof(struct ns16550),
> >              ...
> >          };
> >
> > The of_match_ptr() avoids an #ifdef in the driver declaration since it
evaluates
> > to NULL if !CONFIG_IS_ENABLED(OF_REAL) but we still need an #ifdef
around the
> > function, since it is static and would otherwise produce a warning.
> >
> > One solution is to drop the 'static'. But this is not very nice, since
the
> > structure clearly should not be used from another file.
> >
> > We can add STATIC_IF_CONFIG() to help with this:
> >
> >      STATIC_IF_CONFIG(OF_REAL) const struct udevice_id
> > apl_ns16550_serial_ids[] = {
> >          { .compatible = "intel,apl-ns16550" },
> >          { },
> >          };
> >      #endif
> >
> > It expands to 'static' if CONFIG(OF_REAL) is enabled, otherwise it
expand to
> > nothing, in the hope that the compiler drops the data. Failing that it
would
> > also be possible to have it expand to '__section(".discard.config")' so
at least
> > the struct is discarded, even if the compatible string is not. The
behaviour of
> > gcc/binutils in this area is not always as might be hoped.
> >
>
> What about __maybe_unused? Do functions marked that way get GC'd?

Yes but not that well. Making the macro expand to 'static __maybe_unused'
seems like a good idea to me.

Regards,
SImon


More information about the U-Boot mailing list