* Re: [PATCH] init/main.c: log initcall level when initcall_debug is used
From: Andrew Morton @ 2025-04-03 7:09 UTC (permalink / raw)
To: Rob Landley
Cc: Francesco Valla, linux-kernel, linux-embedded, Steven Rostedt,
Tim Bird, Petr Mladek
In-Reply-To: <5b8eea42-76cd-414d-b2f8-416336a9ae27@landley.net>
On Thu, 3 Apr 2025 01:42:46 -0500 Rob Landley <rob@landley.net> wrote:
> On 4/2/25 21:55, Andrew Morton wrote:
> > Please review and test this fixlet:
> >
> > --- a/init/main.c~init-mainc-log-initcall-level-when-initcall_debug-is-used-fix
> > +++ a/init/main.c
> > @@ -1217,7 +1217,7 @@ trace_initcall_finish_cb(void *data, ini
> > static __init_or_module void
> > trace_initcall_level_cb(void *data, const char *level)
> > {
> > - printk(KERN_DEBUG "entering initcall level: %s\n", level);
> > + pr_debug("entering initcall level: %s\n", level);
> > }
>
> How do I tell kconfig to remove all pr_blah() below loglevel X so they
> aren't compiled into the kernel taking up space? I thought that was the
> reason for switching to the pr_thingy() macros (it was in the old -tiny
> tree Mackall walked away from) but last time I tried to do it in vanilla
> I couldn't find the knob or trace the relevant plumbing...
Ask the maintainer :)
I can't see a way. Maybe it was never merged.
^ permalink raw reply
* Re: [PATCH] init/main.c: log initcall level when initcall_debug is used
From: Geert Uytterhoeven @ 2025-04-03 8:27 UTC (permalink / raw)
To: Andrew Morton
Cc: Francesco Valla, linux-kernel, linux-embedded, Steven Rostedt,
Tim Bird
In-Reply-To: <20250402195544.4897a774456eba75915cded7@linux-foundation.org>
Hi Andrew,
On Thu, 3 Apr 2025 at 04:56, Andrew Morton <akpm@linux-foundation.org> wrote:
> On Sun, 16 Mar 2025 21:50:15 +0100 Francesco Valla <francesco@valla.it> wrote:
> > When initcall_debug is specified on the command line, the start and
> > return point for each initcall is printed. However, no information on
> > the initcall level is reported.
> >
> > Add to the initcall_debug infrastructure an additional print that
> > informs when a new initcall level is entered. This is particularly
> > useful when debugging dependency chains and/or working on boot time
> > reduction.
> >
> > ...
> >
> > --- a/init/main.c
> > +++ b/init/main.c
> > @@ -1214,6 +1214,12 @@ trace_initcall_finish_cb(void *data, initcall_t fn, int ret)
> > fn, ret, (unsigned long long)ktime_us_delta(rettime, *calltime));
> > }
> >
> > +static __init_or_module void
> > +trace_initcall_level_cb(void *data, const char *level)
> > +{
> > + printk(KERN_DEBUG "entering initcall level: %s\n", level);
> > +}
>
> Please review and test this fixlet:
>
> --- a/init/main.c~init-mainc-log-initcall-level-when-initcall_debug-is-used-fix
> +++ a/init/main.c
> @@ -1217,7 +1217,7 @@ trace_initcall_finish_cb(void *data, ini
> static __init_or_module void
> trace_initcall_level_cb(void *data, const char *level)
> {
> - printk(KERN_DEBUG "entering initcall level: %s\n", level);
> + pr_debug("entering initcall level: %s\n", level);
> }
>
> static ktime_t initcall_calltime;
I think the "printk(KERN_DEBUG ...)" construct is intentional.
The message should be logged when "initcall_debug" is passed on
the kernel command line, while pr_debug() is a no-op unless DEBUG is
defined inside the source file.
See also the two existing users in init/main.c near
https://elixir.bootlin.com/linux/v6.13.7/source/init/main.c#L1207.
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
^ permalink raw reply
* Re: [PATCH] init/main.c: log initcall level when initcall_debug is used
From: Petr Mladek @ 2025-04-03 9:49 UTC (permalink / raw)
To: Andrew Morton
Cc: Rob Landley, Francesco Valla, linux-kernel, linux-embedded,
Steven Rostedt, Tim Bird
In-Reply-To: <20250403000935.e48f8552231a28d06765b777@linux-foundation.org>
On Thu 2025-04-03 00:09:35, Andrew Morton wrote:
> On Thu, 3 Apr 2025 01:42:46 -0500 Rob Landley <rob@landley.net> wrote:
>
> > On 4/2/25 21:55, Andrew Morton wrote:
> > > Please review and test this fixlet:
> > >
> > > --- a/init/main.c~init-mainc-log-initcall-level-when-initcall_debug-is-used-fix
> > > +++ a/init/main.c
> > > @@ -1217,7 +1217,7 @@ trace_initcall_finish_cb(void *data, ini
> > > static __init_or_module void
> > > trace_initcall_level_cb(void *data, const char *level)
> > > {
> > > - printk(KERN_DEBUG "entering initcall level: %s\n", level);
> > > + pr_debug("entering initcall level: %s\n", level);
> > > }
> >
> > How do I tell kconfig to remove all pr_blah() below loglevel X so they
> > aren't compiled into the kernel taking up space? I thought that was the
> > reason for switching to the pr_thingy() macros (it was in the old -tiny
> > tree Mackall walked away from) but last time I tried to do it in vanilla
> > I couldn't find the knob or trace the relevant plumbing...
>
> Ask the maintainer :)
>
> I can't see a way. Maybe it was never merged.
If I read the definition of pr_debug() correctly then it should
become nop when CONFIG_DYNAMIC_DEBUG is not defined, look
for "pr_debug" and "no_printk" in include/linux/printk.h.
That said, I have never checked this. Another condition is
that DEBUG must not be defined. But I guess that it is
the default.
Best Regards,
Petr
^ permalink raw reply
* Re: [PATCH] init/main.c: log initcall level when initcall_debug is used
From: Francesco Valla @ 2025-04-03 20:11 UTC (permalink / raw)
To: Andrew Morton, Geert Uytterhoeven
Cc: linux-kernel, linux-embedded, Steven Rostedt, Tim Bird
In-Reply-To: <CAMuHMdXSLhypYULqfCm55MQxZCwLzxBBc7mnr6OBcPaHFwh2Lw@mail.gmail.com>
On Thursday, 3 April 2025 at 10:27:14 Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> Hi Andrew,
>
> On Thu, 3 Apr 2025 at 04:56, Andrew Morton <akpm@linux-foundation.org> wrote:
> > On Sun, 16 Mar 2025 21:50:15 +0100 Francesco Valla <francesco@valla.it> wrote:
> > > When initcall_debug is specified on the command line, the start and
> > > return point for each initcall is printed. However, no information on
> > > the initcall level is reported.
> > >
> > > Add to the initcall_debug infrastructure an additional print that
> > > informs when a new initcall level is entered. This is particularly
> > > useful when debugging dependency chains and/or working on boot time
> > > reduction.
> > >
> > > ...
> > >
> > > --- a/init/main.c
> > > +++ b/init/main.c
> > > @@ -1214,6 +1214,12 @@ trace_initcall_finish_cb(void *data, initcall_t fn, int ret)
> > > fn, ret, (unsigned long long)ktime_us_delta(rettime, *calltime));
> > > }
> > >
> > > +static __init_or_module void
> > > +trace_initcall_level_cb(void *data, const char *level)
> > > +{
> > > + printk(KERN_DEBUG "entering initcall level: %s\n", level);
> > > +}
> >
> > Please review and test this fixlet:
> >
> > --- a/init/main.c~init-mainc-log-initcall-level-when-initcall_debug-is-used-fix
> > +++ a/init/main.c
> > @@ -1217,7 +1217,7 @@ trace_initcall_finish_cb(void *data, ini
> > static __init_or_module void
> > trace_initcall_level_cb(void *data, const char *level)
> > {
> > - printk(KERN_DEBUG "entering initcall level: %s\n", level);
> > + pr_debug("entering initcall level: %s\n", level);
> > }
> >
> > static ktime_t initcall_calltime;
>
> I think the "printk(KERN_DEBUG ...)" construct is intentional.
> The message should be logged when "initcall_debug" is passed on
> the kernel command line, while pr_debug() is a no-op unless DEBUG is
> defined inside the source file.
>
> See also the two existing users in init/main.c near
> https://elixir.bootlin.com/linux/v6.13.7/source/init/main.c#L1207.
>
Yes, printk(KERN_DEBUG ...) here is intentional, or it would be removed,
as Geert is correctly saying.
We have another occurrence of this for the "probe" messages also related
to initcall_debug, with a nice explanatory comment:
https://elixir.bootlin.com/linux/v6.14-rc6/source/drivers/base/dd.c#L741
Thank you!
Francesco
^ permalink raw reply
* Re: [PATCH] init/main.c: log initcall level when initcall_debug is used
From: Francesco Valla @ 2025-04-03 20:04 UTC (permalink / raw)
To: linux-kernel@vger.kernel.org, linux-embedded@vger.kernel.org,
Bird, Tim
Cc: Steven Rostedt, Andrew Morton
In-Reply-To: <MW5PR13MB563289C2D6F95091501E017AFDAC2@MW5PR13MB5632.namprd13.prod.outlook.com>
Hi Tim,
On Tuesday, 1 April 2025 at 19:57:22 Bird, Tim <Tim.Bird@sony.com> wrote:
> > -----Original Message-----
> > From: Francesco Valla <francesco@valla.it>
> > When initcall_debug is specified on the command line, the start and
> > return point for each initcall is printed. However, no information on
> > the initcall level is reported.
> >
> > Add to the initcall_debug infrastructure an additional print that
> > informs when a new initcall level is entered. This is particularly
> > useful when debugging dependency chains and/or working on boot time
> > reduction.
> >
> > Signed-off-by: Francesco Valla <francesco@valla.it>
> > ---
> > init/main.c | 18 ++++++++++++++++--
> > 1 file changed, 16 insertions(+), 2 deletions(-)
> >
> > diff --git a/init/main.c b/init/main.c
> > index 2a1757826397..80a07563036d 100644
> > --- a/init/main.c
> > +++ b/init/main.c
> > @@ -1214,6 +1214,12 @@ trace_initcall_finish_cb(void *data, initcall_t fn, int ret)
> > fn, ret, (unsigned long long)ktime_us_delta(rettime, *calltime));
> > }
> >
> > +static __init_or_module void
> > +trace_initcall_level_cb(void *data, const char *level)
> > +{
> > + printk(KERN_DEBUG "entering initcall level: %s\n", level);
> > +}
> > +
> > static ktime_t initcall_calltime;
> >
> > #ifdef TRACEPOINTS_ENABLED
> > @@ -1225,10 +1231,12 @@ static void __init initcall_debug_enable(void)
> > &initcall_calltime);
> > ret |= register_trace_initcall_finish(trace_initcall_finish_cb,
> > &initcall_calltime);
> > + ret |= register_trace_initcall_level(trace_initcall_level_cb, NULL);
> > WARN(ret, "Failed to register initcall tracepoints\n");
> > }
> > # define do_trace_initcall_start trace_initcall_start
> > # define do_trace_initcall_finish trace_initcall_finish
> > +# define do_trace_initcall_level trace_initcall_level
> > #else
> > static inline void do_trace_initcall_start(initcall_t fn)
> > {
> > @@ -1242,6 +1250,12 @@ static inline void do_trace_initcall_finish(initcall_t fn, int ret)
> > return;
> > trace_initcall_finish_cb(&initcall_calltime, fn, ret);
> > }
> > +static inline void do_trace_initcall_level(const char *level)
> > +{
> > + if (!initcall_debug)
> > + return;
> > + trace_initcall_level_cb(NULL, level);
> > +}
> > #endif /* !TRACEPOINTS_ENABLED */
> >
> > int __init_or_module do_one_initcall(initcall_t fn)
> > @@ -1314,7 +1328,7 @@ static void __init do_initcall_level(int level, char *command_line)
> > level, level,
> > NULL, ignore_unknown_bootoption);
> >
> > - trace_initcall_level(initcall_level_names[level]);
> > + do_trace_initcall_level(initcall_level_names[level]);
> > for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
> > do_one_initcall(initcall_from_entry(fn));
> > }
> > @@ -1358,7 +1372,7 @@ static void __init do_pre_smp_initcalls(void)
> > {
> > initcall_entry_t *fn;
> >
> > - trace_initcall_level("early");
> > + do_trace_initcall_level("early");
> > for (fn = __initcall_start; fn < __initcall0_start; fn++)
> > do_one_initcall(initcall_from_entry(fn));
> > }
> > --
> > 2.48.1
>
> This all looks good to me. Just to clarify, does tracing have to be enabled to get an
> the 'entering initcall level...' printk message? Or will you get a printk message with
> tracing disabled, but initcall_debug specified on the command line?
>
No, tracing doesn't have to be enabled. We are just attaching to the tracing subsystem
if it's there, just like it is done for the "calling" / "initcall returned" messages.
> What do we need to do to push this into mainline? Based on our discussion in the SIG
> meeting, there's no official maintainer for init/main.c. I recommend pushing this
> through Andrew Morton's tree, unless we can think of a better tree to push it through.
> Since it does affect a tracer, maybe through Steve's tree?
>
> Another option is for you, Francesco, to become the maintainer of init/main.c (!)
> Let me know if you're interested in that. We'll likely have some more boot-time
> things to work on in init/main.c, and it would be nice to have someone managing
> this stuff as it comes in.
>
I fear I don't have the knowledge to maintain init/main.c, unfortunately. I can
for sure take a look at other MRs related to it, but that's it - I don't wan't to
take a commitment I cannot / am not able to honor.
> Thanks, Francesco, for proposing this patch. I think it will obviate the need for a portion of
> my Boot Markers patch, that I suggested at Plumbers last year.
> -- Tim
>
Thank you for the review!
Francesco
^ permalink raw reply
* [ANNOUNCE] Embedded Recipes conference: May 14-16, Nice, France
From: Kevin Hilman @ 2025-04-04 20:14 UTC (permalink / raw)
To: linux-embedded; +Cc: linux-arm-kernel, linux-kernel
Hello,
Join us May 14-16 in Nice, France for a small conference focused on
embedded Linux (and more!):
https://embedded-recipes.org/2025/
Embedded Recipes (ER) is a small, open source conference (~150 people),
with 2 days of technical talks[1] in a single track, followed by an
optional day of technical workshops/hacking days etc.[2]
Also, that same week other events such as the media summit[3] and the
GStreamer hackfset[4] will also be held nearby in Nice.
So if you're in Europe (or want to be) in May, join other embedded
developers in the sun of the French Riviera for a great technical
conference.
See you in Nice!
Kevin
[1] https://embedded-recipes.org/2025/speakers/
[2] https://embedded-recipes.org/2025/workshops/
[3] https://lore.kernel.org/linux-media/18ac3f06-58c2-4121-86a5-f8a2b5d1e47c@xs4all.nl/T/#m0ec5a88d4b24dc3bd3db6e0c6309031de1afc216
[4] https://discourse.gstreamer.org/t/gstreamer-spring-hackfest-2025-on-16-18-may-2025-in-nice-france/4366/
^ permalink raw reply
* Reminder of boot-time SIG meeting for April
From: Bird, Tim @ 2025-04-22 1:54 UTC (permalink / raw)
To: linux-embedded@vger.kernel.org
Hey Linux Boot-Time SIG interested parties (and other interested Linux kernel developers),
Here is the information for the next Linux Boot-Time SIG conference call.
The meeting will be held via the Jitsi online meeting platform.
To Join the meeting via web, click on:
https://meet.jit.si/LinuxBootTimeSIG
----
Our next meeting is Tuesday, April 22, at 9:00 am Mountain Daylight Time.
See this link for other time zones:
https://www.timeanddate.com/worldclock/meetingdetails.html?year=2025&month=04&day=22&hour=15&min=0&sec=0&p1=220&p2=137&p3=195&p4=771
(That makes it 8:00 am Pacific, 15:00 UTC, 17:00 CET, and 20:30 IST)
I'm planning on 1 hour for this meeting.
The agenda for the meeting (and where we'll keep the minutes) is here:
https://docs.google.com/document/d/1XAufoTT6VVJOTMzKMoz8SyOss-JA9H4J1_yVXQq5mN0/edit?usp=sharing
The agenda for the April 22 meeting is:
- Round-table of on-going work
- Work on the Boot Time wiki (section of elinux wiki) https://elinux.org/Boot_Time
- Status of the Boot Time Data wiki (on birdcloud.org) https://birdcloud.org/boot-time/Boot_Data
- patches in flight:
- init/main.c: print initcall level when initcall_debug is used (Francesco Valla)
- analyze-initcall-debug.py (Francesco Valla)
- work pending submission upstream:
- show_delta version 2.0 (Tim Bird)
- deferred initcalls (Tim Bird)
- Are there any other patches in flight?
- What are people working on?
- deferred memory init (Qualcomm?)
- boot caching (the Good Penguin?)
- unified boot log (TI)
- CPU cycle counter logging (for firmware, kernel, user-space)
- Status of Sony boot-time work:
- boot time wiki (grab-boot-data.sh, boot-data repository, and BootRegion wiki processor)
- boot markers -> boot regions -> common printks (nothing published yet)
- Status of RedHat boot time work?
- [Eric] - patches submitted a couple of years ago - mounting volumes - might trigger errors
- Are currently tracking boot-time variances
- Status of Texas Instruments boot time work?
- [Vishnu] - update on work on boot markers (passing cycle-count timestamps between firmware and kernel)
- During startup, firmware runs on different processors, with different cycle-counters.
- Need generic mechanisms for handling tagging of timestamps, passing data between systems
- Status of Qualcomm deferred memory init patch?
- Qualcomm not on call, but TI is interested in seeing this, and other deferred init work, mainlined
- Review of project ideas
- See https://elinux.org/Boot_Time_Project_Ideas
- TGP (The Good Penguin) has some stuff they did with boot caching - see the page for details
- Review of action items
- Engaging more developers
- Next meeting - Tuesday, May 27, 9:00 am Mountain Daylight Time
- current periodicity = 1 month (the 4th Tuesday of every month
----
I look forward to talking with you in the meeting.
-- Tim
^ permalink raw reply
* [boot time] elinux wiki page for Unified Boot Log was created
From: Bird, Tim @ 2025-04-23 0:51 UTC (permalink / raw)
To: linux-embedded@vger.kernel.org
Hey everyone,
I've created a page on the elinux wiki for information, discussion, and data
dumping about the "Unified Boot Log" we discussed in our meeting today.
Here is the page:
https://elinux.org/Unified_Boot_Log
Right now, it's just my own mind dump of what I think we're referring to,
and some of the requirements and design elements that I think are
worth discussing.
Feel free to raise questions about the content now, or we can discuss it
in our (special) Boot-time SIG call on May 20th on this topic.
-- Tim
^ permalink raw reply
* ER2025: labgrid workshop attendees
From: Kevin Hilman @ 2025-05-15 21:23 UTC (permalink / raw)
To: Bastian Krause, Leonard Goehrs; +Cc: event-orga, Linux Embedded
Hi Bastian, Leonard,
ER has been busy and I just realized we never sent you the list of
participants for you workship. Here's the list of names we got from
the registration as of yesterday:
MARTELLI, Matteo
MANGIAROTTI, Michele
VALLA, Francesco
SANG, Wolfram
FERREIRA, Guilherme
GOKHALE, Varad
NIEDERMAIER, Christoph
NEUHAUSER, Johann
FROST, Benjamin
^ permalink raw reply
* Re: ER2025: labgrid workshop attendees
From: Kevin Hilman @ 2025-05-16 5:21 UTC (permalink / raw)
To: Linux Embedded
In-Reply-To: <CAOi56cUxTs=vJW87iatugQbeSD6z4HPbpLoEkXv8+vnunV=HJA@mail.gmail.com>
Wrong mailing list, sorry for the noise.
^ permalink raw reply
* [boot-time] Unified Boot Log - special topic call for Boot-Time SIG (meeting announcement)
From: Bird, Tim @ 2025-05-19 15:58 UTC (permalink / raw)
To: Linux Embedded
Hey Linux Boot-Time SIG interested parties (and other interested Linux kernel developers),
Here is the information for the next Linux Boot-Time SIG conference call.
This call is a "special topic" call, on the subject of Unified Boot Log.
See https://elinux.org/Unified_Boot_Log
The meeting will be held via the Jitsi online meeting platform.
To Join the meeting via web, click on:
https://meet.jit.si/LinuxBootTimeSIG
----
The meeting is Tuesday, May 20, at 9:00 am Mountain Daylight Time.
See this link for other time zones:
https://www.timeanddate.com/worldclock/meetingdetails.html?year=2025&month=05&day=20&hour=15&min=0&sec=0&p1=220&p2=137&p3=195&p4=771
(That makes it 8:00 am Pacific, 15:00 UTC, 17:00 CEST, and 20:30 IST)
Please note that this is NOT our regularly scheduled monthly SIG call, which is next week.
I'm planning on 30 minutes for this meeting, but I can go longer if the discussion warrants.
The agenda for the meeting (and where we'll keep the minutes) is here:
https://docs.google.com/document/d/1XAufoTT6VVJOTMzKMoz8SyOss-JA9H4J1_yVXQq5mN0/edit?usp=sharing
The agenda for this meeting is:
- Discuss issues with the Unified Boot Log
- review elinux page: https://elinux.org/Unified_Boot_Log
- discuss existing/related efforts:
- U-Boot's boot-stage: https://github.com/u-boot/u-boot/blob/master/include/bootstage.h
- RedHat's boot-time-analysis tools: (cntvct and boot-time)
- https://gitlab.com/CentOS/automotive/src/boot-time-analysis-tools
I look forward to talking with you in the meeting.
-- Tim
^ permalink raw reply
* RE: [boot-time] Unified Boot Log - special topic call for Boot-Time SIG (meeting announcement)
From: Bird, Tim @ 2025-05-21 20:47 UTC (permalink / raw)
To: Saravana Kannan; +Cc: Linux Embedded
In-Reply-To: <CAGETcx9S2nyz00G3fq1taz9QEshpTPmaUX_+=FyHzzj--ELEXg@mail.gmail.com>
> -----Original Message-----
> From: Saravana Kannan <saravanak@google.com>
> Hi Tim,
>
> Could you send out these reminders 2 days earlier? I always miss them and see them later in the day on Tuesdays and regret not being able to
> attend it. It has happened at least 3 times so far.
Yes. I'll try to get these reminders out earlier. I apologize these have been so late.
My goal is to send the reminder the week before (like Wednesday or Thursday), but
I was traveling last week and got behind.
>
> Another option is to have some calendar that people could subscribe to.
I should look into that. My process leaves something to be desired.
I appreciate you reminding me to improve my process here!
Regards,
-- Tim
> On Mon, May 19, 2025 at 9:23 AM Bird, Tim <Tim.Bird@sony.com <mailto:Tim.Bird@sony.com> > wrote:
>
>
> Hey Linux Boot-Time SIG interested parties (and other interested Linux kernel developers),
>
> Here is the information for the next Linux Boot-Time SIG conference call.
>
> This call is a "special topic" call, on the subject of Unified Boot Log.
> See https://elinux.org/Unified_Boot_Log
>
> The meeting will be held via the Jitsi online meeting platform.
> To Join the meeting via web, click on:
> https://meet.jit.si/LinuxBootTimeSIG
>
> ----
> The meeting is Tuesday, May 20, at 9:00 am Mountain Daylight Time.
> See this link for other time zones:
> https://www.timeanddate.com/worldclock/meetingdetails.html?year=2025&month=05&day=20&hour=15&min=0&sec=0&p1=220&
> p2=137&p3=195&p4=771
> (That makes it 8:00 am Pacific, 15:00 UTC, 17:00 CEST, and 20:30 IST)
>
> Please note that this is NOT our regularly scheduled monthly SIG call, which is next week.
>
> I'm planning on 30 minutes for this meeting, but I can go longer if the discussion warrants.
>
> The agenda for the meeting (and where we'll keep the minutes) is here:
> https://docs.google.com/document/d/1XAufoTT6VVJOTMzKMoz8SyOss-JA9H4J1_yVXQq5mN0/edit?usp=sharing
>
> The agenda for this meeting is:
> - Discuss issues with the Unified Boot Log
> - review elinux page: https://elinux.org/Unified_Boot_Log
> - discuss existing/related efforts:
> - U-Boot's boot-stage: https://github.com/u-boot/u-boot/blob/master/include/bootstage.h
> - RedHat's boot-time-analysis tools: (cntvct and boot-time)
> - https://gitlab.com/CentOS/automotive/src/boot-time-analysis-tools
>
> I look forward to talking with you in the meeting.
> -- Tim
>
>
^ permalink raw reply
* [PATCH 1/1] drivers: misc: add driver for bootstage stash
From: Francesco Valla @ 2025-05-22 22:42 UTC (permalink / raw)
To: linux-embedded
In-Reply-To: <20250522224223.358881-2-francesco@valla.it>
Add support for bootstage stash areas containing boot time data
created by some bootloader (e.g. U-Boot). The driver provides generic
time information through sysfs and platform-specific one through
debugfs.
Signed-off-by: Francesco Valla <francesco@valla.it>
---
.../bindings/reserved-memory/bootstage.yaml | 44 +++
Documentation/misc-devices/bootstage.rst | 53 ++++
Documentation/misc-devices/index.rst | 1 +
MAINTAINERS | 7 +
drivers/misc/Kconfig | 10 +
drivers/misc/Makefile | 1 +
drivers/misc/bootstage.c | 292 ++++++++++++++++++
drivers/of/platform.c | 1 +
8 files changed, 409 insertions(+)
create mode 100644 Documentation/devicetree/bindings/reserved-memory/bootstage.yaml
create mode 100644 Documentation/misc-devices/bootstage.rst
create mode 100644 drivers/misc/bootstage.c
diff --git a/Documentation/devicetree/bindings/reserved-memory/bootstage.yaml b/Documentation/devicetree/bindings/reserved-memory/bootstage.yaml
new file mode 100644
index 000000000000..e71d85c5c2ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/reserved-memory/bootstage.yaml
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reserved-memory/bootstage.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bootstage stash
+
+description: |
+ This binding represents a reserved memory region containing bootstage stash
+ data generated by a previous bootloader stage.
+
+maintainers:
+ - Francesco Valla <francesco@valla.it>
+
+allOf:
+ - $ref: reserved-memory.yaml
+
+properties:
+ compatible:
+ const: bootstage
+
+ reg:
+ description: page-aligned region of memory containing bootstage stash data
+
+required:
+ - compatible
+ - reg
+ - no-map
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ bootstage: bootstage@12340000 {
+ compatible = "bootstage";
+ reg = <0x00 0x12340000 0x2000>;
+ no-map;
+ };
+ };
diff --git a/Documentation/misc-devices/bootstage.rst b/Documentation/misc-devices/bootstage.rst
new file mode 100644
index 000000000000..2e1bbd31aab8
--- /dev/null
+++ b/Documentation/misc-devices/bootstage.rst
@@ -0,0 +1,53 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================
+Bootstage driver
+================
+
+The bootstage driver exports interfaces to read from a bootstage stash area
+saved by a bootloader (e.g.: U-Boot) that ran before the Linux kernel.
+
+Two kind of interfaces are exported:
+
+- a sysfs interface for bootloader- and platform-agnostic data
+- a debugfs interface for bootloader- and platform-specific data
+
+
+The sysfs interface
+-------------------
+
+Following sysfs attributes can be found at /sys/devices/platform/<device-name>/:
+
+- start_time_us: bootloader start time in microseconds
+- end_time_us: bootloader end time in microseconds
+
+
+The debugfs interface
+---------------------
+
+Following debugfs interfaces can be found at
+/sys/kernel/debug/bootstage/<device-name>/:
+
+- stages: details on staged bootloader stages, with start time and duration.
+ Example output::
+
+ Mark (us) Elapsed (us) Stage
+ 0 0 reset
+ 183689 183689 SPL
+ 489247 305558 end phase
+ 506987 17740 board_init_f
+ 1257880 750893 board_init_r
+ 1622303 364423 eth_common_init
+ 1888033 265730 eth_initialize
+ 1893077 5044 main_loop
+ 4204282 2311205 cli_loop
+
+- accumulated_time: time accumulated during certain bootloader stages.
+ Example output::
+
+ Time (us) Stage
+ 4902 dm_spl
+ 322719 dm_f
+ 9527 dm_r
+
+The number and type of staged stages are bootloader- and platform-specific.
diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst
index 8c5b226d8313..c5ebb3d44505 100644
--- a/Documentation/misc-devices/index.rst
+++ b/Documentation/misc-devices/index.rst
@@ -28,3 +28,4 @@ fit into other categories.
tps6594-pfsm
uacce
xilinx_sdfec
+ bootstage
diff --git a/MAINTAINERS b/MAINTAINERS
index f21f1dabb5fe..0bdecd07023a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4203,6 +4203,13 @@ F: Documentation/ABI/stable/sysfs-class-bluetooth
F: include/net/bluetooth/
F: net/bluetooth/
+BOOTSTAGE DRIVER
+M: Francesco Valla <francesco@valla.it>
+L: linux-embedded@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/reserved-memory/bootstage.yaml
+F: drivers/misc/bootstage.c
+
BONDING DRIVER
M: Jay Vosburgh <jv@jvosburgh.net>
L: netdev@vger.kernel.org
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 6b37d61150ee..97cdfa241c0c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -632,6 +632,16 @@ config MCHP_LAN966X_PCI
- lan966x-miim (MDIO_MSCC_MIIM)
- lan966x-switch (LAN966X_SWITCH)
+config BOOTSTAGE
+ tristate "Bootstage stash support"
+ depends on OF_RESERVED_MEM
+ help
+ This enables the support for a bootstage stash.
+
+ A bootstage stash can be created by some bootloaders (e.g.: U-Boot) to
+ store information on its boot timings. This driver provides access to
+ these information through sysfs and debugsfs interfaces.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index d6c917229c45..3562c1bf701f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -74,3 +74,4 @@ lan966x-pci-objs := lan966x_pci.o
lan966x-pci-objs += lan966x_pci.dtbo.o
obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o
obj-y += keba/
+obj-$(CONFIG_BOOTSTAGE) += bootstage.o
diff --git a/drivers/misc/bootstage.c b/drivers/misc/bootstage.c
new file mode 100644
index 000000000000..a106410a56ee
--- /dev/null
+++ b/drivers/misc/bootstage.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 - Francesco Valla <francesco@valla.it>
+ *
+ * Driver for bootstage stash.
+ *
+ * This driver exposes bootstage stash generated by bootloader and/or firmware
+ * stages that run before the Linux kernel.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+
+#define BOOTSTAGE_MAGIC 0xb00757a3
+#define BOOTSTAGE_MAX_VERSION 0
+
+enum bootstage_id {
+ BOOTSTAGE_ID_START = 0,
+};
+
+enum bootstage_flags {
+ BOOTSTAGEF_ERROR = 1 << 0, /* Error record */
+ BOOTSTAGEF_ALLOC = 1 << 1, /* Allocate an id */
+};
+
+struct bootstage_record {
+ ulong time_us;
+ u32 start_us;
+ const char *name;
+ int flags;
+ enum bootstage_id id;
+};
+
+struct bootstage_hdr {
+ u32 version; /* Boostage stash version */
+ u32 count; /* Number of records */
+ u32 size; /* Total data size (non-zero if valid) */
+ u32 magic; /* Magic number */
+ u32 next_id; /* Next ID to use for bootstage */
+};
+
+struct bootstage_drvdata {
+ struct bootstage_hdr *hdr;
+ struct bootstage_record *records;
+
+ u32 start_time_us;
+ u32 end_time_us;
+
+ struct dentry *debugfs_dir;
+};
+
+static struct dentry *bootstage_debugfs_dir;
+
+static int stages_show(struct seq_file *m, void *d)
+{
+ struct bootstage_drvdata *drvdata = m->private;
+ struct bootstage_hdr *hdr = drvdata->hdr;
+ struct bootstage_record *rec;
+ u32 prev = 0;
+ int i;
+
+ seq_printf(m, "%13s %13s %s\n", "Mark (us)", "Elapsed (us)", "Stage");
+
+ for (i = 0, rec = drvdata->records; i < hdr->count; i++, rec++) {
+ if ((rec->id && !rec->start_us) || (i == 0)) {
+ if (prev > rec->time_us)
+ prev = 0;
+ seq_printf(m, "%13lu %13lu %s\n", rec->time_us,
+ rec->time_us - prev, rec->name);
+ prev = rec->time_us;
+ }
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(stages);
+
+static int accumulated_time_show(struct seq_file *m, void *d)
+{
+ struct bootstage_drvdata *drvdata = m->private;
+ struct bootstage_hdr *hdr = drvdata->hdr;
+ struct bootstage_record *rec;
+ int i;
+
+ seq_printf(m, "%13s %s\n", "Time (us)", "Stage");
+
+ for (i = 0, rec = drvdata->records; i < hdr->count; i++, rec++) {
+ if (rec->start_us)
+ seq_printf(m, "%13lu %s\n", rec->time_us, rec->name);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(accumulated_time);
+
+static void bootstage_debugfs_init(struct device *dev, struct bootstage_drvdata *drvdata)
+{
+ drvdata->debugfs_dir = debugfs_create_dir(dev_name(dev), bootstage_debugfs_dir);
+ if (IS_ERR(drvdata->debugfs_dir))
+ return;
+
+ debugfs_create_file("stages", 0444, drvdata->debugfs_dir, drvdata, &stages_fops);
+ debugfs_create_file("accumulated_time", 0444, drvdata->debugfs_dir, drvdata,
+ &accumulated_time_fops);
+}
+
+static void bootstage_debugfs_exit(struct device *dev, struct bootstage_drvdata *drvdata)
+{
+ debugfs_remove_recursive(drvdata->debugfs_dir);
+}
+
+static ssize_t start_time_us_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bootstage_drvdata *drvdata = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", drvdata->start_time_us);
+}
+static DEVICE_ATTR_RO(start_time_us);
+
+static ssize_t end_time_us_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bootstage_drvdata *drvdata = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", drvdata->end_time_us);
+}
+static DEVICE_ATTR_RO(end_time_us);
+
+static struct attribute *bootstage_attrs[] = {
+ &dev_attr_start_time_us.attr,
+ &dev_attr_end_time_us.attr,
+ NULL,
+};
+
+static const struct attribute_group bootstage_attr_group = {
+ .attrs = bootstage_attrs,
+};
+
+static int bootstage_parse(struct device *dev, struct bootstage_drvdata *drvdata,
+ resource_size_t size)
+{
+ const char *str_ptr = (const char *)(drvdata->records + drvdata->hdr->count);
+ const resource_size_t calc_size = (resource_size_t)((void *)str_ptr - (void *)drvdata->hdr);
+ struct bootstage_record *rec;
+ u32 r;
+
+ // Sanity checks on bootstage header
+ if (drvdata->hdr->magic != BOOTSTAGE_MAGIC) {
+ dev_err(dev, "wrong bootstage magic number %08Xh\n", drvdata->hdr->magic);
+ return -EINVAL;
+ } else if (drvdata->hdr->version > BOOTSTAGE_MAX_VERSION) {
+ dev_err(dev, "bootstage version %u not supported\n", drvdata->hdr->version);
+ return -EOPNOTSUPP;
+ } else if (drvdata->hdr->size == 0) {
+ dev_err(dev, "invalid bootstage stash (declared size is zero)\n");
+ return -EINVAL;
+ } else if (drvdata->hdr->size > size) {
+ dev_err(dev, "invalid declared stash size %u (expected: <= %llu)\n",
+ drvdata->hdr->size, size);
+ return -EINVAL;
+ } else if (calc_size > size) {
+ dev_err(dev, "invalid calculated stash size %llu (expected: <= %llu)\n",
+ calc_size, size);
+ return -EINVAL;
+ } else if (drvdata->hdr->count == 0) {
+ dev_info(dev, "bootstage stash has no records\n");
+ return 0;
+ }
+
+ // Set start time to invalid
+ drvdata->start_time_us = 0xFFFFFFFF;
+
+ // Associate names to records, which are placed at the end of the record area
+ for (r = 0, rec = drvdata->records; r < drvdata->hdr->count; r++, rec++) {
+ // Save minimum time, will be used as bootloader enter time
+ if (rec->start_us < drvdata->start_time_us)
+ drvdata->start_time_us = rec->time_us;
+
+ // Save maximum time, will be used as bootloader exit time
+ if (rec->time_us > drvdata->end_time_us)
+ drvdata->end_time_us = rec->time_us;
+
+ if (str_ptr > ((const char *)drvdata->hdr + size)) {
+ dev_err(dev, "name for record %u is corrupted\n", r);
+ return -ENODATA;
+ }
+
+ rec->name = str_ptr;
+ str_ptr += strlen(rec->name) + 1;
+ }
+
+ return 0;
+}
+
+static int bootstage_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct reserved_mem *rmem;
+ struct bootstage_drvdata *drvdata;
+ int ret;
+
+ rmem = of_reserved_mem_lookup(dev->of_node);
+ if (!rmem) {
+ dev_err(dev, "failed to lookup reserved memory\n");
+ return -EINVAL;
+ }
+
+ if (!rmem->size || (rmem->size > ULONG_MAX) ||
+ (rmem->size < sizeof(struct bootstage_hdr))) {
+ dev_err(dev, "invalid memory region size\n");
+ return -EINVAL;
+ }
+
+ if (!PAGE_ALIGNED(rmem->base) || !PAGE_ALIGNED(rmem->size)) {
+ dev_err(dev, "memory region must be page-aligned\n");
+ return -EINVAL;
+ }
+
+ drvdata = devm_kmalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, drvdata);
+
+ drvdata->hdr = devm_memremap(dev, rmem->base, rmem->size, MEMREMAP_WB);
+ if (IS_ERR(drvdata->hdr)) {
+ dev_err(dev, "failed to remap bootstage region\n");
+ return PTR_ERR(drvdata->hdr);
+ }
+
+ drvdata->records =
+ (struct bootstage_record *)((void *)drvdata->hdr + sizeof(struct bootstage_hdr));
+
+ ret = bootstage_parse(dev, drvdata, rmem->size);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &bootstage_attr_group);
+ if (ret) {
+ dev_err(dev, "failed to create sysfs group\n");
+ return ret;
+ }
+
+ bootstage_debugfs_init(dev, drvdata);
+
+ return 0;
+}
+
+static void bootstage_remove(struct platform_device *pdev)
+{
+ struct bootstage_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ bootstage_debugfs_exit(&pdev->dev, drvdata);
+ sysfs_remove_group(&pdev->dev.kobj, &bootstage_attr_group);
+}
+
+static const struct of_device_id bootstage_of_match[] = {
+ { .compatible = "bootstage" },
+ {},
+};
+
+static struct platform_driver bootstage_driver = {
+ .probe = bootstage_probe,
+ .remove = bootstage_remove,
+ .driver = {
+ .name = "bootstage",
+ .of_match_table = bootstage_of_match,
+ },
+};
+
+static int __init bootstage_init(void)
+{
+ bootstage_debugfs_dir = debugfs_create_dir(bootstage_driver.driver.name, NULL);
+ return platform_driver_register(&bootstage_driver);
+}
+arch_initcall(bootstage_init);
+
+static void __exit bootstage_exit(void)
+{
+ debugfs_remove_recursive(bootstage_debugfs_dir);
+ platform_driver_unregister(&bootstage_driver);
+}
+module_exit(bootstage_exit)
+
+MODULE_DESCRIPTION("Driver for Bootstage stash.");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Francesco Valla <francesco@valla.it>");
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index f77cb19973a5..e19b04733584 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -496,6 +496,7 @@ static const struct of_device_id reserved_mem_matches[] = {
{ .compatible = "ramoops" },
{ .compatible = "nvmem-rmem" },
{ .compatible = "google,open-dice" },
+ { .compatible = "bootstage" },
{}
};
--
2.49.0
^ permalink raw reply related
* Reminder of Boot-Time SIG meeting - May 27
From: Bird, Tim @ 2025-05-22 23:33 UTC (permalink / raw)
To: Linux Embedded
Hey Linux Boot-Time SIG interested parties (and other interested Linux kernel developers),
Here is the information for the next Linux Boot-Time SIG conference call.
The meeting will be held via the Jitsi online meeting platform.
To Join the meeting via web, click on:
https://meet.jit.si/LinuxBootTimeSIG
----
Our next meeting is Tuesday, May 27, at 9:00 am Mountain Daylight Time.
See this link for other time zones:
https://www.timeanddate.com/worldclock/meetingdetails.html?year=2025&month=05&day=27&hour=15&min=0&sec=0&p1=220&p2=137&p3=195&p4=771
(That makes it 8:00 am Pacific, 15:00 UTC, 17:00 CET, and 20:30 IST)
I'm planning on 1 hour for this meeting.
The agenda for the meeting (and where we'll keep the minutes) is here:
https://docs.google.com/document/d/1XAufoTT6VVJOTMzKMoz8SyOss-JA9H4J1_yVXQq5mN0/edit?usp=sharing
The agenda for the May 27 meeting will be available in the above document before the call.
This is what I've got so far:
- Round-table of on-going work
- Report on Unified Boot Log discussion
- boot time regression test
- Tim currently working on:
- finding common printks (to define kernel boot markers
with adding additional code upstream)
- reference value file meta-data matching
- Status of patches being considered for upstream
- print initlevel
- show_delta 2.0
- deferred initcalls
- anything outstanding for deferred memory init?
- documentation or tuning guide?
- Things to follow up on:
- boot caching (The Good Penguin work)
- boot-time data wiki
- elinux wiki Boot-Time pages
- https://elinux.org/Boot_Time_Project_Ideas
If you have items you'd like to cover, please e-mail me or put them in the document.
Thanks,
-- Tim
^ permalink raw reply
* [RFC PATCH 0/1] Add driver for bootstage stash
From: Francesco Valla @ 2025-05-22 22:42 UTC (permalink / raw)
To: linux-embedded
Hello,
after the discussion on the "Unified Boot Log" topic during the latest
Boot Time SIG special meeting [1], I tried to mock up a driver that
reads a bootstage stash saved by the U-Boot bootloader in a given memory
area and exposes the data in a user- and machine- friendly through both
sysfs and debugfs attributes. Details on the interfaces, as well as
example output for the debugfs interfaces, can be found on the
documentation that is part of the patchset.
To use this driver, a memory area shall be reserved inside the Linux
kernel devicetree as follows (possibly changing the address and the size
of the memory area):
bootstage@a4300000 {
compatible = "bootstage";
reg = <0 0xa4300000 0 0x1000>;
no-map;
};
At U-Boot side, following configuration shall then be set:
CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_STASH_ADDR=0xa4300000
CONFIG_BOOTSTAGE_STASH_SIZE=0x1000
Once booted, the bootstage data can will be found at:
- /sys/devices/platform/a4300000.bootstage/
- /sys/kernel/debug/bootstage/a4300000.bootstage/
The device name is purposely part of the sysfs and debugfs paths to
support multiple bootstage areas, as this _might_ then be used for
multiple bootstage sources, e.g. bootloaders running on different
cores inside a SoC with different architectures.
Note that this is not really meant to be integrated as-is, not only
because it's a single patch including code, documentation and devicetree
bindings, but also because the bootstage stash format itself may need to
be touched up a bit. In particular, fixed data type should probably be
evaluated for the bootstage record, in order to increase compatibility
with different data sources.
Comments are of course welcome.
Regards,
Francesco
[1] https://lore.kernel.org/linux-embedded/MW5PR13MB5632B8FA3279D77F2F9217BBFD9CA@MW5PR13MB5632.namprd13.prod.outlook.com/
Francesco Valla (1):
drivers: misc: add driver for bootstage stash
.../bindings/reserved-memory/bootstage.yaml | 44 +++
Documentation/misc-devices/bootstage.rst | 53 ++++
Documentation/misc-devices/index.rst | 1 +
MAINTAINERS | 7 +
drivers/misc/Kconfig | 10 +
drivers/misc/Makefile | 1 +
drivers/misc/bootstage.c | 292 ++++++++++++++++++
drivers/of/platform.c | 1 +
8 files changed, 409 insertions(+)
create mode 100644 Documentation/devicetree/bindings/reserved-memory/bootstage.yaml
create mode 100644 Documentation/misc-devices/bootstage.rst
create mode 100644 drivers/misc/bootstage.c
--
2.49.0
^ permalink raw reply
* Re: [PATCH 1/1] drivers: misc: add driver for bootstage stash
From: Krzysztof Kozlowski @ 2025-05-23 6:29 UTC (permalink / raw)
To: Francesco Valla, linux-embedded
In-Reply-To: <20250522224223.358881-3-francesco@valla.it>
On 23/05/2025 00:42, Francesco Valla wrote:
> Add support for bootstage stash areas containing boot time data
> created by some bootloader (e.g. U-Boot). The driver provides generic
> time information through sysfs and platform-specific one through
> debugfs.
>
> Signed-off-by: Francesco Valla <francesco@valla.it>
Your Cc list is so incomplete I really do not understand which project
you target and this popped up in my lei filters. If this is not for
Linux kernel, please ignore the rest.
If this is for Linux kernel then:
Please run scripts/checkpatch.pl on the patches and fix reported
warnings. After that, run also 'scripts/checkpatch.pl --strict' on the
patches and (probably) fix more warnings. Some warnings can be ignored,
especially from --strict run, but the code here looks like it needs a
fix. Feel free to get in touch if the warning is not clear.
Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC. It might happen, that command when run on an older
kernel, gives you outdated entries. Therefore please be sure you base
your patches on recent Linux kernel.
Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about `b4 prep --auto-to-cc` if you added new
patches to the patchset.
You missed at least devicetree list (maybe more), so this won't be
tested by automated tooling. Performing review on untested code might be
a waste of time.
Please kindly resend and include all necessary To/Cc entries.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [RFC PATCH 0/1] Add driver for bootstage stash
From: Geert Uytterhoeven @ 2025-05-23 7:04 UTC (permalink / raw)
To: Francesco Valla; +Cc: linux-embedded
In-Reply-To: <20250522224223.358881-2-francesco@valla.it>
Hi Francesco,
On Fri, 23 May 2025 at 02:25, Francesco Valla <francesco@valla.it> wrote:
> after the discussion on the "Unified Boot Log" topic during the latest
> Boot Time SIG special meeting [1], I tried to mock up a driver that
> reads a bootstage stash saved by the U-Boot bootloader in a given memory
> area and exposes the data in a user- and machine- friendly through both
> sysfs and debugfs attributes. Details on the interfaces, as well as
> example output for the debugfs interfaces, can be found on the
> documentation that is part of the patchset.
Thanks for your work!
> To use this driver, a memory area shall be reserved inside the Linux
> kernel devicetree as follows (possibly changing the address and the size
> of the memory area):
>
> bootstage@a4300000 {
> compatible = "bootstage";
> reg = <0 0xa4300000 0 0x1000>;
> no-map;
> };
>
> At U-Boot side, following configuration shall then be set:
>
> CONFIG_BOOTSTAGE=y
> CONFIG_BOOTSTAGE_STASH_ADDR=0xa4300000
> CONFIG_BOOTSTAGE_STASH_SIZE=0x1000
I think this can be simplified further, using either of these two options:
1. If the bootstage@a4300000 node would already be present in the
DTB used by U-Boot, the two CONFIG_BOOTSTAGE_STASH_*
options would no longer be needed.
2. U-Boot could add the bootstage@a4300000 to the DTB that is
passed to the kernel, just like it already adds/updates the memory
nodes.
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
^ permalink raw reply
* Re: [RFC PATCH 0/1] Add driver for bootstage stash
From: Federico Giovanardi @ 2025-05-23 7:34 UTC (permalink / raw)
To: linux-embedded
In-Reply-To: <PA4PR08MB604681FF6392B25A19926A11ED98A@PA4PR08MB6046.eurprd08.prod.outlook.com>
Hello,
The note about the data format also was my initial thought, by just
copying a C structure we might have issues as soon one party changes it,
and they might not be perfectly aligned.
To avoid inventing yet-another-data-format I've used msgpack in the past
for that (the format
https://github.com/msgpack/msgpack/blob/master/spec.md, not the library
); because the specs are so simple they can be implemented in a few
lines, and it's something with a reference. But I don't have a lot of
experience in upstreaming stuff on the kernel, so I don't know if it
might cause someone to don't be happy. Anyway, I can contribute the
implementation if needed.
Something as simple as an array of fixarray will give extensibility with
only a few bytes of overhead.
Which gets encoded as:
0xdc # lenght 16 bit << array header
# 0xB << 4 | ( array_size & 0xF) << fixarray header ( 3 elements,
simplest case)
# 0xce # time_us
# 0xce # start_us
# 0xc << 4 | strlen(name) # name
/*no flags, no id*/
# 0xB << 4 | ( array_size & 0xF) << fixarray header ( 5 elements
bigger case)
# 0xce # time_us
# 0xce # start_us
# 0xc << 4 | strlen(name) # name
# 0xcc # flags
# 0xcc # id
.. repeat ...
Since the goal is to use that in many different contexts, defining the
fields that we need early is important.
Bye
Federico
> -------------------------
>
> Da: Francesco Valla <francesco@valla.it>
> Inviato: venerdì 23 maggio 2025 00:42
> A: linux-embedded@vger.kernel.org <linux-embedded@vger.kernel.org>
> Oggetto: [RFC PATCH 0/1] Add driver for bootstage stash
>
> Questo messaggio proviene da un mittente esterno: fai attenzione ad
> allegati e link.
>
> Hello,
>
> after the discussion on the "Unified Boot Log" topic during the latest
> Boot Time SIG special meeting [1], I tried to mock up a driver that
> reads a bootstage stash saved by the U-Boot bootloader in a given
> memory
> area and exposes the data in a user- and machine- friendly through
> both
> sysfs and debugfs attributes. Details on the interfaces, as well as
> example output for the debugfs interfaces, can be found on the
> documentation that is part of the patchset.
>
> To use this driver, a memory area shall be reserved inside the Linux
> kernel devicetree as follows (possibly changing the address and the
> size
> of the memory area):
>
> bootstage@a4300000 {
> compatible = "bootstage";
> reg = <0 0xa4300000 0 0x1000>;
> no-map;
> };
>
> At U-Boot side, following configuration shall then be set:
>
> CONFIG_BOOTSTAGE=y
> CONFIG_BOOTSTAGE_STASH_ADDR=0xa4300000
> CONFIG_BOOTSTAGE_STASH_SIZE=0x1000
>
> Once booted, the bootstage data can will be found at:
>
> - /sys/devices/platform/a4300000.bootstage/
> - /sys/kernel/debug/bootstage/a4300000.bootstage/
>
> The device name is purposely part of the sysfs and debugfs paths to
> support multiple bootstage areas, as this _might_ then be used for
> multiple bootstage sources, e.g. bootloaders running on different
> cores inside a SoC with different architectures.
>
> Note that this is not really meant to be integrated as-is, not only
> because it's a single patch including code, documentation and
> devicetree
> bindings, but also because the bootstage stash format itself may need
> to
> be touched up a bit. In particular, fixed data type should probably be
> evaluated for the bootstage record, in order to increase compatibility
> with different data sources.
>
> Comments are of course welcome.
>
> Regards,
>
> Francesco
>
> [1]
> https://eur02.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Flinux-embedded%2FMW5PR13MB5632B8FA3279D77F2F9217BBFD9CA%40MW5PR13MB5632.namprd13.prod.outlook.com%2F&data=05%7C02%7Cfederico.giovanardi%40cnh.com%7C68aacb29d80340fc5d3208dd99904415%7C79310fb0d39b486bb77b25f3e0c82a0e%7C0%7C0%7C638835567100175385%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=Hrd3rjtJ7sLciUzkFymL7y2agCAMZSAKKF7evt20LQU%3D&reserved=0
> [1]
>
> Francesco Valla (1):
> drivers: misc: add driver for bootstage stash
>
> .../bindings/reserved-memory/bootstage.yaml | 44 +++
> Documentation/misc-devices/bootstage.rst | 53 ++++
> Documentation/misc-devices/index.rst | 1 +
> MAINTAINERS | 7 +
> drivers/misc/Kconfig | 10 +
> drivers/misc/Makefile | 1 +
> drivers/misc/bootstage.c | 292
> ++++++++++++++++++
> drivers/of/platform.c | 1 +
> 8 files changed, 409 insertions(+)
> create mode 100644
> Documentation/devicetree/bindings/reserved-memory/bootstage.yaml
> create mode 100644 Documentation/misc-devices/bootstage.rst
> create mode 100644 drivers/misc/bootstage.c
>
> --
> 2.49.0
>
>
>
> Links:
> ------
> [1]
> https://lore.kernel.org/linux-embedded/MW5PR13MB5632B8FA3279D77F2F9217BBFD9CA@MW5PR13MB5632.namprd13.prod.outlook.com/
^ permalink raw reply
* Deferred probe times
From: Federico Giovanardi @ 2025-05-23 7:56 UTC (permalink / raw)
To: Linux Embedded
[-- Attachment #1: Type: text/plain, Size: 328 bytes --]
Hello,
I was poking around the boot data database while I noticed that the
deferred_probe initicalls are considered as a giant block;
There is a patch that looks never went upstream to measure them:
https://lkml.iu.edu/1707.3/02349.html
And another one from me to print the result in the .svg.
Have a nice day
Federico
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: update_bootgraph_deferred_init.patch --]
[-- Type: text/x-diff; name=update_bootgraph_deferred_init.patch, Size: 961 bytes --]
commit c8d97bad2987b33b2ce804805071218fd7f68bbd
Author: Federico Giovanardi <federico.giovanardi@cnhind.com>
Date: Fri Oct 4 14:13:30 2024 +0200
Update bootgraph to handle deferred initcalls
diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl
index 79c903292ae8..8057d9f474df 100755
--- a/scripts/bootgraph.pl
+++ b/scripts/bootgraph.pl
@@ -67,7 +67,8 @@ my $cyheader = 0;
while (<>) {
my $line = $_;
- if ($line =~ /([0-9\.]+)\] calling ([a-zA-Z0-9\_\.]+)\+/) {
+ if ($line =~ /([0-9\.]+)\] calling ([a-zA-Z0-9\_\.]+)\+/ or
+ $line =~ /([0-9\.]+)\] deferred probe ([a-zA-Z0-9\_\.]+) @/) {
my $func = $2;
if ($done == 0) {
$start{$func} = $1;
@@ -109,6 +110,12 @@ while (<>) {
$maxtime = $1;
}
}
+ if ($line =~ /([0-9\.]+)\] deferred probe ([a-zA-Z0-9\_\.]+).*returned/) {
+ if ($done == 0) {
+ $end{$2} = $1;
+ $maxtime = $1;
+ }
+ }
if ($line =~ /([0-9\.]+)\] async_continuing @ ([0-9]+)/) {
my $pid = $2;
^ permalink raw reply related
* Re: [PATCH 1/1] drivers: misc: add driver for bootstage stash
From: Rob Landley @ 2025-05-23 19:34 UTC (permalink / raw)
To: Krzysztof Kozlowski, Francesco Valla, linux-embedded
In-Reply-To: <f1673d75-e951-4cdd-8414-f1e9d7d6e6aa@kernel.org>
On 5/23/25 01:29, Krzysztof Kozlowski wrote:
> On 23/05/2025 00:42, Francesco Valla wrote:
>> Add support for bootstage stash areas containing boot time data
>> created by some bootloader (e.g. U-Boot). The driver provides generic
>> time information through sysfs and platform-specific one through
>> debugfs.
>>
>> Signed-off-by: Francesco Valla <francesco@valla.it>
>
> Your Cc list is so incomplete I really do not understand which project
> you target and this popped up in my lei filters. If this is not for
> Linux kernel, please ignore the rest.
The discussion is happening on the linux-embedded list you cc'd in your
reply.
https://www.spinics.net/lists/linux-embedded/msg04429.html
https://www.spinics.net/lists/linux-embedded/msg04435.html
Rob
^ permalink raw reply
* Re: [RFC PATCH 0/1] Add driver for bootstage stash
From: Rob Landley @ 2025-05-23 19:43 UTC (permalink / raw)
To: linux-embedded
In-Reply-To: <473a062e4f939bc58a5c0e636569b826@giovanardi.dev>
On 5/23/25 02:34, Federico Giovanardi wrote:
> Hello,
>
> The note about the data format also was my initial thought, by just
> copying a C structure we might have issues as soon one party changes it,
> and they might not be perfectly aligned.
>
> To avoid inventing yet-another-data-format I've used msgpack in the past
> for that (the format https://github.com/msgpack/msgpack/blob/master/
> spec.md, not the library ); because the specs are so simple they can be
> implemented in a few lines, and it's something with a reference. But I
> don't have a lot of experience in upstreaming stuff on the kernel, so I
> don't know if it might cause someone to don't be happy. Anyway, I can
> contribute the implementation if needed.
I note that if it has an external build-time dependency, I will not only
never enable it, I will go to great lengths to _disable_ it. I maintain
a patch to build x86-64 without that ridiculous fourth ELF library, for
example:
https://landley.net/bin/mkroot/latest/linux-patches/0005-x86-64-elfcrap.patch
The traditional approach to exporting data was to have synthetic
filesystems like /sys and /blah produce human readable ascii output that
could be easily parsed, because unix is textual.
Ala "Write programs to handle text streams, because that is a universal
interface." from https://en.wikipedia.org/wiki/Unix_philosophy (quoting
Peter Salus's "a quarter century of unix" in 1994 which was itself
quoting... I think Doug McIlroy?
Rob
P.S. The whole digression into Plan 9 muddied the waters, not because
they backed off on it but because the original authors of unix doubled
down on their sequel project, and then unix copied things like the
concept of synthetic filesystems from that. The difference is Unix was
published freely in 1974 and Plan 9 was closed source proprietary until
2000, so the first changed the world and the second is a footnote must
people weren't aware existed until it had basically died, and then mined
it for ideas they could port to what they were using without ever
touching the incompatibly licensed code...
^ permalink raw reply
* Re: [RFC PATCH 0/1] Add driver for bootstage stash
From: Francesco Valla @ 2025-05-23 20:06 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-embedded
In-Reply-To: <CAMuHMdXqw9igYU-iPFbA-uP8-LrmZocUKT4k9cb8+py1gFp8tA@mail.gmail.com>
Hi Geert,
On Friday, 23 May 2025 at 09:04:48 Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> >
> > At U-Boot side, following configuration shall then be set:
> >
> > CONFIG_BOOTSTAGE=y
> > CONFIG_BOOTSTAGE_STASH_ADDR=0xa4300000
> > CONFIG_BOOTSTAGE_STASH_SIZE=0x1000
>
> I think this can be simplified further, using either of these two options:
> 1. If the bootstage@a4300000 node would already be present in the
> DTB used by U-Boot, the two CONFIG_BOOTSTAGE_STASH_*
> options would no longer be needed.
> 2. U-Boot could add the bootstage@a4300000 to the DTB that is
> passed to the kernel, just like it already adds/updates the memory
> nodes.
>
The second option is probably the best one, as it aligns with other
similar usecases (e.g.: OP-TEE node [1]). Once it has been determined that
this driver is the right approach, it should be pretty simple to do.
[1] https://elixir.bootlin.com/u-boot/v2025.04/source/lib/optee/optee.c#L112
> Gr{oetje,eeting}s,
>
> Geert
>
>
Regards,
Francesco
^ permalink raw reply
* Re: [PATCH 1/1] drivers: misc: add driver for bootstage stash
From: Francesco Valla @ 2025-05-23 19:43 UTC (permalink / raw)
To: linux-embedded, Krzysztof Kozlowski
In-Reply-To: <f1673d75-e951-4cdd-8414-f1e9d7d6e6aa@kernel.org>
Hello Krzysztof,
On Friday, 23 May 2025 at 08:29:28 Krzysztof Kozlowski <krzk@kernel.org> wrote:
> On 23/05/2025 00:42, Francesco Valla wrote:
> > Add support for bootstage stash areas containing boot time data
> > created by some bootloader (e.g. U-Boot). The driver provides generic
> > time information through sysfs and platform-specific one through
> > debugfs.
> >
> > Signed-off-by: Francesco Valla <francesco@valla.it>
>
> Your Cc list is so incomplete I really do not understand which project
> you target and this popped up in my lei filters. If this is not for
> Linux kernel, please ignore the rest.
>
Yes, target is the Linux kernel, the patch contains a mock-up driver
generated by a discussion [1] of the Boot Time SIG held on last Tuesday.
I should have marked it as proof-of-concept rather than RFC, probably.
> If this is for Linux kernel then:
>
> Please run scripts/checkpatch.pl on the patches and fix reported
> warnings. After that, run also 'scripts/checkpatch.pl --strict' on the
> patches and (probably) fix more warnings. Some warnings can be ignored,
> especially from --strict run, but the code here looks like it needs a
> fix. Feel free to get in touch if the warning is not clear.
>
The only warning, if we ignore three on unnecessary parentheses raised
by --strict, is the one about the DT bindings that need to be submitted
separately. That was expected and somewhat specified in the cover letter,
but I honestly did not think of the automated tooling.
>
> Please use scripts/get_maintainers.pl to get a list of necessary people
> and lists to CC. It might happen, that command when run on an older
> kernel, gives you outdated entries. Therefore please be sure you base
> your patches on recent Linux kernel.
>
> Tools like b4 or scripts/get_maintainer.pl provide you proper list of
> people, so fix your workflow. Tools might also fail if you work on some
> ancient tree (don't, instead use mainline) or work on fork of kernel
> (don't, instead use mainline). Just use b4 and everything should be
> fine, although remember about `b4 prep --auto-to-cc` if you added new
> patches to the patchset.
>
I used scripts/get_maintainer.pl in the past but I wasn't aware of this
use of b4. I'll check it out.
> You missed at least devicetree list (maybe more), so this won't be
> tested by automated tooling. Performing review on untested code might be
> a waste of time.
>
> Please kindly resend and include all necessary To/Cc entries.
>
I did not want to unnecessary bother people that might not be interested,
as the current form is not intended for mainline. I'll however be more
scrupulous in the future.
>
> Best regards,
> Krzysztof
>
>
Thank you for the guidance!
Regards,
Francesco
[1] https://docs.google.com/document/d/1XAufoTT6VVJOTMzKMoz8SyOss-JA9H4J1_yVXQq5mN0/edit?tab=t.0
^ permalink raw reply
* Re: [RFC PATCH 0/1] Add driver for bootstage stash
From: Francesco Valla @ 2025-05-23 20:11 UTC (permalink / raw)
To: linux-embedded, Federico Giovanardi
In-Reply-To: <473a062e4f939bc58a5c0e636569b826@giovanardi.dev>
Hi Federico,
On Friday, 23 May 2025 at 09:34:09 Federico Giovanardi <fede.dev@giovanardi.dev> wrote:
> Hello,
>
> The note about the data format also was my initial thought, by just
> copying a C structure we might have issues as soon one party changes it,
> and they might not be perfectly aligned.
>
Definitely - before a proper implementation, a formal specification with
a versioning should probably be defined.
> To avoid inventing yet-another-data-format I've used msgpack in the past
> for that (the format
> https://github.com/msgpack/msgpack/blob/master/spec.md, not the library
> ); because the specs are so simple they can be implemented in a few
> lines, and it's something with a reference. But I don't have a lot of
> experience in upstreaming stuff on the kernel, so I don't know if it
> might cause someone to don't be happy. Anyway, I can contribute the
> implementation if needed.
>
I'd avoid a serialization technology here, as it would be another
(somewhat costly) step before booting, while re-using the memory area
that the bootloader itself uses as stash is basically free.
Regards,
Francesco
^ permalink raw reply
* RE: [PATCH 1/1] drivers: misc: add driver for bootstage stash
From: Bird, Tim @ 2025-05-23 23:43 UTC (permalink / raw)
To: Francesco Valla, linux-embedded@vger.kernel.org
In-Reply-To: <20250522224223.358881-3-francesco@valla.it>
Francesco,
Thanks for this prototype!!
> -----Original Message-----
> From: Francesco Valla <francesco@valla.it>
> Add support for bootstage stash areas containing boot time data
> created by some bootloader (e.g. U-Boot). The driver provides generic
> time information through sysfs and platform-specific one through
> debugfs.
>
> Signed-off-by: Francesco Valla <francesco@valla.it>
> ---
> .../bindings/reserved-memory/bootstage.yaml | 44 +++
> Documentation/misc-devices/bootstage.rst | 53 ++++
> Documentation/misc-devices/index.rst | 1 +
> MAINTAINERS | 7 +
> drivers/misc/Kconfig | 10 +
> drivers/misc/Makefile | 1 +
> drivers/misc/bootstage.c | 292 ++++++++++++++++++
> drivers/of/platform.c | 1 +
> 8 files changed, 409 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/reserved-memory/bootstage.yaml
> create mode 100644 Documentation/misc-devices/bootstage.rst
> create mode 100644 drivers/misc/bootstage.c
>
> diff --git a/Documentation/devicetree/bindings/reserved-memory/bootstage.yaml b/Documentation/devicetree/bindings/reserved-
> memory/bootstage.yaml
> new file mode 100644
> index 000000000000..e71d85c5c2ce
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reserved-memory/bootstage.yaml
> @@ -0,0 +1,44 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/reserved-memory/bootstage.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Bootstage stash
> +
> +description: |
> + This binding represents a reserved memory region containing bootstage stash
> + data generated by a previous bootloader stage.
> +
> +maintainers:
> + - Francesco Valla <francesco@valla.it>
> +
> +allOf:
> + - $ref: reserved-memory.yaml
> +
> +properties:
> + compatible:
> + const: bootstage
> +
> + reg:
> + description: page-aligned region of memory containing bootstage stash data
> +
> +required:
> + - compatible
> + - reg
> + - no-map
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + reserved-memory {
> + #address-cells = <2>;
> + #size-cells = <1>;
> +
> + bootstage: bootstage@12340000 {
> + compatible = "bootstage";
> + reg = <0x00 0x12340000 0x2000>;
> + no-map;
> + };
> + };
> diff --git a/Documentation/misc-devices/bootstage.rst b/Documentation/misc-devices/bootstage.rst
> new file mode 100644
> index 000000000000..2e1bbd31aab8
> --- /dev/null
> +++ b/Documentation/misc-devices/bootstage.rst
> @@ -0,0 +1,53 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +================
> +Bootstage driver
> +================
> +
> +The bootstage driver exports interfaces to read from a bootstage stash area
> +saved by a bootloader (e.g.: U-Boot) that ran before the Linux kernel.
> +
> +Two kind of interfaces are exported:
> +
> +- a sysfs interface for bootloader- and platform-agnostic data
> +- a debugfs interface for bootloader- and platform-specific data
> +
> +
> +The sysfs interface
> +-------------------
> +
> +Following sysfs attributes can be found at /sys/devices/platform/<device-name>/:
> +
> +- start_time_us: bootloader start time in microseconds
> +- end_time_us: bootloader end time in microseconds
> +
> +
> +The debugfs interface
> +---------------------
> +
> +Following debugfs interfaces can be found at
> +/sys/kernel/debug/bootstage/<device-name>/:
> +
> +- stages: details on staged bootloader stages, with start time and duration.
> + Example output::
> +
> + Mark (us) Elapsed (us) Stage
> + 0 0 reset
> + 183689 183689 SPL
> + 489247 305558 end phase
> + 506987 17740 board_init_f
> + 1257880 750893 board_init_r
> + 1622303 364423 eth_common_init
> + 1888033 265730 eth_initialize
> + 1893077 5044 main_loop
> + 4204282 2311205 cli_loop
> +
> +- accumulated_time: time accumulated during certain bootloader stages.
> + Example output::
> +
> + Time (us) Stage
> + 4902 dm_spl
> + 322719 dm_f
> + 9527 dm_r
> +
> +The number and type of staged stages are bootloader- and platform-specific.
I think it would be good to indicate in this document the required U-Boot CONFIG
settings for bootstage to be enabled. We don't need to replicate detailed U-Boot
documentation, but maybe just refer to the required configs. (e.g. CONFIG_BOOTSTAGE,
CONFIG_BOOTSTAGE_STASH, etc.)
Note: I looked in the U-boot documentation for documentation about Bootstage,
and I couldn't find much. There might be an opportunity to add some documentation
there as well.
> diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst
> index 8c5b226d8313..c5ebb3d44505 100644
> --- a/Documentation/misc-devices/index.rst
> +++ b/Documentation/misc-devices/index.rst
> @@ -28,3 +28,4 @@ fit into other categories.
> tps6594-pfsm
> uacce
> xilinx_sdfec
> + bootstage
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f21f1dabb5fe..0bdecd07023a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4203,6 +4203,13 @@ F: Documentation/ABI/stable/sysfs-class-bluetooth
> F: include/net/bluetooth/
> F: net/bluetooth/
>
> +BOOTSTAGE DRIVER
> +M: Francesco Valla <francesco@valla.it>
> +L: linux-embedded@vger.kernel.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/reserved-memory/bootstage.yaml
> +F: drivers/misc/bootstage.c
> +
> BONDING DRIVER
> M: Jay Vosburgh <jv@jvosburgh.net>
> L: netdev@vger.kernel.org
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index 6b37d61150ee..97cdfa241c0c 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -632,6 +632,16 @@ config MCHP_LAN966X_PCI
> - lan966x-miim (MDIO_MSCC_MIIM)
> - lan966x-switch (LAN966X_SWITCH)
>
> +config BOOTSTAGE
> + tristate "Bootstage stash support"
> + depends on OF_RESERVED_MEM
> + help
> + This enables the support for a bootstage stash.
> +
> + A bootstage stash can be created by some bootloaders (e.g.: U-Boot) to
> + store information on its boot timings. This driver provides access to
> + these information through sysfs and debugsfs interfaces.
> +
> source "drivers/misc/c2port/Kconfig"
> source "drivers/misc/eeprom/Kconfig"
> source "drivers/misc/cb710/Kconfig"
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index d6c917229c45..3562c1bf701f 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -74,3 +74,4 @@ lan966x-pci-objs := lan966x_pci.o
> lan966x-pci-objs += lan966x_pci.dtbo.o
> obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o
> obj-y += keba/
> +obj-$(CONFIG_BOOTSTAGE) += bootstage.o
> diff --git a/drivers/misc/bootstage.c b/drivers/misc/bootstage.c
> new file mode 100644
> index 000000000000..a106410a56ee
> --- /dev/null
> +++ b/drivers/misc/bootstage.c
> @@ -0,0 +1,292 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2025 - Francesco Valla <francesco@valla.it>
> + *
> + * Driver for bootstage stash.
> + *
> + * This driver exposes bootstage stash generated by bootloader and/or firmware
> + * stages that run before the Linux kernel.
> + *
> + */
> +
> +#include <linux/debugfs.h>
> +#include <linux/io.h>
> +#include <linux/mm.h>
> +#include <linux/module.h>
> +#include <linux/of_reserved_mem.h>
> +#include <linux/platform_device.h>
> +#include <linux/seq_file.h>
> +
> +#define BOOTSTAGE_MAGIC 0xb00757a3
> +#define BOOTSTAGE_MAX_VERSION 0
> +
> +enum bootstage_id {
> + BOOTSTAGE_ID_START = 0,
> +};
> +
> +enum bootstage_flags {
> + BOOTSTAGEF_ERROR = 1 << 0, /* Error record */
> + BOOTSTAGEF_ALLOC = 1 << 1, /* Allocate an id */
> +};
> +
> +struct bootstage_record {
> + ulong time_us;
> + u32 start_us;
> + const char *name;
> + int flags;
> + enum bootstage_id id;
> +};
> +
> +struct bootstage_hdr {
> + u32 version; /* Boostage stash version */
> + u32 count; /* Number of records */
> + u32 size; /* Total data size (non-zero if valid) */
> + u32 magic; /* Magic number */
> + u32 next_id; /* Next ID to use for bootstage */
> +};
> +
> +struct bootstage_drvdata {
> + struct bootstage_hdr *hdr;
> + struct bootstage_record *records;
> +
> + u32 start_time_us;
> + u32 end_time_us;
> +
> + struct dentry *debugfs_dir;
> +};
> +
> +static struct dentry *bootstage_debugfs_dir;
> +
> +static int stages_show(struct seq_file *m, void *d)
> +{
> + struct bootstage_drvdata *drvdata = m->private;
> + struct bootstage_hdr *hdr = drvdata->hdr;
> + struct bootstage_record *rec;
> + u32 prev = 0;
> + int i;
> +
> + seq_printf(m, "%13s %13s %s\n", "Mark (us)", "Elapsed (us)", "Stage");
> +
> + for (i = 0, rec = drvdata->records; i < hdr->count; i++, rec++) {
> + if ((rec->id && !rec->start_us) || (i == 0)) {
> + if (prev > rec->time_us)
> + prev = 0;
> + seq_printf(m, "%13lu %13lu %s\n", rec->time_us,
> + rec->time_us - prev, rec->name);
> + prev = rec->time_us;
> + }
> + }
> +
> + return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(stages);
> +
> +static int accumulated_time_show(struct seq_file *m, void *d)
> +{
> + struct bootstage_drvdata *drvdata = m->private;
> + struct bootstage_hdr *hdr = drvdata->hdr;
> + struct bootstage_record *rec;
> + int i;
> +
> + seq_printf(m, "%13s %s\n", "Time (us)", "Stage");
> +
> + for (i = 0, rec = drvdata->records; i < hdr->count; i++, rec++) {
> + if (rec->start_us)
> + seq_printf(m, "%13lu %s\n", rec->time_us, rec->name);
> + }
> +
> + return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(accumulated_time);
> +
> +static void bootstage_debugfs_init(struct device *dev, struct bootstage_drvdata *drvdata)
> +{
> + drvdata->debugfs_dir = debugfs_create_dir(dev_name(dev), bootstage_debugfs_dir);
> + if (IS_ERR(drvdata->debugfs_dir))
> + return;
> +
> + debugfs_create_file("stages", 0444, drvdata->debugfs_dir, drvdata, &stages_fops);
> + debugfs_create_file("accumulated_time", 0444, drvdata->debugfs_dir, drvdata,
> + &accumulated_time_fops);
> +}
> +
> +static void bootstage_debugfs_exit(struct device *dev, struct bootstage_drvdata *drvdata)
> +{
> + debugfs_remove_recursive(drvdata->debugfs_dir);
> +}
> +
> +static ssize_t start_time_us_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> + struct bootstage_drvdata *drvdata = dev_get_drvdata(dev);
> +
> + return sprintf(buf, "%u\n", drvdata->start_time_us);
> +}
> +static DEVICE_ATTR_RO(start_time_us);
> +
> +static ssize_t end_time_us_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> + struct bootstage_drvdata *drvdata = dev_get_drvdata(dev);
> +
> + return sprintf(buf, "%u\n", drvdata->end_time_us);
> +}
> +static DEVICE_ATTR_RO(end_time_us);
> +
> +static struct attribute *bootstage_attrs[] = {
> + &dev_attr_start_time_us.attr,
> + &dev_attr_end_time_us.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group bootstage_attr_group = {
> + .attrs = bootstage_attrs,
> +};
> +
> +static int bootstage_parse(struct device *dev, struct bootstage_drvdata *drvdata,
> + resource_size_t size)
> +{
> + const char *str_ptr = (const char *)(drvdata->records + drvdata->hdr->count);
> + const resource_size_t calc_size = (resource_size_t)((void *)str_ptr - (void *)drvdata->hdr);
> + struct bootstage_record *rec;
> + u32 r;
> +
> + // Sanity checks on bootstage header
> + if (drvdata->hdr->magic != BOOTSTAGE_MAGIC) {
> + dev_err(dev, "wrong bootstage magic number %08Xh\n", drvdata->hdr->magic);
> + return -EINVAL;
> + } else if (drvdata->hdr->version > BOOTSTAGE_MAX_VERSION) {
> + dev_err(dev, "bootstage version %u not supported\n", drvdata->hdr->version);
> + return -EOPNOTSUPP;
> + } else if (drvdata->hdr->size == 0) {
> + dev_err(dev, "invalid bootstage stash (declared size is zero)\n");
> + return -EINVAL;
> + } else if (drvdata->hdr->size > size) {
> + dev_err(dev, "invalid declared stash size %u (expected: <= %llu)\n",
> + drvdata->hdr->size, size);
> + return -EINVAL;
> + } else if (calc_size > size) {
> + dev_err(dev, "invalid calculated stash size %llu (expected: <= %llu)\n",
> + calc_size, size);
> + return -EINVAL;
> + } else if (drvdata->hdr->count == 0) {
> + dev_info(dev, "bootstage stash has no records\n");
> + return 0;
> + }
> +
> + // Set start time to invalid
> + drvdata->start_time_us = 0xFFFFFFFF;
> +
> + // Associate names to records, which are placed at the end of the record area
> + for (r = 0, rec = drvdata->records; r < drvdata->hdr->count; r++, rec++) {
> + // Save minimum time, will be used as bootloader enter time
> + if (rec->start_us < drvdata->start_time_us)
> + drvdata->start_time_us = rec->time_us;
> +
> + // Save maximum time, will be used as bootloader exit time
> + if (rec->time_us > drvdata->end_time_us)
> + drvdata->end_time_us = rec->time_us;
> +
> + if (str_ptr > ((const char *)drvdata->hdr + size)) {
> + dev_err(dev, "name for record %u is corrupted\n", r);
> + return -ENODATA;
> + }
> +
> + rec->name = str_ptr;
> + str_ptr += strlen(rec->name) + 1;
> + }
> +
> + return 0;
> +}
> +
> +static int bootstage_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct reserved_mem *rmem;
> + struct bootstage_drvdata *drvdata;
> + int ret;
> +
> + rmem = of_reserved_mem_lookup(dev->of_node);
> + if (!rmem) {
> + dev_err(dev, "failed to lookup reserved memory\n");
> + return -EINVAL;
> + }
> +
> + if (!rmem->size || (rmem->size > ULONG_MAX) ||
> + (rmem->size < sizeof(struct bootstage_hdr))) {
> + dev_err(dev, "invalid memory region size\n");
> + return -EINVAL;
> + }
> +
> + if (!PAGE_ALIGNED(rmem->base) || !PAGE_ALIGNED(rmem->size)) {
> + dev_err(dev, "memory region must be page-aligned\n");
> + return -EINVAL;
> + }
> +
> + drvdata = devm_kmalloc(dev, sizeof(*drvdata), GFP_KERNEL);
> + if (!drvdata)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, drvdata);
> +
> + drvdata->hdr = devm_memremap(dev, rmem->base, rmem->size, MEMREMAP_WB);
> + if (IS_ERR(drvdata->hdr)) {
> + dev_err(dev, "failed to remap bootstage region\n");
> + return PTR_ERR(drvdata->hdr);
> + }
> +
> + drvdata->records =
> + (struct bootstage_record *)((void *)drvdata->hdr + sizeof(struct bootstage_hdr));
> +
> + ret = bootstage_parse(dev, drvdata, rmem->size);
> + if (ret)
> + return ret;
> +
> + ret = sysfs_create_group(&pdev->dev.kobj, &bootstage_attr_group);
> + if (ret) {
> + dev_err(dev, "failed to create sysfs group\n");
> + return ret;
> + }
> +
> + bootstage_debugfs_init(dev, drvdata);
> +
> + return 0;
> +}
> +
> +static void bootstage_remove(struct platform_device *pdev)
> +{
> + struct bootstage_drvdata *drvdata = platform_get_drvdata(pdev);
> +
> + bootstage_debugfs_exit(&pdev->dev, drvdata);
> + sysfs_remove_group(&pdev->dev.kobj, &bootstage_attr_group);
> +}
> +
> +static const struct of_device_id bootstage_of_match[] = {
> + { .compatible = "bootstage" },
> + {},
> +};
> +
> +static struct platform_driver bootstage_driver = {
> + .probe = bootstage_probe,
> + .remove = bootstage_remove,
> + .driver = {
> + .name = "bootstage",
> + .of_match_table = bootstage_of_match,
> + },
> +};
> +
> +static int __init bootstage_init(void)
> +{
> + bootstage_debugfs_dir = debugfs_create_dir(bootstage_driver.driver.name, NULL);
> + return platform_driver_register(&bootstage_driver);
> +}
> +arch_initcall(bootstage_init);
> +
> +static void __exit bootstage_exit(void)
> +{
> + debugfs_remove_recursive(bootstage_debugfs_dir);
> + platform_driver_unregister(&bootstage_driver);
> +}
> +module_exit(bootstage_exit)
> +
> +MODULE_DESCRIPTION("Driver for Bootstage stash.");
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Francesco Valla <francesco@valla.it>");
OK - I have to admit now that I am confused. I haven't actually run this code,
or the U-boot code, but in examining the code at:
https://elixir.bootlin.com/u-boot/v2025.04/source/common/bootstage.c#L269
it seems like U-boot adds each individual record as a device tree property.
If that code (add_bootstage_devicetree) is putting info in the device tree as properties,
why is this kernel code reading bootstage stash entries as binary structured data
from the bootstage stash memory.
I see the 'bootstage_stash()' function in that same U-boot code, which presumably
is storing U-boot entries into the stash area, to be passed to the kernel.
Is there code in U-boot to add the stash element address property to the flattened
device tree that it passes to the kernel, or is this just manually configured
in 1) the U-boot config, and 2) the kernel device tree file?
Or maybe, the bootstage_stash() in the U-boot source code is there to copy
records from a secondary bootloader into the primary U-boot bootstage
stash? I can't figure out what's going on.
Are these two things related or completely separate? (That is, if the flattened
device tree has a bootstage node with sub-notes having 'name' and either 'accum' or 'mark'
records with a time_us element, is that completely different from the bootstage stash
memory area?
Just trying to get a handle on what's going on here and how the data is being transferred.
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index f77cb19973a5..e19b04733584 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -496,6 +496,7 @@ static const struct of_device_id reserved_mem_matches[] = {
> { .compatible = "ramoops" },
> { .compatible = "nvmem-rmem" },
> { .compatible = "google,open-dice" },
> + { .compatible = "bootstage" },
> {}
> };
>
> --
> 2.49.0
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox