What Is the Linux Built-In Driver Load Order

What is the Linux built-in driver load order?

Built-in drivers wont be loaded, hence built-in. Their initialization functions are called and the drivers are activated when kernel sets up itself. These init functions are called in init/main.c::do_initcalls(). All init calls are classified in levels, which are defined in initcall_levels and include/linux/init.h

These levels are actuall symbols defined in linker script (arch/*/kernel/vmlinux.lds.*). At kernel compile time, the linker collects all function marked module_init() or other *_initcall(), classify in levels, put all functions in the same level together in the same place, and create like an array of function pointers.

What do_initcall_level() does in the run-time is to call each function pointed by the pointers in the array. There is no calling policy, except levels, in do_initcall_level, but the order in the array is decided in the link time.

So, now you can see that the driver's initiation order is fixed at the link time, but what can you do?

  1. put your init function in the higher level, or
  2. put your device driver at the higher position in Makefile

The first one is clear if you've read the above. ie) use early_initcall() instead if it is appropriate.

The second one needs a bit more explanation. The reason why the order in a Makefile matter is how the current kernel build system works and how the linkers works. To make a long story short, the build system takes all object files in obj-y and link them together. It is highly environment dependent but there is high probability that the linker place first object file in the obj-y in lower address, thus, called earlier.

If you just want your driver to be called earlier than other drivers in the same directory, this is simplest way to do it.

Change the order that built in kernel drivers get initialized?

initcall ordering is defined here:

http://lxr.free-electrons.com/source/include/linux/init.h#L194

which is, for reference:

/*
* A "pure" initcall has no dependencies on anything else, and purely
* initializes variables that couldn't be statically initialized.
*
* This only exists for built-in code, not for modules.
* Keep main.c:initcall_level_names[] in sync.
*/
#define pure_initcall(fn) __define_initcall(fn, 0)

#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)

As module_init is #defined to be device_initcall, a general module with nothing dependent on it gets initialized towards the end of the sequence. To load your module early, you simply change its module_init call to something else that occurs earlier (like subsys_initcall, for example)

Note: just switching the order on things can break other dependencies, and you can get in a catch-22 dependency loop from hell.

Changing Linux kernel module boot order

I was able to solve the problem. It turns out that order to make *_initcall()'s work, the module should be statically linked, therefore, I set;

CONFIG_DRM_VC4=y
CONFIG_SND=y
CONFIG_SNC_SOC=y

This loses a couple of milliseconds of boot time, but now /dev/fb0 loads at around ~0.3 seconds, rather than ~9 seconds.

Are builtin driver always prioritized over loadable modules?

I found the answer in the meanwhile and I documented it here:
http://0x0001.de/linux-driver-loading-registration-and-binding

To make a long story short:
Yes, builtin drivers are in general prioritized over loadable drivers.
Just because they are registered first and "first comes first serves" principle while binding.

Driver probe order in Linux Kernel

According to this SO answer, the order in the makefile is the correct approach to this.

See also this other SO answer for a detailed explanation of the mechanisms.

How to change kernel module loading order in yocto

You can also use the KERNEL_MODULE_AUTOLOAD variable. It is working for me.

Add
KERNEL_MODULE_AUTOLOAD += "<module-name>" in your local.conf

Difference between Linux Loadable and built-in modules

Linux kernel supports inserting of modules (aka device drivers) in two ways:

  1. Built-in kernel modules - When the kernel is booted up, the kernel automatically inserts this driver in to the kernel (it's more like it is already part of the kernel code).
  2. Loadable kernel module (LKM) - A driver that is not automatically loaded by the kernel, the user can insert this module at run-time by insmod driver.ko or modprobe driver.ko

The advantage the loadable modules have over the built-in modules is that you can load unload them on run-time. This is good if you are working on a module and you need to test it. Every time you test it and you need to make changes to it, you can easily unload it (rmmod driver.ko or modprobe -r driver.ko) and then after making changes, you can insert it back. But for the built-in modules if you need to make any changes in the module then you need to compile the whole kernel and then reboot the system with the new image of the kernel.

Configuration:

You can configure a module to be either of the two by editing the .config file in the root folder of your kernel source:

DRIVER_1=y // y indicate a builtin module
DRIVER_1=m //m inicates a loadable module

Note: lsmod displays only the dynamically loaded modules not the built-in ones.

Read on: http://www.tldp.org/HOWTO/Module-HOWTO/x73.html



Related Topics



Leave a reply



Submit