Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

init function invocation of drivers compiled into kernel

In Linux if device drivers are built as loadable kernel modules, then upon inserting the device driver kernel module, the kernel calls the init function of the device driver as pointed out by module_init() macro.

How does this work for device drivers that are statically compiled into the kernel ? How is their init function called ?

like image 839
Bandicoot Avatar asked Oct 12 '12 18:10

Bandicoot


2 Answers

The init routine of a built-in driver can still use the module_init() macro to declare that entry point. Or the driver can use device_initcall() when the driver would never be compiled as a loadable module. Or to move its initialization very early in the boot sequence, the driver could use subsys_initcall().

In include/linux/init.h the sequence for invoking these init routines is described as:

/* initcalls are now grouped by functionality into separate 
 * subsections. Ordering inside the subsections is determined
 * by link order. 
 * For backwards compatibility, initcall() puts the call in 
 * the device init subsection.
 *
 * The `id' arg to __define_initcall() is needed so that multiple initcalls
 * can point at the same handler without causing duplicate-symbol build errors.
 */

I assume that these subsections for device drivers correspond to the subdirectories within the drivers directory of the Linux kernel source tree, and that the link order is recorded in the built-in.o file of each subdirectory in drivers. So during kernel boot the init routine of each built-in driver is eventually executed by do_initcalls() in init/main.c.

The init routine of the device driver is responsible for probing the system to verify that the HW device actually exists. The driver should not allocate any resources or register any devices when the probe fails.

UPDATE:
Passing the option "initcall_debug" on the kernel command line will cause timing information to be printed to the console for each initcall. initcalls are used to initialize statically linked kernel drivers and subsystems and contribute a significant amount of time to the Linux boot process. The output looks like:

calling  tty_class_init+0x0/0x44 @ 1
initcall tty_class_init+0x0/0x44 returned 0 after 9765 usecs
calling  spi_init+0x0/0x90 @ 1
initcall spi_init+0x0/0x90 returned 0 after 9765 usecs

Reference: http://elinux.org/Initcall_Debug

like image 115
sawdust Avatar answered Sep 28 '22 04:09

sawdust


As specified by the comments in kernel init.h

"module_init() will either be called during do_initcalls() (if builtin) or at module insertion time (if a module)."

If you look into init.h then you will see

define module_init(x) __initcall(x);

And if you closely observe then

define __initcall(fn) device_initcall(fn)

And

define device_initcall(fn) __define_initcall("6",fn,6)

So basically the module init leads to initcall (NOTE: only for statically compiled modules) at the time of boot only.

like image 37
shingaridavesh Avatar answered Sep 28 '22 04:09

shingaridavesh