Working With Linux Kernel Modules
While studying for my lpic-1 exam I have been learning more about kernel modules. One thing that is useful is identifying and configuring the options associated with the kernel modules or the kernel parameters. In the process of inspecting the kernel modules I identified some parameters for a couple of modules that I wondered if it would be helpful to set. The modules I was looking at were are 'btusb' and 'iwlmvm'. These modules caught my attention because they are used on my wireless card on my desktop. They offer some power saving features because they are traditionally used on a laptop, but since the hardware is installed on my desktop I want to make sure these features are turned off. I did have an issue with my Bluetooth ear buds loosing connection after 20 or 30 minutes sometimes so I thought this could be part of the issue. WiFi I want to make sure is always working it's best and isn't switching in and out of a power saving mode which can cause issues.
Finding Kernel Module Parameters
To manipulate these parameters we need to figure out what they are. To do that we need to know what module is being used by the hardware. There are multiple ways to do this depending on how the hardware is connected to the system.
lspci
For the WiFi card, it is connected to the Peripheral Component Interconnect Express (PCIe) bus.
It's a card that plugs into a PCIe slot and is exposed to the system. We can inspect
components connected to this bus with the lspci
command. Here is a sample of the
output that includes information on the wireless card installed in the system.
02:00.0 USB controller: Fresco Logic FL1100 USB 3.0 Host Controller (rev 10)
03:00.0 PCI bridge: Intel Corporation DSL6540 Thunderbolt 3 Bridge [Alpine Ridge 4C 2015]
04:00.0 PCI bridge: Intel Corporation DSL6540 Thunderbolt 3 Bridge [Alpine Ridge 4C 2015]
04:01.0 PCI bridge: Intel Corporation DSL6540 Thunderbolt 3 Bridge [Alpine Ridge 4C 2015]
04:02.0 PCI bridge: Intel Corporation DSL6540 Thunderbolt 3 Bridge [Alpine Ridge 4C 2015]
04:04.0 PCI bridge: Intel Corporation DSL6540 Thunderbolt 3 Bridge [Alpine Ridge 4C 2015]
07:00.0 USB controller: Intel Corporation DSL6540 USB 3.1 Controller [Alpine Ridge]
09:00.0 Network controller: Intel Corporation Wi-Fi 6 AX200 (rev 1a)
0a:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM951/PM951 (rev 01)
We can see which hardware is installed and detected, it's address on the PCIe bus
and a description of the hardware.
09:00.0 Network controller: Intel Corporation Wi-Fi 6 AX200 (rev 1a)
This is the WiFi card. Now we want to find out what module is being used with this card.
lspci
can give us this info pretty easily, it has a couple option flags we can use.
-s 9:0.0
will select the specific device in question
-k
will specifically tell lspci
we want to know the kernel module being used with the hardware
# lspci -s 9:0.0 -k
09:00.0 Network controller: Intel Corporation Wi-Fi 6 AX200 (rev 1a)
Subsystem: Intel Corporation Wi-Fi 6 AX200
Kernel driver in use: iwlwifi
Kernel modules: iwlwifi
Great! We know the iwlwifi
module is being used for our WiFi card. Now let's figure
out what module is being used for our Bluetooth adapter.
lsusb
Our Bluetooth adapter was not listed with lspci
, it's not connected to the system
the same way. The adapter is a USB adapter, lsusb
is very similar to lspci
but
give us a list of USB hardware connected to the system.
# lsusb
Bus 001 Device 005: ID 0451:2036 Texas Instruments, Inc. TUSB2036 Hub
Bus 001 Device 003: ID 1e7d:2e23 ROCCAT Kone XTD Optical Mouse
Bus 001 Device 006: ID 8087:0029 Intel Corp. AX200 Bluetooth
Bus 001 Device 004: ID 1e7d:3232 ROCCAT Ryos MK Pro Keyboard
Bus 001 Device 002: ID 04b4:6572 Cypress Semiconductor Corp. Unprogrammed CY7C65642 hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
This is a sample of the output from my system after running the command. We have a similar output, but we will use different flags to get the info we need. The USB devices have two different ways to reference them, the bus and device number or we can use the ID which is two parts [vendor]:[product]. We will need the bus and device number unfortunately lsusb doesn't have an "easy" way to give us just the module name we are after but it's still pretty easy to get.
# lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/16p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 3: Dev 4, If 1, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 3: Dev 4, If 0, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 5: Dev 3, If 1, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 5: Dev 3, If 0, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 6: Dev 5, If 0, Class=Hub, Driver=hub/3p, 12M
|__ Port 2: Dev 7, If 0, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 2: Dev 7, If 1, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 3: Dev 8, If 4, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 5, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 3: Dev 8, If 3, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 14: Dev 6, If 0, Class=Wireless, Driver=btusb, 12M
|__ Port 14: Dev 6, If 1, Class=Wireless, Driver=btusb, 12M
Here we used the "tree" flag and we can see all the devices on Bus 01. We find
Dev 6, our Bluetooth adapter and we can see the driver in use by it is btusb
.
|__ Port 14: Dev 6, If 0, Class=Wireless, Driver=btusb, 12M
|__ Port 14: Dev 6, If 1, Class=Wireless, Driver=btusb, 12M
lsmod
Let's get some more info on the modules that our hardware is using.
# lsmod | grep 'iwlwifi'
iwlwifi 380928 1 iwlmvm
cfg80211 892928 3 iwlmvm,iwlwifi,mac80211
The iwlwifi
module is in use and is also using iwlmvm
.
modinfo
Now that we know what kernel module drivers our hardware is using we can get some info on it.
The modinfo
command will give us the info we want. Take a look at your modules information
there is a lot to learn there. For this exercise we are going to specifically target
getting the modules parameters. We can use the -F
or --field
flag with mod info, we will
provide a field name and modinfo will only return info on that field.
# modinfo -F parm iwlmvm
init_dbg:set to true to debug an ASSERT in INIT fw (default: false (bool)
power_scheme:power management scheme: 1-active, 2-balanced, 3-low power, default: 2 (int)
We can see that the driver has a couple parameters that we can manipulate. We
don't really care about init_dbg
, but power_scheme
sounds interesting. A
little searching online reveals that this is the setting that determines when how
aggressively to switch the wireless off to save power. Considering we are using
the card in a desktop we don't need to worry about switching the wireless off,
if the machine is on then we want the power to the wireless on.
Setting Module Parameters
modprobe.d
We can use configuration files in /etc/modprobe.d/
to set options for a module.
# echo "options iwlmvm power_scheme=1" > /etc/modprobe.d/iwlmvm.conf
Now let's unload and reload the module and see if it load the correct option.
# modprobe -r iwlmvm
# modprobe iwlmvm
cat /sys/module/iwlmvm/parameters/power_scheme
1
We can see that our module now has the option set to 1, always active. Because we created the config file, every time the module is loaded it will use that config.
btusb autosuspend
Similarly, we want to disable autosuspend on the btusb module since we are on a desktop and we don't need to suspend. This should at least help prevent unwanted disconnects.
# echo "options btusb enable_autosuspend=n" > /etc/modprobe.d/btusb.conf
# modprobe -r btusb
# modprobe btusb
Wrap Up
Manipulating the module settings is pretty straightforward and will offer us a lot of control over the system. It sounds like documentation on the options can be sparse #linux referred me to the kernel module source code as the documentation on the module parameter options, so I cloned the 5GB git repo for the Linux source. I didn't find much helpful for the iwlmvm module options. But it will be fun to dig into that more to learn more about the kernel/modules. There are a lot of modules loaded by the system (see below). We can start poking around at them now and figure out how else we might improve the system!
Module Size Used by
iwlmvm 421888 0
iwlwifi 380928 1 iwlmvm
mac80211 1028096 1 iwlmvm
cfg80211 892928 3 iwlmvm,iwlwifi,mac80211
libarc4 16384 1 mac80211
binfmt_misc 24576 1
rfcomm 81920 16
ipt_REJECT 16384 2
nf_reject_ipv4 16384 1 ipt_REJECT
xt_conntrack 16384 1
xt_comment 16384 17
xt_CHECKSUM 16384 2
nft_chain_nat 16384 4
xt_MASQUERADE 20480 4
nf_nat 49152 2 nft_chain_nat,xt_MASQUERADE
nf_conntrack 147456 3 xt_conntrack,nf_nat,xt_MASQUERADE
nf_defrag_ipv6 24576 1 nf_conntrack
nf_defrag_ipv4 16384 1 nf_conntrack
nft_counter 16384 25
vboxnetadp 28672 0
vboxnetflt 28672 0
vboxdrv 516096 2 vboxnetadp,vboxnetflt
xt_tcpudp 20480 12
nft_compat 20480 38
nf_tables 212992 128 nft_compat,nft_counter,nft_chain_nat
libcrc32c 16384 3 nf_conntrack,nf_nat,nf_tables
nfnetlink 20480 2 nft_compat,nf_tables
vhost_vsock 24576 0
vmw_vsock_virtio_transport_common 40960 1 vhost_vsock
vhost 53248 1 vhost_vsock
vhost_iotlb 16384 1 vhost
vsock 45056 2 vmw_vsock_virtio_transport_common,vhost_vsock
ccm 20480 9
cmac 16384 3
algif_hash 16384 1
algif_skcipher 16384 1
af_alg 32768 6 algif_hash,algif_skcipher
bnep 28672 2
nls_iso8859_1 16384 1
nvidia_uvm 1048576 0
intel_rapl_msr 20480 0
nvidia_drm 61440 7
nvidia_modeset 1196032 14 nvidia_drm
intel_rapl_common 28672 1 intel_rapl_msr
x86_pkg_temp_thermal 20480 0
mei_hdcp 24576 0
intel_powerclamp 20480 0
coretemp 20480 0
crct10dif_pclmul 16384 1
ghash_clmulni_intel 16384 0
aesni_intel 372736 10
nvidia 35270656 710 nvidia_uvm,nvidia_modeset
crypto_simd 16384 1 aesni_intel
cryptd 24576 3 crypto_simd,ghash_clmulni_intel
glue_helper 16384 1 aesni_intel
rapl 20480 0
snd_hda_codec_realtek 147456 1
snd_hda_codec_generic 81920 1 snd_hda_codec_realtek
ledtrig_audio 16384 1 snd_hda_codec_generic
snd_hda_codec_hdmi 65536 1
snd_hda_intel 53248 4
snd_intel_dspcfg 28672 1 snd_hda_intel
soundwire_intel 40960 1 snd_intel_dspcfg
soundwire_generic_allocation 16384 1 soundwire_intel
soundwire_cadence 32768 1 soundwire_intel
snd_usb_audio 299008 3
snd_hda_codec 147456 4 snd_hda_codec_generic,snd_hda_codec_hdmi,snd_hda_intel,snd_hda_codec_realtek
intel_cstate 20480 0
snd_usbmidi_lib 36864 1 snd_usb_audio
snd_hda_core 94208 5 snd_hda_codec_generic,snd_hda_codec_hdmi,snd_hda_intel,snd_hda_codec,snd_hda_codec_realtek
snd_hwdep 16384 2 snd_usb_audio,snd_hda_codec
soundwire_bus 77824 3 soundwire_intel,soundwire_generic_allocation,soundwire_cadence
snd_seq_midi 20480 0
snd_soc_core 294912 1 soundwire_intel
snd_seq_midi_event 16384 1 snd_seq_midi
snd_seq 73728 2 snd_seq_midi,snd_seq_midi_event
snd_rawmidi 36864 2 snd_seq_midi,snd_usbmidi_lib
snd_compress 28672 1 snd_soc_core
ac97_bus 16384 1 snd_soc_core
snd_pcm_dmaengine 16384 1 snd_soc_core
mc 57344 1 snd_usb_audio
snd_pcm 118784 9 snd_hda_codec_hdmi,snd_hda_intel,snd_usb_audio,snd_hda_codec,soundwire_intel,snd_compress,snd_soc_core,snd_hda_core,snd_pcm_dmaengine
btusb 61440 0
serio_raw 20480 0
btrtl 24576 1 btusb
btbcm 16384 1 btusb
snd_seq_device 16384 3 snd_seq,snd_seq_midi,snd_rawmidi
eeepc_wmi 16384 0
wmi_bmof 16384 0
efi_pstore 16384 0
btintel 28672 1 btusb
intel_wmi_thunderbolt 20480 0
mxm_wmi 16384 0
ee1004 20480 0
snd_timer 40960 2 snd_seq,snd_pcm
bluetooth 655360 43 btrtl,btintel,btbcm,bnep,btusb,rfcomm
drm_kms_helper 245760 1 nvidia_drm
snd 94208 29 snd_hda_codec_generic,snd_seq,snd_seq_device,snd_hda_codec_hdmi,snd_hwdep,snd_hda_intel,snd_usb_audio,snd_usbmidi_lib,snd_hda_codec,snd_hda_codec_realtek,snd_timer,snd_compress,snd_soc_core,snd_pcm,snd_rawmidi
cec 53248 1 drm_kms_helper
joydev 28672 0
input_leds 16384 0
rc_core 57344 1 cec
mei_me 40960 1
fb_sys_fops 16384 1 drm_kms_helper
syscopyarea 16384 1 drm_kms_helper
ecdh_generic 16384 2 bluetooth
sysfillrect 16384 1 drm_kms_helper
ecc 32768 1 ecdh_generic
soundcore 16384 1 snd
mei 126976 3 mei_hdcp,mei_me
sysimgblt 16384 1 drm_kms_helper
mac_hid 16384 0
acpi_pad 184320 0
sch_fq_codel 20480 4
uhid 20480 0
kvm_intel 286720 0
kvm 835584 1 kvm_intel
iptable_filter 16384 0
ip6table_filter 16384 0
ip6_tables 32768 1 ip6table_filter
br_netfilter 28672 0
bridge 249856 1 br_netfilter
stp 16384 1 bridge
llc 16384 2 bridge,stp
arp_tables 24576 0
msr 16384 0
parport_pc 45056 0
ppdev 24576 0
lp 20480 0
parport 65536 3 parport_pc,lp,ppdev
drm 552960 11 drm_kms_helper,nvidia,nvidia_drm
sunrpc 548864 1
ip_tables 32768 1 iptable_filter
x_tables 49152 12 ip6table_filter,xt_conntrack,iptable_filter,nft_compat,xt_tcpudp,xt_CHECKSUM,xt_comment,ip6_tables,ipt_REJECT,ip_tables,xt_MASQUERADE,arp_tables
autofs4 45056 4
hid_roccat_ryos 16384 0
hid_roccat 16384 1 hid_roccat_ryos
hid_roccat_common 16384 1 hid_roccat_ryos
hid_generic 16384 0
usbhid 61440 1
hid 135168 5 hid_roccat_ryos,usbhid,hid_generic,hid_roccat,uhid
mfd_aaeon 16384 0
asus_wmi 40960 2 eeepc_wmi,mfd_aaeon
sparse_keymap 16384 1 asus_wmi
crc32_pclmul 16384 0
psmouse 163840 0
nvme 45056 2
e1000e 270336 0
i2c_i801 32768 0
nvme_core 122880 4 nvme
i2c_smbus 20480 1 i2c_i801
ahci 40960 1
xhci_pci 20480 0
libahci 36864 1 ahci
xhci_pci_renesas 20480 1 xhci_pci
wmi 32768 5 intel_wmi_thunderbolt,asus_wmi,wmi_bmof,mfd_aaeon,mxm_wmi
video 53248 1 asus_wmi