[U-Boot] [RFC] New init sequence processing without init_sequence array

Graeme Russ graeme.russ at gmail.com
Tue Aug 23 01:20:44 CEST 2011


Hi Wolfgang,

On Tue, Aug 23, 2011 at 6:10 AM, Wolfgang Denk <wd at denx.de> wrote:
> Dear Graeme Russ,
>
> In message <1313587343-3693-1-git-send-email-graeme.russ at gmail.com> you wrote:
>> I have been thinking about the problem of the pesky init_sequence arrays
>> and the inevitable #ifdefs and empty stub functions that result so I
>> thought I'de have a crack at a more dynamic implementation. And like all
>> good programmers, I stole the solution ;). This implementation is based
>> on Linux's __initcall(fn) et. al. macros
>>
>> If this works cross-platform, we can finally move board_init_* into
>> /lib/ - Wouldn't that be nice
>>
>> Thoughts?
>
> My initial thoughts are these two:
>
> 1. I think we should change the code in a different order.  I would
>   prefer to first unify the init code across architectures (the big
>   ARM reorganization we just seem to have overcome was an important
>   prerequisite for this), before we start changing the init code.
>

I agree - I am currently auditing the init sequences and teasing out any
common ordering and identifying where arches call an otherwise common
init function out-of-order to the others. This is, generally speaking,
very ugly - There are:

 - Two archictectures that do not use the init loop
 - Two that do not relocate and therefore have a mix of (what other arches
   consider) _f and _r int functions in a single loop
 - Functions that could be made init functions after the init loop in
   board_init_r
 - Some arches have an equivalent init_f loop, others have an init_r loop
   x86 is the only one that does both _f anf _r init sequences as loops

I think, as a first step, all arches need to implement an init_f and
init_r loop and collapse board_init_f and board_init_r into trival
loop processing functions - Combine them into one function (which takes
a pointer to the relavent init_function array) and move it into
/lib/init.c - Easy ;)

> 2. One of the advantages of the current implementation is that there
>   is a central place in the code (well, at least per architecture,
>   untill we unify these as mentioned above) where you can see exactly
>   which steps get performed in which sequence.

This new method can have the same by putting all the INIT_FUNC()
in a single location, much like the existing array. I don't think this
is a good idea though. I prefer good clear documentation.

>   I understand (and appreciate) your intentions, does the initcall
>   concept not mean that we will have some sort of sequence numbers
>   distributed all over the code?  Maybe I'm mising something - but
>   does this not make it really difficult to actually see (from the
>   source code) what the exact init sequence is?

Well the bulk of the init sequence will be defined by init steps clearly
defined in include/init.h. Where there is as arch, SoC or board which
needs an init function called immediately after a particular point in the
standard sequence, then there will be:

	#define CUSTOM_INIT_STEP	STANDARD_INIT_STEP + 1

> 3. Hardware initialization in inherently very much hardware depen-
>   dent ;-)  We have some boards where PCI must be initialized early
>   because it is needed to access some other peripherals like memory.
>   And we have other boards where PCI can only be initialized late
>   because it depends on a lot of other functions that must be working
>   first.

Yes, I am seeing that in my audit

>   I explained this a number of times before: the current code was
>   designed to allow even for completely board specific init
>   sequences, by simply adding #define for the list of init functions
>   to the board config file - see for example here:
>
>   http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/33951/focus=36436
>
>   http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/72131/focus=72136

Yes, I saw some of the macro'd init functions in my audit, and I must say
that I am not a fan. If we continue down this path, we will have an init
sequence array made up of purely of macros and then it will be a PITA to
search throught the code resolving the macro for your particular arch /
Soc / board. Also, it does not allow the functions to be put in an
arbitrary order in a central location - Do do so will require a really bad
mess of #ifdef's - This will be a big barrier to centralising the whole
init sequence in say /lib/init.c as each arch will still need to put the
critical init function array in /arch/lib/board.c

>
>   If you look at the current code - heavily larded with #ifdefs of
>   all shapes and colors - I cannot see any good way to transform this
>   into an initcall (and thus sequence number based) implementation.
>   Do you have any specific ideas how to address this?

The _really_ nice thing about initcall is that if you take something like
PCI, you put the INIT_FUNC() in pci.c and it only gets included if you
define CONFIG_PCI - No #ifdefs. The problem, as you quite rightly point
out, is how to clearly define INIT_STEP_PCI. From what I am seeing, these
are mostly corner cases that can be clearly documented.

Now to answer some points in your other email:

> >  For a board to add an arbitrary initialisation function is trivial -
> >  simply add a INIT_FUNC() entry with an appropriate sequence number
>
> This is actually hte biffest voncern I have: I cannot imagine how you
> will try to figure out the exact init sequence when writing the code
> (or, even worse, when reading somebody else's code).

Good point - The init sequence audit I am doing now will help. It will
become a lot clearer when the init sequences are unified. For the rest,
good clear documentation will help, but I think we will only know how it
looks and feels when a complete patchs hits the list.

One nicity of putting INIT_FUNC() after a function body (or just before
it which is easier to see if the body is longer that a screen) is that
you can see immediately that the function is involved in the init
sequence - I kind of like that.

> >  I imagine the sequence numbers could be #defined, but I don't exactly
> >  now what the linker will do - I use leading zeros in the sequence numbers
> >  to ensure correct ordering.
>
> This is another concern: what exactly will the linker do, and
> different versions of linkers with differen options and/or levels of
> optimization?

I have another patch now that #define's the step numbers. As long as the
step numbers are 100-999 (or 1000-9999, 10000-99999 etc) then everything
works fine. The linker MUST support SORT_BY_NAME, KEEP and DISCARD - can
anyone think of a linker that does not? Optimization will only be an issue
if the linker disobeys SORT_BY_NAME, KEEP or DISCARD as part of the
optimisation (which I would think would be brain-dead as these directives
are clearly telling the linker to do something very particular)

OK, so what do I see as adventageous about using initcall versus current
implementation...

 - Any arch, SoC or board can cleanly inject an init function anywhere in
   the init sequence without touching a single line of code outside that
   arch/SoC/board. The current system requires a mod to /arch/lib/board.c
   with the potential addittion of ugly #ifdef's
 - The _f init function pointers are put in a section outside of the data
   copied to RAM during relocation, slightly reducing the RAM footprint
 - No more #ifdef in the init sequence array
 - sub-systems (PCI, IDE, PCMCIA, SCSI) define the init function in their
   respective .c files and it gets pulled in when the Makefile pulls in
   the .c file
 - It's more like Linux :)

And the bad...
 - Init sequence not clearly obvious in a single location
 - Maybe brain-dead linkers will do something wrong

And the neutral
 - Dealing with specific arch/Soc/board requiring an init function at a
   different sequence step than everything else

Some neat features that are trivial to implement with initcall and
difficult or ugly with init array:
 - The names of the function can be (conditionally by DEBUG) added and
   printed out as the init sequence is being run - Very nice for debugging
   the init sequence
 - Boot profiling - Store the step number and time to execute then after
   bootup completes, a simple 'show boot profile information' can print
   each function name and the time taken to execute

Honestly, after having a good play with this and fully converting x86 to
trivial board_init_f and board_init_r functions, I really like the initcall
method - It really does 'just work' like a dream :)

Regards,

Graeme


More information about the U-Boot mailing list