Some Linux device drivers need loading firmware files to enable the features, especially the new DRM and Wireless drivers.
However, we notice some drivers load the firmware files when they probe, not the open action. If the driver is built in kernel image and it will load a firmware file, then it may fail to load the firmware file. Because, the kernel may have not mounted the whole file system before probing, yet. The current workaround is building the drivers as modules and inserting the firmware files into the ramfs. The WiFi on Raspberry Pi has the same issue as well.
So, the initial idea is that try to move the firmware loading action from probe to open function for Raspberry Pi's WiFi driver. But, it is good to study how other drivers do related things in advance.
Let's check the Intel WiFi on my laptop as the example!
The module iwlwifi loads "71.058653f6.0 so-a0-gf-a0-71.ucode" in the filesystem.
So, it is in drivers/net/wireless/intel/iwlwifi/iwl-drv.c
's iwl_req_fw_callback()
.
Intel WiFi has a Driver system flows:
Trace the real code:
module_init(iwl_drv_init) -> iwl_pci_register_driver() -> iwl_pci_driver -> iwl_pci_probe() -> iwl_drv_start() -> iwl_request_firmware() -> iwl_req_fw_callback()
The driver is registered as a kind of PCI driver:
The pci_driver has probe, remove … functions, but does not have the open function.
Then, moving the load firmware file action into open function might be impractical. :cry:
Following the Intel WiFi driver, it loads the firmware files by the procedure:
request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, drv->trans->dev, GFP_KERNEL, drv, iwl_req_fw_callback) -> request_firmware_work_func() -> _request_firmware() -> fw_get_filesystem_firmware()
I notice fw_get_filesystem_firmware() is blocked by wait_for_initramfs() introduced from commit e7cb072eb988 ("init/initramfs.c: do unpacking asynchronously").
This means if any driver wants to load the firmware file from filesystem, it waits until the rootfs in the ramfs populated. Interesting!
The root device (root=
) is set in root_dev_setup().
From Early userspace support - How does it work?, the kernel has currently 3 ways to mount the root filesystem:
To maintain backwards compatibility, the /init binary will only run if it comes via an initramfs cpio archive. If this is not the case, init/main.c:init() will run prepare_namespace() to mount the final root and exec one of the predefined init binaries.
prepare_namespace() is an entry point to mount the root filesystem. However, …
Linux distros like Endless OS use the initramfs. Then, the call to prepare_namespace() must be skipped. The real root filesystem is mounted by OSTree, not the code in the kernel.
So, checking root file system is mounted cannot be the barrier in the device driver.
Thanks to Daniel's reminder:
The Intel WiFi driver is not only a PCI device driver, but also a WiFi interface driver. The WiFi feature cannot be access without the interface.
From this angle, found the WiFi interface driver has the start() callback function.
This is the test target.