[U-Boot] [WIP, PATCH] initcall: An outline of the idea

Graeme Russ graeme.russ at gmail.com
Sat Mar 3 13:46:01 CET 2012


Hi Laurence,

On 03/03/2012 10:47 PM, Laurence Withers wrote:
> Hi Graeme,
> 
> On Fri, Mar 02, 2012 at 10:05:12PM +1100, Graeme Russ wrote:
>> diff --git a/doc/README.INIT_FUNC b/doc/README.INIT_FUNC
>> new file mode 100644
>> index 0000000..b545390
>> --- /dev/null
>> +++ b/doc/README.INIT_FUNC
>> @@ -0,0 +1,31 @@
>> +The INIT_FUNC macro allows initialisation functions (i.e. functions which are
>> +executed before the main loop) to be easily added to the init sequence
>> +
>> +The format of the INIT_FUNC macro is:
>> +
>> +INIT_FUNC({function_name}, {init_class}, {prerequisite init_class(es)})
>> +
>> +{function_name} is the name of the init function to call. This function must
>> +have the following prototype:
>> +
>> +int foo(void);
>> +
>> +Each init function must return 0 to indicate success - any other return value
>> +indicates failure and the init sequence will stop
>> +
>> +{init_class} is a simple test string to describe the basic purpose of the init
>> +function. Multiple init functions may share the same init_class string
>> +
>> +{prerequisite init_class(es)} is a list of init_class strings (see above) which
>> +defines what init functions are executed before and after the given init
>> +function. Each prerequisite init_class is seperated by a space and preceeded by
>> +either:
>> + * - At least one function of this init class must exist (i.e. there must be at
>> +     least one INIT_FUNC entry with {init_class} set to the init class named
>> +     after the '*' - All init functions with an init class matching the class
>> +     named after the '*' will be executed before this function
>> + + - All init functions with an init class matching the class named after the
>> +     '+' will be executed before this function, but there does not need to be
>> +     any functions with the named init class in the init sequence
>> + - - This function will be called before any other functions with the init
>> +     class named after the '-'
> 
> What happens if there's a set of dependencies that cannot be resolved? From
> reading the above, it seems I can do something like this:

tools/mkinitseq would return an error - It would be akin to a compilation error

> INIT_FUNC(ifunc1, class1, *class2);
> INIT_FUNC(ifunc2, class2, *class1);

What you need to keep in mind is that currently the init sequences are
maintained as a fixed array of function pointers (except in one corner case
arch, but that can be fixed) so you could just name the classes 'class1',
'class2', 'class3' and build the existing init sequences as-is. But there
is no guarantee the order is the same for all the arches, hence the desire
to group like functions together.

The dependencies are not really that complicated, so I don't imagine there
will be much difficultly in getting the current sequences migrated.

It's when someone adds a board specific init function that things might get
interesting...


> It would also seem that if you want to change the prerequisites for a given
> init_class, you need to find every instance of INIT_FUNC for that init_class
> and change it.

Yes, but this would be rare - The idea of init class is to say, for
example, 'PCI must be initialised before Ethernet' - The chance of this
dependency rule changing is very low

> Perhaps there's a better way of solving this, but it maybe there should be a
> separate place which names the init classes and their prerequisites?

Some board, SoCs or arches _may_ need slightly different prerequisites -
For example, arch 'A' may need GPIO before PCI while arch 'B' may need PCI
before GPIO

> 
>> diff --git a/include/initcall.h b/include/initcall.h
>> new file mode 100644
>> index 0000000..a81cf21
>> --- /dev/null
>> +++ b/include/initcall.h
>> @@ -0,0 +1,19 @@
>> +#ifndef __INIT_CALL_H__
>> +#define __INIT_CALL_H__
>> +#include <linux/compiler.h>
>> +#define INIT_FUNC(fn, init_name, deps) \
>> +	static const char __init_func_ ## fn[] __used \
>> +	__attribute__((__section__(".initfuncs"))) = \
>> +	"(" #fn ":" #init_name ";" #deps ")\n";
>> +
>> +#define SKIP_INIT(init_name) \
>> +	static const char __skip_init_ ## req[] __used \
>> +	__attribute__((__section__(".initfuncs"))) = \
>> +	"{" #init_name "}\n";
>> +
>> +#define REPLACE_INIT(old_func, new_func) \
>> +	static const char __replace_init_ ## old_func[] __used \
>> +	__attribute__((__section__(".initfuncs"))) = \
>> +	"[" #old_func "," #new_func "]\n";
>> +
>> +#endif /* !__INIT_CALL_H__ */
> 
> What are SKIP_INIT() and REPLACE_INIT() used for?

Glad you asked :) - They are more advanced functions...

SKIP_INIT() drops all initialisation of a given init class - This allows a
board to completely override an init class normally defined by the arch,
SoC or CPU

REPLACE_INIT() replaces one init function with another - It is similar to
weak functions

> 
> Perhaps the macro could be expanded to include a prototype for the function,

How so - Can you provide a code example?

> so that gcc complains with a useful error message if there's a type mismatch.

The type mismatch will be flagged when the file generated by mkinitseq is
compiled - All functions are int foo(void)

> 
> Bye for now,

Thanks & Regards,

Graeme


More information about the U-Boot mailing list