Interrupts
Technical Overview
An interrupt is a signal to the CPU that causes it to immediately suspend its current execution and transfer control to a special handler function in the kernel. Interrupts are the fundamental mechanism by which hardware devices communicate with the CPU — when a network card receives a packet, when a disk completes an I/O, when a USB device is plugged in, or when a timer fires, the hardware signals the CPU via an interrupt. Without interrupts, the OS would have to continuously poll every device in a tight loop, wasting CPU cycles and increasing latency.
Linux's interrupt subsystem is one of the most performance-critical and latency-sensitive parts of the kernel. Interrupt handlers run at the highest priority — they preempt everything except other interrupt handlers and NMIs (Non-Maskable Interrupts). This priority means interrupt handler code must be short, non-blocking, and extremely carefully written. The Linux interrupt model divides interrupt handling into a "top half" (the handler, running in interrupt context) and a "bottom half" (deferred work via softirqs, tasklets, or threaded interrupt handlers).
Prerequisites
02-user-space-vs-kernel-space.md: kernel context vs. user context03-cpu-privilege-rings.md: privilege modes05-system-calls.md: the other kernel entry mechanism- Basic understanding of computer hardware bus architecture
Core Content
Hardware Interrupts vs. Software Interrupts
Hardware interrupts (IRQs): Triggered by physical devices via electrical signals. A timer chip fires every millisecond to drive the scheduling tick. A NIC fires when a packet arrives. A keyboard controller fires when a key is pressed. These are asynchronous — they can occur at any point during execution.
Software interrupts: Generated by software, not hardware. On x86, the INT n instruction raises interrupt vector n. INT 0x80 was the traditional Linux syscall mechanism. INT3 (opcode 0xCC) is the debugger breakpoint instruction. Software interrupts are synchronous — they occur at the point of the instruction.
Exceptions: Generated by the CPU itself in response to instruction execution (divide-by-zero, page fault, GP fault). These are covered in 07-traps-faults-and-exceptions.md.
In Linux's code, "interrupt" usually means hardware IRQ. "Exception" means CPU-generated fault/trap. "Software interrupt" (softirq) in the Linux sense is a deferred-work mechanism — not a processor INT instruction.
Interrupt Descriptor Table (IDT)
On x86, the IDT is an array of 256 8-byte (32-bit) or 16-byte (64-bit) gate descriptors. Each entry specifies the handler address, code segment, privilege level, and type for one interrupt vector. The CPU uses the IDTR register to locate the IDT in memory. The kernel loads it at boot with lidt.
IDT (Interrupt Descriptor Table) — 256 entries
┌─────────────────────────────────────────────────────┐
│ Vector 0: #DE Divide Error → do_divide_error │
│ Vector 1: #DB Debug → do_debug │
│ Vector 2: NMI Non-Maskable Interrupt → nmi_handler │
│ Vector 3: #BP Breakpoint (INT3) → do_int3 │
│ Vector 4: #OF Overflow → do_overflow │
│ Vector 5: #BR Bound Range Exceeded → do_bounds │
│ Vector 6: #UD Invalid Opcode → do_invalid_op │
│ Vector 7: #NM Device Not Available → do_device_not_available │
│ Vector 8: #DF Double Fault → do_double_fault │
│ ... │
│ Vector 13: #GP General Protection Fault → do_general_protection │
│ Vector 14: #PF Page Fault → do_page_fault │
│ ... │
│ Vectors 32-255: External hardware IRQs and software-defined uses │
│ Vector 32: Timer IRQ (HPET/PIT/APIC) │
│ Vector 33: Keyboard (legacy 8259 PIC) │
│ ... │
│ Vector 236: Local APIC timer vector │
│ Vector 239: IRQ work interrupts (CALL_FUNCTION_VECTOR) │
│ Vector 240-255: IPIs and APIC self-interrupts │
└─────────────────────────────────────────────────────────────────────┘
Vectors 0–31 are reserved by Intel for CPU exceptions. Vectors 32–255 are for use by the OS and hardware. Linux allocates these at boot time based on the number of I/O APICs and their IRQ routing.
Interrupt Vector Numbers: 0–31 Exceptions, 32+ Hardware
Intel-reserved CPU exceptions (Vectors 0-31):
0 #DE Divide Error (divide by zero)
1 #DB Debug Exception
2 NMI Non-Maskable Interrupt
3 #BP Breakpoint
4 #OF Overflow
5 #BR BOUND Range Exceeded
6 #UD Invalid Opcode
7 #NM Device Not Available (FPU not present/coprocessor)
8 #DF Double Fault
9 Coprocessor Segment Overrun (obsolete)
10 #TS Invalid TSS
11 #NP Segment Not Present
12 #SS Stack-Segment Fault
13 #GP General Protection Fault
14 #PF Page Fault
15 Reserved
16 #MF x87 Floating-Point Exception
17 #AC Alignment Check
18 #MC Machine Check Exception
19 #XM SIMD Floating-Point Exception
20 #VE Virtualization Exception (VT-x EPT)
21 #CP Control Protection Exception (CET)
22-31 Reserved
Hardware IRQ vectors start at 32:
32-47: Legacy ISA IRQs (if using 8259 PIC)
32+: IOAPIC-routed IRQs (when APIC is enabled)
IRQ to Vector Mapping: PIC and APIC
Legacy PIC (Programmable Interrupt Controller, Intel 8259)
The original IBM PC interrupt controller. Two cascaded 8259 chips provide 15 IRQ lines (IRQ0–IRQ15), mapped to vectors 0x20–0x2F (32–47). Programming the PIC involves writing to I/O ports 0x20/0x21 (master) and 0xA0/0xA1 (slave). Linux still supports the 8259 PIC but disables it on any system with APIC (enable_IO_APIC()).
APIC (Advanced Programmable Interrupt Controller)
Modern systems use the APIC architecture:
Device → I/O APIC → Local APIC → CPU core
I/O APIC (in chipset/PCH):
- Receives IRQs from devices via interrupt lines
- Configured by OS via memory-mapped registers
- Routes each IRQ to a vector on a target CPU's Local APIC
- Contains an Interrupt Redirection Table (IRT)
Each entry: vector number, delivery mode, destination CPU, flags
Local APIC (in each CPU core):
- Receives interrupt messages from I/O APIC (via system bus)
- Also generates: timer interrupts, thermal interrupts
- Contains: LAPIC timer, Performance Counter interrupt, IPI facility
- Processes interrupts: sets bit in IRR (Interrupt Request Register)
- When processor is ready: moves to ISR (In-Service Register)
- Sends EOI (End of Interrupt) acknowledgment to APIC
The Linux APIC code lives in arch/x86/kernel/apic/ and arch/x86/kernel/irq_remapping.c. The MADT ACPI table tells the kernel the I/O APIC base address and the IRQ-to-interrupt-line mapping.
MSI/MSI-X (Message Signaled Interrupts)
PCIe devices use MSI/MSI-X rather than legacy wire-based IRQ lines. Instead of signaling a hardware line, the device writes a specific data value to a specific memory address (configured by the kernel). This write is interpreted by the APIC as an interrupt message.
Advantages: - No shared IRQ lines (each device function gets unique vectors) - Lower latency (no wire propagation delay) - Scalable: MSI-X allows up to 2048 interrupt vectors per device - Enables multi-queue NICs: each TX/RX queue gets its own MSI-X vector, mapped to a different CPU core
Linux configures MSI/MSI-X via pci_enable_msi() / pci_enable_msix_range() in drivers/pci/msi.c.
Interrupt Handler Registration
Device drivers register interrupt handlers using request_irq() (or request_threaded_irq()):
// From a driver's probe() function:
int err = request_irq(
pdev->irq, // IRQ number (from PCI config or device tree)
my_irq_handler, // handler function
IRQF_SHARED, // flags: shared IRQ line, etc.
"my_device", // name (shown in /proc/interrupts)
dev // private data passed to handler
);
The handler function signature:
irqreturn_t my_irq_handler(int irq, void *dev_id)
{
struct my_device *dev = dev_id;
// MUST:
// - Check if interrupt is from this device (shared IRQs)
// - Acknowledge the interrupt to the hardware
// - Read status registers
// - Queue deferred work (tasklet, workqueue)
// MUST NOT:
// - Sleep
// - Call schedule()
// - Allocate memory with GFP_KERNEL
// - Acquire a mutex
return IRQ_HANDLED; // or IRQ_NONE if not our interrupt
}
Return values: IRQ_HANDLED (this handler owned the interrupt), IRQ_NONE (not our interrupt — for shared IRQ lines), IRQ_WAKE_THREAD (wake the threaded handler).
Interrupt Context Rules: No Sleeping, No Scheduling
When the CPU is executing an interrupt handler, it is said to be in interrupt context. The in_interrupt() macro returns true. Critical rules:
-
No sleeping:
msleep(),wait_event(), and anything that callsschedule()will triggermight_sleep()BUG assertions. The interrupt handler cannot sleep because it's not running on behalf of any particular process — there's no task to put to sleep. -
No mutexes:
mutex_lock()may sleep if the lock is contended. Usespin_lock_irqsave()instead, which disables interrupts and takes a spinlock atomically. -
Memory allocation: Only
GFP_ATOMICallocation is permitted (non-sleeping, may fail).GFP_KERNELallocations may sleep. -
Limited stack: The interrupt handler runs on a separate per-CPU interrupt stack (size:
IRQ_STACK_SIZE= 16 KiB on x86-64). Deep call chains from an interrupt handler can overflow it. -
Preemption: The interrupt handler runs with preemption disabled.
preempt_countis incremented on entry, preventingschedule()even if called indirectly.
Interrupt Delivery Flow Diagram
Hardware event (NIC receives packet):
NIC raises interrupt signal on PCIe MSI-X message
↓ PCIe bus delivers MSI write to memory address
I/O APIC (or directly to Local APIC for MSI):
Receives interrupt, looks up IRT entry
Sends interrupt message to target CPU's Local APIC
Local APIC:
Sets bit N in IRR (Interrupt Request Register)
When CPU is ready (not in non-maskable-interrupt, IF=1):
Moves bit from IRR to ISR, raises INTR pin to CPU
CPU hardware:
Finishes current instruction
Saves: RIP, RSP, RFLAGS, CS, SS onto kernel stack
Switches to ring 0 (CPL=0)
Switches to interrupt stack (from TSS.ist[])
Loads handler address from IDT[vector]
Jumps to handler
Kernel entry (arch/x86/entry/entry_64.S):
Save all registers (PUSH_REGS)
Set up IRQ stack
call handle_irq(irq, pt_regs)
handle_irq():
Find struct irq_desc for this IRQ number
Call registered handler chain
Device driver handler (my_irq_handler):
Read device status register (confirms interrupt is ours)
Acknowledge interrupt to device
Read/write device data
Schedule bottom-half work (napi_schedule, tasklet_schedule, etc.)
return IRQ_HANDLED
Return path:
Send EOI (End of Interrupt) to Local APIC
POP_REGS (restore registers)
IRET (restore RIP, RFLAGS, RSP, CPL)
CPU resumes interrupted code
Interrupt Latency
Interrupt latency = time from hardware event to first instruction of the handler. Contributors: - PCIe/bus propagation: ~100ns - APIC delivery: ~50ns - CPU instruction finish: up to one instruction boundary (usually <10ns) - IDT lookup and ring/stack switch: ~50ns - Kernel entry overhead (save registers, route to handler): ~100ns
Total: typically 200–500ns on a modern system with APIC and MSI-X.
Real-time Linux (PREEMPT_RT) aims to reduce worst-case interrupt latency by making interrupt handlers runnable as threads (they can be preempted by higher-priority RT tasks), eliminating the "always preempts everything" behavior.
Interrupt Affinity: /proc/interrupts and smp_affinity
# Show interrupt counts per CPU core
cat /proc/interrupts
# CPU0 CPU1 CPU2 CPU3
# 0: 9 0 0 0 IO-APIC 2-edge timer
# 8: 0 0 1 0 IO-APIC 8-edge rtc0
# 29: 0 0 0 312454 PCI-MSI 524288-edge xhci_hcd
# NMI: 5 4 6 5 Non-maskable interrupts
# LOC: 924130 842517 931204 887645 Local timer interrupts
# Show/set which CPUs handle IRQ 29:
cat /proc/irq/29/smp_affinity # hex bitmask
echo "3" > /proc/irq/29/smp_affinity # route to CPUs 0 and 1 only
cat /proc/irq/29/smp_affinity_list # human-readable: "0-1"
IRQ balancing: irqbalance daemon dynamically adjusts IRQ affinity to distribute interrupt load across CPUs. For high-throughput networking, it's common to disable irqbalance and manually pin each NIC queue's IRQ to a specific CPU core, co-locating the interrupt handler and the application thread that processes the data on the same NUMA node.
Multi-queue NICs (with MSI-X) create one RX queue interrupt per CPU core. This allows the NIC to be scaled across all cores without any locking — each core processes its own RX queue. Linux's ethtool -l and ethtool -L control the number of queues; ethtool -x shows the RSS (Receive-Side Scaling) flow-to-queue mapping.
Threaded Interrupt Handlers (IRQF_THREAD)
request_threaded_irq() splits the interrupt handler into:
1. Primary handler (runs in hardware interrupt context): must be short, just checks if the interrupt is from this device and acknowledges it. Returns IRQ_WAKE_THREAD.
2. Thread handler (runs in a dedicated kernel thread irq/N-name): does the real work. CAN sleep. CAN use mutexes. Runs at SCHED_FIFO priority.
request_threaded_irq(irq,
my_primary_handler, // fast, no-sleep, returns IRQ_WAKE_THREAD
my_thread_handler, // slow, may sleep
IRQF_ONESHOT, // keep IRQ masked until thread handler completes
"my_device",
dev);
Threaded IRQ handlers are the modern recommended approach for drivers that need to do significant work in response to an interrupt (e.g., USB host controllers, I2C/SPI devices). They make the driver's interrupt handling preemptible and reduce worst-case interrupt latency for the rest of the system.
Historical Context
The interrupt concept dates to the late 1950s. The Univac LARC (1959) had a form of interrupt. The IBM 7090 (1959) had interrupt channels. The PDP-11 (1970) had a clean vectored interrupt architecture that directly influenced both x86 and Unix interrupt handling design.
The Intel 8259 PIC (1976) became the standard interrupt controller for the IBM PC (1981). Its 15-IRQ limitation was a constant constraint — adding a sound card, network card, and SCSI adapter simultaneously required IRQ sharing, which was unreliable and a source of "IRQ conflict" errors familiar to anyone who administered PCs in the 1990s.
APIC was introduced with the Intel Pentium (1993) for multi-processor support. The I/O APIC enabled routing interrupts to specific CPUs, essential for SMP. MSI was introduced in PCI 2.2 (2001) and MSI-X in PCI 3.0 (2002), eliminating the shared interrupt line problem.
Linux's interrupt subsystem has been significantly refactored multiple times. The genirq (generic IRQ handling) framework, introduced in Linux 2.6.17 (2006) by Thomas Gleixner and Ingo Molnar, unified x86, ARM, MIPS, and other architectures under a common struct irq_desc model. Threaded interrupt handlers were added in Linux 2.6.30.
Production Examples
High-frequency trading NIC interrupt tuning: HFT firms run Linux with custom kernel builds, disable irqbalance, pin NIC IRQs to isolated CPUs (isolcpus=), disable the scheduler tick on those CPUs (nohz_full=), and use polling mode (NAPI with CONFIG_NET_RX_BUSY_POLL) to achieve sub-microsecond packet processing latency. Every microsecond of interrupt latency is a competitive disadvantage.
Multi-queue NIC configuration for a 100G server: A modern 100 GbE NIC (Mellanox ConnectX-6) has 64 RX/TX queue pairs. Each queue is assigned a separate MSI-X vector. irqbalance or a tuning script pins queue 0's IRQ to CPU 0, queue 1's IRQ to CPU 1, etc. Application threads are also pinned to matching CPUs (using SO_INCOMING_CPU or RSS hash). This ensures cache locality: the interrupt handler that processes incoming packet headers and the application thread that reads socket data run on the same CPU core, sharing L1/L2 cache.
Storage array interrupt coalescing: NVMe SSDs support interrupt coalescing: the drive can be configured to accumulate multiple completions before firing an interrupt. This reduces interrupt rate at the cost of latency. Linux configures this via nvme set-feature (NVMe admin command) or automatically via I/O depth heuristics. For throughput-optimized workloads (sequential reads/writes), coalescing is a net win. For latency-sensitive workloads, it must be disabled.
Debugging Notes
# Check interrupt counts and identify which CPU handles which IRQ
watch -n 0.5 'cat /proc/interrupts'
# Check if an IRQ is being shared (multiple drivers on one line)
grep " 29:" /proc/interrupts
# IRQ affinity
cat /proc/irq/*/smp_affinity_list
# Softirq statistics
cat /proc/softirqs
# Interrupt rate per second (useful for diagnosing interrupt storms)
grep "NIC_name" /proc/interrupts # note the count
sleep 1
grep "NIC_name" /proc/interrupts # compare
# eBPF: trace all hardware interrupts
bpftrace -e 'tracepoint:irq:irq_handler_entry { @[args->irq, args->name] = count(); }'
# Measure interrupt latency (requires kernel with CONFIG_IRQSOFF_TRACER)
echo 1 > /sys/kernel/debug/tracing/options/irqsoff
cat /sys/kernel/debug/tracing/latency_trace
# Find interrupt storms (IRQ firing faster than expected)
perf stat -e irq:irq_handler_entry -a sleep 5 | grep "irq_handler"
Diagnosing spurious interrupts:
# Spurious interrupts appear in /proc/interrupts as "ERR" counter
grep ERR /proc/interrupts
# Increment means a spurious interrupt occurred (device raised IRQ,
# but no handler claimed it). Common cause: IRQ sharing with mismatched EOI timing.
Security Implications
Interrupt handler as privilege escalation path: Any kernel code running during interrupt handling runs at ring 0. Vulnerabilities in interrupt handlers or in the interrupt routing/management code (APIC driver, IRQ remapping) can lead to ring-0 code execution. The interrupt stack is a separate allocation — stack overflows in interrupt context are detected by CONFIG_VMAP_STACK.
Interrupt injection from VMs: A compromised guest VM in a virtualized environment could potentially trigger unexpected interrupts on the host via APIC misconfiguration. Intel VT-d interrupt remapping (IR) prevents DMA-based interrupt injection by ensuring that MSI writes from PCIe devices are validated through an Interrupt Remapping Table before delivery.
APIC as an attack vector (historical): CVE-2010-5313 and related bugs showed that improper handling of APIC timer interrupts in KVM could cause the host kernel to dereference invalid memory. Modern KVM versions have extensive validation of APIC state transitions.
NMI (Non-Maskable Interrupt): NMIs cannot be masked by software (hence the name). They are delivered even when IF=0. An NMI handler that is not re-entrant and is hit by a second NMI causes a double NMI, which corrupts state. Linux uses an NMI nesting detection mechanism and a separate NMI stack to handle this. NMIs are used for hardware watchdogs (NMI watchdog, nmi_watchdog=1 kernel parameter) and for hardware error reporting (MCE, PMU overflow).
Performance Implications
Interrupt overhead: Each interrupt invocation costs roughly 1–3 microseconds (IDT lookup, stack switch, handler, EOI, return). At 100K interrupts/second, this is 100–300ms/second of CPU time spent on interrupt overhead alone — 10–30% of one core.
NAPI (New API) for networking: Linux's NAPI (include/linux/netdevice.h) avoids this overhead for high-throughput networking. On the first packet, the NIC fires an interrupt. The interrupt handler disables the NIC interrupt and schedules a NAPI poll. The poll function runs in softirq context, processing up to budget packets before re-enabling the interrupt. This converts interrupt-driven to poll-driven reception under load, capping interrupt rate regardless of packet arrival rate.
Interrupt coalescence: NICs support hardware interrupt coalescing (configurable via ethtool -C): fire an interrupt only after N packets or T microseconds. This reduces interrupt rate at the cost of added latency.
# Check current coalescing settings
ethtool -c eth0
# Set: fire interrupt after 50 packets or 50 microseconds
ethtool -C eth0 rx-frames 50 rx-usecs 50
Failure Modes and Real Incidents
Interrupt storm causing system hang (common with buggy drivers): A device driver that incorrectly acknowledges interrupts (or doesn't acknowledge them at all) causes the hardware to re-fire the interrupt immediately after the handler returns. The CPU enters an infinite loop of interrupt delivery, starving all other work. The symptom is 100% kernel CPU time and complete system unresponsiveness. Mitigation: Linux's spurious interrupt detection (kernel/irq/spurious.c) disables an IRQ after it fires 100,000 times with no handler claiming it.
AWS EC2 network interrupt latency regression (2017): A change to interrupt affinity management in a kernel update caused NIC interrupt handlers to be processed on CPUs distant from the application's CPU, increasing network latency for EC2 instances. Root cause: irqbalance was rebalancing during traffic bursts, moving IRQs away from hot CPUs. Fix: static IRQ pinning with irqbalance --banirq.
Twitter's NMI watchdog latency spikes (2012): Under high load, Twitter's production machines showed periodic latency spikes. Investigation with ftrace revealed that the NMI watchdog was firing on CPUs during critical sections (spinlocks held), adding latency to those sections. The NMI watchdog uses the PMU overflow interrupt to detect soft lockups. Under high PMU event rates, this caused unexpected NMIs during timing-sensitive code paths.
Modern Usage
eBPF interrupt tracing: bpftrace can trace individual interrupt events with near-zero overhead:
bpftrace -e '
tracepoint:irq:irq_handler_entry {
@start[args->irq] = nsecs;
}
tracepoint:irq:irq_handler_exit {
@latency = hist(nsecs - @start[args->irq]);
delete(@start[args->irq]);
}'
DPDK interrupt-free operation: DPDK-based applications run a polling loop on isolated CPUs, continuously reading the NIC RX queues without ever using interrupts. This reduces latency to sub-microsecond at the cost of dedicating entire CPU cores to polling (spinning at 100% CPU). Interrupts are still used for control-plane operations but never for the data plane.
XDP (eXpress Data Path): Linux's XDP framework runs a small eBPF program in the NIC driver's interrupt handler (before NAPI even runs), enabling packet filtering, load balancing, and DDoS mitigation at the earliest possible point in the interrupt path.
Future Directions
- Interrupt-free I/O at scale: io_uring's
IORING_SETUP_SQPOLLand NVMe's poll queues enable storage I/O without interrupt overhead. The trend is toward polling for hot paths, interrupts for idle/low-load detection. - Adaptive interrupt moderation: Dynamic adjustment of interrupt coalescing based on real-time latency measurements, rather than static tuning. Intel's "Adaptive ITR" (Interrupt Throttle Rate) in e1000e/igb/ixgbe drivers does this already.
- Hardware interrupt delivery to VMs: PCIe SR-IOV (Single Root I/O Virtualization) and Posted Interrupts (Intel VT-d Posted Interrupts) allow device interrupts to be delivered directly to a guest VM's Local APIC without hypervisor involvement, reducing VM network/storage latency.
Exercises
-
Run
cat /proc/interruptson a Linux system. Identify: (a) the IRQ for the primary NIC, (b) which CPU core handles the most interrupts, (c) any shared IRQ lines (multiple drivers on one entry). Now set the NIC's IRQ affinity to only CPU 0 using/proc/irq/N/smp_affinityand observe the change withwatch cat /proc/interrupts. -
Write a minimal Linux kernel module that registers a timer using
timer_setup()andmod_timer()to fire every second. In the timer callback, increment a counter and log it withprintk. Observe the counter value indmesg. Note: timer callbacks run in softirq context, not interrupt context — what does this mean for what you can do in the callback? -
Use
bpftrace -e 'tracepoint:irq:irq_handler_entry { @[args->name] = count(); }' --timeout 5to count interrupt handler invocations by name over 5 seconds. Calculate the interrupt rate per second for the top interrupt source. Is this consistent with whatcat /proc/interruptsshows? -
Configure NIC interrupt coalescing on a Linux system using
ethtool -C eth0 rx-usecs 0 rx-frames 1(minimum coalescing = maximum interrupt rate). Run a network benchmark (iperf3). Compare CPU usage and latency vs.rx-usecs 50 rx-frames 50. Explain the tradeoff. -
Read
kernel/irq/spurious.cin the Linux source. Findnote_interrupt(). Under what conditions does Linux disable an IRQ? What isIRQPF_PERCPU_DEVID? Why does the kernel need a per-CPU device ID for some IRQs?
References
- Linux kernel source:
arch/x86/kernel/irq.c,arch/x86/kernel/apic/,kernel/irq/,include/linux/interrupt.h,drivers/pci/msi.c - Intel 64 and IA-32 Architectures Software Developer's Manual, Vol. 3A, Chapters 10–11 (APIC and Interrupts)
- Linux kernel documentation:
Documentation/core-api/genericirq.rst - Thomas Gleixner, "genirq — The Generic Interrupt Handling Layer", Kernel Summit 2006
- Brendan Gregg, Systems Performance, 2nd ed., Chapter 6 (CPUs) — interrupt analysis
- Robert Love, Linux Kernel Development, Chapter 7 (Interrupts and Interrupt Handlers)
- NAPI documentation:
Documentation/networking/napi.rst - MSI/MSI-X: PCI Express Base Specification, Section 6.1 (Interrupt Signaling)
ethtoolman page andDocumentation/networking/scaling.rst(RSS, multi-queue)- PREEMPT_RT patches: https://wiki.linuxfoundation.org/realtime/start