The work that's carried out by a given softirq is statically compiled into the kernel image (it's fixed). This coupling of the softirq and the action it takes (in effect, the code it runs, via the action function pointer) is done via the following code:
// kernel/softirq.c
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}
The following diagram is a conceptual representation of the available softirqs and their priority level on Linux (as of kernel version 5.4), with 0 being the highest and 9 the lowest softirq priority level:
Figure 4.11 – The 10 softirqs on Linux in order of priority (0:highest, 9:lowest)
The following table sums up the individual kernel's softirqs in order of their priority (0: HI_SOFTIRQ being the highest priority one), along with the action or vector, its functionality, and a comment mentioning what its use case is:
Softirq# | Softirq | Comment... |