Table of Contents
Linux loadable kernel modules allow code to be added to a running Linux kernel. Most device drivers in Linux can be built statically in the kernel image or as a Loadable Kernel Module(LKM). Loadable kernel modules are installed into the kernel at run time from user space. This page is not intended to be a complete tutorial for Linux loadable kernel modules as there is a lot of documentation for general build and use. This page focuses on topics which are can be less obvious in the general documentation and are needed for a Xilinx specific solution using PetaLinux and/or Yocto generally.
Modules can be in the kernel source tree or out of the kernel source tree referred to as external kernel modules.
Udev is a user space application that is a device manager for the Linux kernel. The Linux kernel sends uevents to user space whenever a device is initialized or removed in the system. A device manager application, such as udev, handles the udev events by creating device nodes and loading loadable kernel modules. Udev works with sysfs and rules from the file system to manage devices. Udev starts early in user space initialization as shown below in the boot log.
Loadable kernel modules (*.ko) are typically installed into the rootfs by a Linux build system such as PetaLinux or Yocto. The install also consists of other files that reflect the details about the loadable kernel modules such as modules.alias and modules.dep. The runtime system in user space uses the other files when loading the kernel modules, such as to load all dependent modules prior to a specific module. Modules are installed in the /lib/modules/<kernel version> directory of the rootfs by default. In tree modules are located in the kernel sub-directory and all others are located in the extra sub-directory.
Loadable kernel modules are loaded (inserted) from user space by a number of methods. Udev is one common method to load kernel modules. Other methods include initialization scripts in the rootfs and manual user commands using the modprobe or insmod commands.
Programmable Logic (PL) Bitstream
The PL bitstream can be loaded in a number of methods for a Xilinx system with many being early in system boot, such as FSBL. There may be reasons to postpone the loading of the bitstream such that it is completed from Linux user space. In this case any loadable kernel modules which are device drivers for the PL must be loaded after the PL bitsream is loaded.
The ability to load kernel modules automatically with udev is convenient but may not always be desired in some systems. The ability to prevent udev from loading specific modules is referred to a blacklisting. A driver can be blacklisted in PetaLinux and Yocto by adding lines to a configuration file such as <plnx-proj-root>/project-spec/meta-user/conf/petalinuxbsp.conf or build/conf/local.conf file as illustrated below with the blacklist of the AXI GPIO driver.
The previous lines cause the /etc/modprobe.d directory to be created in the target rootfs along with a configuration file for each driver in that directory which specifies to blacklist the driver. Each configuration file contains a single line with the format of "blacklist <driver ko file base name without the extension>" and causes udev to not load the specified driver.
Which Modules Get Automatically Loaded
Modules, either in tree or out of tree, which are referenced in a device tree node using the appropriate compatible property are typically loaded automatically by udev. Modules which have no device tree connections are not typically loaded automatically and require another method to cause them to be loaded.
Loading Modules Automatically Without Udev
A PetaLinux created (petalinux-create -t modules --name hello --enable) out of tree module is automatically copied into the target rootfs when the module is enabled in the PetaLinux rootfs configuration.
In Yocto the driver module copy requires an additional configuration file (such as build/conf/local.conf) change. The following line illustrates adding the hello kernel module to the target rootfs.
Assuming the module file (ko) is contained in the target rootfs, the mod-utils.sh script must find a configuration file to cause it to load the driver. The following line is added to a PetaLinux/Yocto configuration file such as <plnx-proj-root>/project-spec/meta-user/conf/petalinuxbsp.conf or build/conf/local.conf.
The previous configuration line causes the creation of the /etc/modules-load.d directory together with hello.conf in the directory. Note that the configuration only contains the name of the driver (without an extension).
Uevents, Device Drivers, and Device Tree
The Linux kernel creates udev events to be sent to user space in a number of frameworks including the device driver framework. Device tree compatible device drivers include a compatible list which is used to bind to a device to a compatible driver. The compatible property in the device tree helps the appropriate kernel module for a device be loaded by udev. The following driver and device tree snippets illustrate a compatible string.
The compatible string in the device tree can also be seen in the modules.alias file of the target.
Udev provides a user space application, udevadm, that can be helpful for understanding the uevents which udev receives from the kernel. Any loaded modules, seen by lsmod, can be unloaded and then reloaded using udev while watching uevents in real time on the target as illustrated below.
Remove the UIO modules from the kernel assuming they were automatically inserted.
Start the udev admininstration application monitoring all uevents from the kernel and put it in the background.
Stop the udev application, then restart it to simulate a boot up of the kernel.
A lot of output from udevadm will be seen showing all the uevents from the kernel. Some typical uevents are shown below.
[ 3270.286742] udevd: starting version 3.2
[ 3270.297017] udevd: starting eudev-3.2
KERNEL[3270.322676] add /module/uio (module)
KERNEL[3270.322701] add /class/uio (class)
UDEV [3270.322913] add /module/uio (module)
KERNEL[3270.322970] add /module/uio_pdrv_genirq (module)
UDEV [3270.323051] add /class/uio (class)
KERNEL[3270.323080] add /bus/platform/drivers/uio_pdrv_genirq (drivers)
UDEV [3270.323168] add /module/uio_pdrv_genirq (module)
UDEV [3270.323334] add /bus/platform/drivers/uio_pdrv_genirq (drivers)