Interrupt handling depends on the type of interrupt. three main classes of interrupts: | |||||||
I/O interrupts | |||||||
An I/O device requires attention; the corresponding interrupt handler | |||||||
must query the device to determine the proper course of action. | |||||||
Timer interrupts | |||||||
Some timer, either a local APIC timer or an external timer, has issued an interrupt; | |||||||
this kind of interrupt tells the kernel that a fixed-time interval has elapsed. | |||||||
These interrupts are handled mostly as I/O interrupts; | |||||||
Interprocessor interrupts | |||||||
A CPU issued an interrupt to another CPU of a multiprocessor system | |||||||
I/O Interrupt Handling | |||||||
Interrupt handler flexibility is achieved in two distinct ways | |||||||
IRQ sharing | |||||||
IRQ dynamic allocation | |||||||
Linux divides the actions to be performed following an interrupt into three classes: | |||||||
Critical | |||||||
Noncritical | |||||||
Noncritical deferrable | |||||||
all I/O interrupt handlers perform the same four basic actions: | |||||||
1. Save the IRQ value and the register's contents on the Kernel Mode stack. | |||||||
2. Send an acknowledgment to the PIC that is servicing the IRQ line, | |||||||
thus allowing it to issue further interrupts | |||||||
3. Execute the interrupt service routines (ISRs) associated with all the devices that share the IRQ. | |||||||
4. Terminate by jumping to the ret_from_intr( ) address. | |||||||
Interrupt vectors | |||||||
physical IRQs may be assigned any vector in the range 32-238. | |||||||
However, Linux uses vector 128 to implement system calls. | |||||||
The IBM-compatible PC architecture requires that some devices | |||||||
be statically connected to specific IRQ lines. In particular: | |||||||
· The interval timer device must be connected to the IRQ 0 line | |||||||
· The slave 8259A PIC must be connected to the IRQ 2 line | |||||||
(although more advanced PICs are now being used, Linux still supports 8259A-style PICs) | |||||||
· The external mathematical coprocessor must be connected to the IRQ 13 line | |||||||
· In general, an I/O device can be connected to a limited number of IRQ lines. | |||||||
There are three ways to select a line for an IRQ-configurable device: | |||||||
· By setting hardware jumpers (only on very old device cards). | |||||||
· By a utility program shipped with the device and executed when installing it. | |||||||
Such a program may either ask the user to select an available IRQ number | |||||||
or probe the system to determine an available number by itself | |||||||
· By a hardware protocol executed at system startup. | |||||||
Peripheral devices declare which interrupt lines they are ready to use; | |||||||
IRQ data structures | |||||||
irq_desc_t | |||||||
irq_desc | |||||||
/* | |||||||
* Interrupt controller descriptor. This is all we need | |||||||
* to describe about the low-level hardware. | |||||||
*/ | |||||||
struct hw_interrupt_type { | |||||||
const char * typename; | |||||||
unsigned int (*startup)(unsigned int irq); | |||||||
void (*shutdown)(unsigned int irq); | |||||||
void (*enable)(unsigned int irq); | |||||||
void (*disable)(unsigned int irq); | |||||||
void (*ack)(unsigned int irq); | |||||||
void (*end)(unsigned int irq); | |||||||
void (*set_affinity)(unsigned int irq, cpumask_t dest); | |||||||
}; | |||||||
typedef struct irq_desc { | |||||||
unsigned int status; | /* IRQ status */ | ||||||
hw_irq_controller *handler; | |||||||
struct irqaction *action; | /* IRQ action list */ | ||||||
unsigned int depth; | /* nested irq disables */ | ||||||
unsigned int irq_count; | /* For detecting broken interrupts */ | ||||||
unsigned int irqs_unhandled; | |||||||
spinlock_t lock; | |||||||
} ____cacheline_aligned irq_desc_t; | |||||||
/* | |||||||
* IRQ line status. | |||||||
*/ | |||||||
#define IRQ_INPROGRESS | 1 | /* IRQ handler active - do not enter! */ | |||||
#define IRQ_DISABLED | 2 | /* IRQ disabled - do not enter! */ | |||||
#define IRQ_PENDING | 4 | /* IRQ pending - replay on enable */ | |||||
#define IRQ_REPLAY | 8 | /* IRQ has been replayed but not acked yet */ | |||||
#define IRQ_AUTODETECT | 16 | /* IRQ is being autodetected */ | |||||
#define IRQ_WAITING | 32 | /* IRQ not yet seen - for autodetection */ | |||||
#define IRQ_LEVEL | 64 | /* IRQ level triggered */ | |||||
#define IRQ_MASKED | 128 | /* IRQ masked - shouldn't be seen again */ | |||||
#define IRQ_PER_CPU | 256 | /* IRQ is per CPU */ | |||||
void disable_irq(unsigned int irq) | |||||||
void enable_irq(unsigned int irq) | |||||||
void __init init_IRQ(void) | |||||||
Understanding the linux kernel-ch4-Interrupt Handling
最新推荐文章于 2021-05-10 14:20:23 发布