I think my lack of hardware knowledge hinders me on this problem.
Then let's start with the basics. Indicator LEDs can be controlled several ways:
The LED is controlled directly by a peripheral chip/device. In this situation, the CPU and the kernel driver would have no control over the LED. This is typically the case for the "activity" and "link speed" LEDs on an Ethernet RJ-45 jack; these LEDs would be under direct/exclusive control of the Ethernet PHY device.
The LED is controlled by a GPIO (General Purpose Input/Output) pin of the CPU or SoC.
The LED is an output of external logic (e.g. an FPGA chip).
The LED is an output on a peripheral chip.
The last three situations may not be distinguishable in the source code. One bit in a port or device register will turn the LED on or off. Inspect the header file for what the other bits in the register will control. The register will be read/written using either I/O instructions or memory fetch/store instructions depending on the processor architecture.
Note that the LED is often a current sink and tied to logic high voltage, so the LED is turned on by grounding the pin by writing a 0
bit value. Conversely the LED is typically turned off by writing a 1
bit value. Since only one bit of the register is being changed, a read of the whole register is typically required prior to the bit modification. The register itself may be a critical region, which will necessitate the acquisition (& release) of a mutex or spin-lock to protect the entire operation.
Source Code Inspection
If the device drivers are proprietary, then you're screwed. Otherwise you should be able to obtain the source code. Your distro should make its source code available. There are online viewers such as this Linux kernel tree with built-in cross-reference hyperlinks. If the drivers are not in the mainline kernel source tree, then you should ask the hardware manufacturer to provide the source code per terms of the GPL.
You have mentioned four indicators:
- wireless connectivity
- hibernation
- bluetooth connectivity
- battery
Obtain the output of the lsmod
command, which will list the runtime modules appended to the kernel. From the list of modules, you need to determine which drivers correspond to the functionality of these LEDs, e.g. wireless networking, power etc. Assuming that this ThinkPad has an Intel wireless controller chip, then you would need to look in the drivers/net/wireless/iwlwifi
directory. Inspect the Kconfig
and Makefile
files in that driver directory for the correlations between the actual HW device name, the configuration symbols, the .ko
module(s) built and the corresponding source code.
Review the driver source code for manipulation of the indicator LED. If the operation is not commented, then you'll have to look for a bit operation, or a macro, or a procedure call. There are many ways to organize this code depending on the modularity of the code, or if OOP techniques were employed and these LED operations are encapsulated in procedures in some other driver. Beware of text (executable code) in macros (i.e. #define
) and in header files. That is, reviewing just the .c
files would be a mistake. Also beware that some device code may be under arch/xxx/platform
or arch/xxx/machine
, especially for embedded single-board computers.
I decided to think a bit more hardware-related so opened to case to clean the processor heat sink. There was hardly any dust so that definitely wasn't the cause, but now System only uses around 1% of the CPU.
The heat sink must have not been fitted properly because all I did was remove it and put it back on and I didn't change anything else. Now my CPU graph actually goes down to ZERO when I'm not doing anything. Yay!
N.B. I'm an idiot.
Best Answer
There is a good article from RedHat on finding out what code kworker threads are running. Please see https://access.redhat.com/solutions/4388131
Here is an excerpt from the article:
On Red Hat Enterprise Linux 7 the ftrace subsystem and trace-cmd command can provide information about what functions the kworker and softirq kernels threads are running.
You can get list of the most frequently queued to least frequently queued workqueue functions with the following: