How does newer Linux kernels load non-removable hardware device drivers during boot?
Multiple device drivers (specified in the device tree) are not loading during boot. All built in drivers get loaded with no issue. The drivers successfully load and function if modprobe is used at the command line. Linux Kernel: 5.4.24 Hardware: Custom board with an iMX6 (ARM), ov5640 Camera, TI WL1831 Wifi chip, and an audio amp tied to a PWM output of the iMX6. Yocto (Dunfell) is used to build an SD card image for this embedded device. Root is only/always mounted read only during the boot of the kernel. The following device drivers are not loading: wl18xx, wlcore_sdio, wlcore, ov564x_mipi (ov5640_camera_int.ko), mxc_v4l2_capture, pwm-imx. The TI WL18XX drivers are patched into the kernal from Texas Instruments source. The pwm-imx driver is something I wrote. I am using stock ov564x_mipi and mxc_v4l2_capture drivers at the moment. Side Note: This works as desired in an older 3.14 kernel. So I suspect I am missing something that the newer kernels require. The device tree is getting loaded by u-boot. The /proc/device-tree matches the device tree as expected.
My Actions:
- There are no errors or indication that drivers are even attemped to get loaded in the dmesg output.
- Reverse compile device tree to verify all devices are enabled and have a compatible attribute defined. I had to fix the device tree attribute to get these drives to function correctly after loading them with modprobe.
- Checked that all of these kernel modules use the MODULE_DEVICE_TABLE() macro.
- Checked that all the /sys/firmware/devicetree listings have a “compatible” entry that contains a matching of_device_id string that is in the source of each driver.
- Checked that the expected module alias shows up in modinfo
- Checked the depmod database. It lists all modules and the correct dependancies.
- After boot an lsmod shows nothing. No kernel modules are loaded at all.
- I have tried loading these based on info found at https://wiki.archlinux.org/index.php/Kernel_module#Loading
- There is no listing in /sys/bus/*/drivers for any of these drivers after a clean boot. When I manually load each driver with modprobe the an appropriate listing shows up in /sys/bus/*/drivers
- Researching udev has not provided answers. udev handles events that are driven by actions triggered by loading kernel modules. I can not find anything stating how, when, or why udev actually loads kernel modules.
- Tried posting this first at https://stackoverflow.com/questions/66754562/linux-device-drivers-not-loading-during-boot
My Opinions:
- Systemd is capable of running scripts that call modprobe. I do not believe systemd should load kernel modules for hardware that is not removable.
Information:
These kernel modules are present at:
/lib/modules/5.4.24+g5303049bda95/kernel/drivers/media/platform/mxc/capture/ov5640_camera_mipi_int.ko /lib/modules/5.4.24+g5303049bda95/extra/pwm-imx.ko /lib/modules/5.4.24+g5303049bda95/kernel/drivers/media/platform/mxc/capture/mxc_v4l2_capture.ko /lib/modules/5.4.24+g5303049bda95/kernel/drivers/net/wireless/ti/wl18xx/wl18xx.ko /lib/modules/5.4.24+g5303049bda95/kernel/drivers/net/wireless/ti/wlcore/wlcore.ko /lib/modules/5.4.24+g5303049bda95/kernel/drivers/net/wireless/ti/wlcore/wlcore_sdio.ko
The following sys paths are present upon boot:
/sys/bus/platform/devices/2080000.pwm /sys/bus/platform/devices/20d4000.v4l2_cap_0 /sys/bus/platform/devices/21a0000.i2c /sys/bus/platform/devices/2190000.usdhc /sys/devices/soc0/soc/2000000.aips-bus/2080000.pwm /sys/devices/soc0/soc/2000000.aips-bus/20d4000.v4l2_cap_0 /sys/devices/soc0/soc/2100000.aips-bus/21a0000.i2c /sys/devices/soc0/soc/2100000.aips-bus/2190000.usdhc /sys/firmware/devicetree/base/soc/aips-bus@2000000/pwm@2080000 /sys/firmware/devicetree/base/soc/aips-bus@2000000/v4l2_cap_0@20d4000 /sys/firmware/devicetree/base/soc/aips-bus@2100000/i2c@21a0000/ov5640_mipi@3c /sys/firmware/devicetree/base/soc/aips-bus@2100000/usdhc@2190000/wlcore@0
Example of changes in /sys:
$> find / -name *ov564* /sys/firmware/devicetree/base/soc/aips-bus@2100000/i2c@21a0000/ov5640_mipi@3c /lib/modules/5.4.24+g5303049bda95/kernel/drivers/media/platform/mxc/capture/ov5640_camera_mipi_int.ko $> modprobe ov5640_camera_mipi_int $> find / -name *ov564* /sys/firmware/devicetree/base/soc/aips-bus@2100000/i2c@21a0000/ov5640_mipi@3c /sys/bus/i2c/drivers/ov564x_mipi /sys/module/ov5640_camera_mipi_int /sys/module/ov5640_camera_mipi_int/drivers/i2c:ov564x_mipi /sys/module/v4l2_int_device/holders/ov5640_camera_mipi_int /lib/modules/5.4.24+g5303049bda95/kernel/drivers/media/platform/mxc/capture/ov5640_camera_mipi_int.ko
/usr/lib/modprobe.d/ does not exist /etc/conf.d/modules does not exist $> ls -als /lib/modprobe.d total 12 4 drwxr-xr-x 2 root root 4096 Mar 9 12:34 . 4 drwxr-xr-x 9 root root 4096 Mar 9 12:34 .. 4 -rw-r--r-- 1 root root 765 Mar 9 12:34 systemd.conf $> ls -als /etc/modprobe.d/ total 12 4 drwxr-xr-x 2 root root 4096 Mar 9 12:36 . 4 drwxr-xr-x 39 root root 4096 Mar 9 2018 .. 4 -rw-r--r-- 1 root root 70 Mar 9 12:38 ov564x-mipi.conf cat /etc/modprobe.d/ov564x-mipi.conf # Load ov5640_camera_mipi_int at boot options ov5640_camera_mipi_int $> ls -als /etc/modules-load.d/ total 12 4 drwxr-xr-x 2 root root 4096 Mar 9 2018 . 4 drwxr-xr-x 39 root root 4096 Mar 9 2018 .. 4 -rw-r--r-- 1 root root 62 Mar 9 2018 ov564x-mipi.conf cat /etc/modules-load.d/ov564x-mipi.conf # Load ov5640_camera_mipi_int at boot ov5640_camera_mipi_int
Example of udev Events that get fired when a driver is loaded
$> udevadm monitor & $>modprobe ov5640_camera_int KERNEL[225.175451] add /module/v4l2_int_device (module) UDEV [225.181252] add /module/v4l2_int_device (module) KERNEL[225.183581] add /module/ov5640_camera_int (module) KERNEL[225.183956] add /bus/i2c/drivers/ov564x (drivers) UDEV [225.186825] add /module/ov5640_camera_int (module) UDEV [225.190633] add /bus/i2c/drivers/ov564x (drivers) $>modprobe mxc_v4l2_capture KERNEL[267.876151] add /module/ipu_fg_overlay_sdc (module) KERNEL[267.880571] add /module/ipu_csi_enc (module) UDEV [267.882058] add /module/ipu_fg_overlay_sdc (module) KERNEL[267.885927] add /module/ipu_prp_enc (module) UDEV [267.887871] add /module/ipu_csi_enc (module) UDEV [267.888047] add /module/ipu_prp_enc (module) KERNEL[267.889285] add /module/ipu_still (module) UDEV [267.890705] add /module/ipu_still (module) KERNEL[267.891847] add /module/ipu_bg_overlay_sdc (module) UDEV [267.894052] add /module/ipu_bg_overlay_sdc (module) KERNEL[267.901998] add /module/mxc_v4l2_capture (module) UDEV [267.903648] add /module/mxc_v4l2_capture (module) KERNEL[267.904599] add /devices/soc0/soc/2000000.aips-bus/20d4000.v4l2_cap_0/video4linux/video0 (video4linux) KERNEL[267.906944] bind /devices/soc0/soc/2000000.aips-bus/20d4000.v4l2_cap_0 (platform) KERNEL[267.907472] add /bus/platform/drivers/mxc_v4l2_capture (drivers) UDEV [267.910128] add /bus/platform/drivers/mxc_v4l2_capture (drivers) UDEV [267.924422] add /devices/soc0/soc/2000000.aips-bus/20d4000.v4l2_cap_0/video4linux/video0 (video4linux) UDEV [267.927830] bind /devices/soc0/soc/2000000.aips-bus/20d4000.v4l2_cap_0 (platform)
Relevant sections from reverse compiled device tree:
soc < #address-cells = ; #size-cells = ; compatible = "simple-bus"; interrupt-parent = ; ranges; aips-bus@2000000 < compatible = "fsl,aips-bus", "simple-bus"; #address-cells = ; #size-cells = ; reg = ; ranges; pwm@2080000 < #pwm-cells = ; compatible = "fsl,pwm-imx"; reg = ; interrupts = ; clocks = ; clock-names = "ipg", "per"; status = "okay"; pinctrl-names = "default"; pinctrl-0 = ; >; v4l2_cap_0@20d4000 < compatible = "fsl,imx6q-v4l2-capture"; reg = ; interrupts = ; interrupt-names = "epit2"; clocks = ; clock-names = "ipg", "per"; ipu_id = ; csi_id = ; mclk_source = ; mipi_camera = ; default_input = ; io3-gpios = ; io4-gpios = ; HREF-gpios = ; LED_EN-gpios = ; LASER2-gpios = ; LASER3-gpios = ; LED2_EN-gpios = ; LASER1-gpios = ; LED1_EN-gpios = ; FLEN-gpios = ; LED_CUR1-gpios = ; LED_CUR2-gpios = ; CHARGE_EN-gpios = ; FLASH_FLAG-gpios = ; status = "okay"; >; >; aips-bus@2100000 < compatible = "fsl,aips-bus", "simple-bus"; #address-cells = ; #size-cells = ; reg = ; ranges; usdhc@2190000 < compatible = "fsl,imx6q-usdhc"; reg = ; interrupts = ; clocks = ; clock-names = "ipg", "ahb", "per"; bus-width = ; status = "okay"; pinctrl-names = "default"; pinctrl-0 = ; vmmc-supply = ; mmc-pwrseq = ; no-1-8-v; enable-sdio-wakeup; non-removable; ti,non-removable; ti,needs-special-hs-handling; cap-power-off-card; keep-power-in-suspend; #address-cells = ; #size-cells = ; wlcore@0 < compatible = "ti,wl1831"; reg = ; interrupts = ; interrupt-parent = ; platform-quirks = ; >; >; i2c@21a0000 < #address-cells = ; #size-cells = ; compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; reg = ; interrupts = ; clocks = ; status = "okay"; clock-frequency = ; pinctrl-names = "default"; pinctrl-0 = ; ov5640_mipi@3c < compatible = "ovti,ov564x_mipi"; reg = ; pintctrl-names = "default"; pinctrl-0 = ; clocks = ; clock-names = "csi_mclk"; clock-rates = ; DOVDD-supply = ; AVDD-supply = ; DVDD-supply = ; pwn-gpios = ; rst-gpios = ; ipu_id = ; csi_id = ; default_input = ; mclk = ; mclk_source = ; status = "okay"; >; >; >; >;
how a device driver is loaded into linux kernel? [closed]
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Can anyone tell, how a device driver is loaded into linux kernel? means the function call flow. who invokes what? etc., for static and pnp drivers. with some example would be great, like insert USB pen drive kind of stuff. THanks
1 Answer 1
- First of all, to be loaded in the kernel, the driver must be compiled as module.
- The compiled module will have .ko extension.
- The usual location for modules is inside the /lib/modules directory.
- You can have a list of all inserted modules with command lsmod.
- The module is loaded when the system or the user inserts the module (command insmod or modprobe)
- The module_init() function specifies which is the function to be invoked when the module is inserted:
static int __init hello_init(void) < printk(KERN_ALERT "Hello world!\n"); return 0; >module_init(hello_init);
- allocates (through vmalloc()) the memory to hold the module;
- copies the module into that memory region;
- resolves kernel references in the module via the kernel symbol table (works like the linker ld)
- calls the module’s initialization function.
Related
Hot Network Questions
Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.17.43537
By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.
What is the Linux built-in driver load order?
How can we customize the built-in driver load order (to make some built-in driver module load first, and the dependent module load later)?
4 Answers 4
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?
- put your init function in the higher level, or
- 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.