Chapter VII interrupt and interrupt handling
This chapter describes the Linux core interrupt handling process. Although the core provides general mechanisms and interfaces for interrupt processing, most of the interrupt processing details are related to the CPU architecture.
Figure 7.1 logic diagram of the interrupted route
Linux uses a variety of different hardware to execute many different tasks. Including video devices that drive displays and IDE devices that drive hard disks. We can synchronously drive these devices, that is, we can send a request to execute a group of operations (such as writing a piece of memory data to the disk) and wait until the execution is complete. This method can work, but the efficiency is very low, because the operating system must wait for each operation to complete, so the operating system will spend a lot of time on "Waiting. A more effective way is to execute the request and then execute other tasks. When the device completes the request, it then notifies the operating system through interruption. In this way, multiple unfinished tasks can exist simultaneously in the system.
No matter what the CPU is doing, some necessary hardware support must be provided to interrupt the device. Almost all general-purpose processors such as alpha AXP use an approximate method. Some physical pins of the CPU are designed to change the voltage (for example, from + 5 V to-5 V), causing the CPU to stop the current job and start executing the special code for handling the interrupt: the interrupt handler. One of these pins is connected to a periodic clock and receives an interruption every 1‰ seconds. Other pins can be connected to other devices in the system, such as the SCSI controller.
The system often uses the interrupt controller to group device interruptions before sending signals to the CPU interrupt pin. This reduces the number of interrupt pins on the CPU and increases the flexibility of the system design. The interrupt controller controls the interrupt by shielding and status registers. You can enable or disable the interruption by setting some bits in the shield register. You can read the Status Register to obtain the interruption in the active state of the system.
Some interruptions in the system are hard-wired. For example, the periodic timer of the real-time clock may be fixed to Pin 3 of the interrupt controller. Other pins connected to the controller can only be determined by the Control card inserted into the specific ISA or PCI slot. For example, pin 4 in the interrupt controller may be connected to the PCIe slot No. 0, but an Ethernet card may be inserted in the slot one day and changed to the SCSI Controller in a few days. In short, each system has its own interrupt routing mechanism, and the operating system should be able to handle these situations flexibly.
Most modern general-purpose microprocessors use an approximate method to handle interruptions. When a hardware interruption occurs, the CPU stops executing the current command and jumps to the memory where the Interrupt Processing code or interrupt processing code instruction branch is included. This code is executed in a special CPU mode: interrupt mode. Normally, no other interruptions occur in this mode. However, there are exceptions. Some CPUs classify the interrupt priority, and higher-priority interruptions may occur. This means that the first-level interrupt processing code must be carefully written, and the interrupt processing process should have its own stack, this allows you to store the CPU execution status (General registers and context of all CPUs) before the process is interrupted ). Some CPUs have a set of special registers-they exist only in the interrupt mode and can be used in the interrupt mode to save the execution context required for execution.
After the interrupt processing is completed, the CPU status will be retained and the interrupt will be released. The CPU will continue to do the work before the interruption occurs. The more refined the Interrupt Processing code, the better. This will reduce the time and frequency of the operating system blocking on the interrupt.
7.1 Programmable Interrupt Controller
System designers are free to choose the interrupt structure. Generally, ibm pc compatibility uses Intel 82c59a-2 CMOS Programmable Interrupt Controller or its derivation. This controller was generated before the birth of the PC, and its programmability is reflected in those registers located in the well-known ISA memory location. Non-Intel systems, such as alpha AXP-based PCs, are not subject to these architecture constraints and often use different interrupt controllers.
Figure 7.1 shows two eight-bit controllers connected to each other. Each controller has a mask and interrupt Status Register: pic1 and pic2. The two shielded registers are located at isa I/O space 0x21 and 0xa1 respectively, and the status registers are located at 0x20 and 0xa0. A specific position in the shielding register will enable a certain interruption, and write 0 to block it. Unfortunately, the interrupt shield register is only written, so you cannot read the value you write. This also means that Linux must save a local copy of the write value of the shielded register. Generally, these stored values are modified in the interrupt enable and shield routines, and these full screen codes are written into registers each time.
When an interrupt occurs, the Interrupt Processing code reads the two interrupt status registers (ISR ). It regards ISR in 0x20 as a low 8-bit 16-bit interrupt register and ISR in 0xa0 as its high 8-bit. In this way, ISR 1st-bit interruption in 0xa0 will be considered as system interruption 9. Because the second digit on pic1 is used for hierarchical connection to pic2, it cannot be used for other purposes. Any interruption on pic2 will cause the second digit of pic1 to be placed.
7.2 initialize the data structure of Interrupt Processing
The core interrupt processing data structure is established when the device driver requests the system interrupt control. To do this, the device driver uses a set of Linux core functions to request interruptions, enabling interruption and blocking.
Each device driver will call these processes to register the address of the interrupt processing routine.
Some interruptions because the traditional PC architecture is fixed, the driver only needs to request its interruptions during its initialization. The drive of a floppy disk is used in this way; its interrupt number is 6 in total. Sometimes the device driver may not know the interrupt number used by the device. This is not a big problem for PCI device drivers. They can always know the disconnections. However, there is no convenient way to get the interrupt number for the driver of the ISA Device. Linux solves this problem by letting the device drivers detect their interrupt numbers.
The device driver first forces the device to cause an interruption. All unallocated interruptions in the system are enabled. In this case, the interrupt caused by the device can be sent out through the programmable interrupt controller. Linux then reads the interrupt Status Register and returns its content to the device driver. If the value is not 0, one or more interruptions occur in the detection. The device driver will then disable the detection and block all unallocated interruptions.
If the ISA Device Driver finds the IRQ of the device, you can request Device Control as usual.
PCI-based systems are more dynamic than ISA-based systems. The interrupt pin used by the ISA Device is usually set and fixed in the device driver by a jumper on the hardware device. When the system starts and initializes PCI, the pci bios or PCI sub-system allocates the interruption. Each PCI device can use any interruption in A, B, C, or D. This interruption is determined when the device is established and usually the default interruption of most devices is. PCI interrupt connections A, B, C, and D in the PCI slot are correctly routed to the interrupt controller. Therefore, pin a on PCIe slot 4 may be routed to pin 6 on the interrupt controller, and Pin B on PCIe slot 7 may be routed to pin 7 on the interrupt controller.
How to route PCI interruptions depends entirely on the specific system. Generally, you can set the code to understand the PCI interrupt routing topology. On an Intel-based PC, the system BIOS code makes these settings at startup, and the Linux core completes this task in a system without BIOS (such as alpha AXP.
The PCI configuration code writes the pin number of the interrupt controller corresponding to each device to the PCI configuration header. You can obtain the PCI interrupt routing topology, the PCI slot number of the device, and the PCI interrupt pin setting code to determine the interrupt pin (or IRQ) number. The interrupt pins used by the device are stored in the interrupt connection domain reserved for this purpose in the PCI configuration header of the device. This information is read when the device driver is running and used to control interrupt requests from the Linux core.
There may be many PCI interrupt sources in the system, such as when using a PCI-PCI bridge. The number of these interrupt sources may exceed the number of pins in the system's programmable interrupt controller. In this case, the PCI device must share the interrupt number-one pin on the interrupt controller may be used by multiple PCI devices at the same time. In Linux, the first requestor of an interruption declares whether the interruption can be shared. Interrupted sharing causes an entry in the irq_action array to point to several irqaction data structures at the same time. When a shared interrupt occurs, Linux calls all the interrupt processing processes corresponding to the interrupt source. If a service is not interrupted, any device drivers that share the interrupt (all PCI device drivers) must prepare calls to the interrupt handling process.
7.3 interrupt handling
Figure 7.2 Linux Interrupt Processing Data Structure
A basic task of the Linux interrupt processing subsystem is to route the interrupt to the correct position in the Interrupt Processing code. The code must understand the interrupt topology of the system. For example, a floppy disk controller interrupt on Pin 6 on the interrupt controller must be identified and routed to the Interrupt Processing code driven by the system's floppy disk device. Linux uses a set of pointers to call addresses that contain routines that process system interruptions. These routines belong to the device driver corresponding to this device, and it is responsible for requesting the interruption of its request for each device driver during device initialization. Figure 7.2 shows an irq_action pointer pointing to a group of irqactions. Each irqaction data structure contains information related to the interrupt processing, including the address of the interrupt processing routine. The number of interruptions and how they are handled will change according to the changes in the architecture and system. The Interrupt Processing code in Linux is related to the architecture. This also means that the size of the irq_action array varies with the number of interrupt sources.
When an interrupt occurs, Linux first reads the interrupt Status Register in the Programmable Interrupt Controller to determine the interrupt source and converts it to the offset value in the irq_action array. For example, the interrupt controller Pin 6 from the floppy controller is converted into 7th pointers in the Interrupt Processing Array. If there is no corresponding interrupt processing process for this interrupt, the Linux core will record this error, otherwise it will call the interrupt processing routine in all irqaction data structures corresponding to this interrupt source.
When Linux core calls the interrupt handling process of the device driver, the cause of the interruption and corresponding solutions must be identified. To find out the cause of the interruption, the device driver must read the status register on the device where the interruption occurs. The device may report an error or the processing of the notification request has been completed. For example, the floppy disk controller may report that it has completed the correct positioning of a sector by the floppy disk reading head. Once the cause of the interruption is determined, the device driver must complete more work. In this case, the Linux core will postpone these operations. This avoids the CPU from spending too much time in the interrupted mode. We will discuss the driver interruption in detail.
File translated from Tex by tth, Version 1.0.
Top of chapter, table of contents, show frames, no frames? 1996-1999 David a rusling copyright notice.
This chapter describes the Linux core interrupt handling process. Although the core provides general mechanisms and interfaces for interrupt processing, most of the interrupt processing details are related to the CPU architecture.
Figure 7.1 logic diagram of the interrupted route
Linux uses a variety of different hardware to execute many different tasks. Including video devices that drive displays and IDE devices that drive hard disks. We can synchronously drive these devices, that is, we can send a request to execute a group of operations (such as writing a piece of memory data to the disk) and wait until the execution is complete. This method can work, but the efficiency is very low, because the operating system must wait for each operation to complete, so the operating system will spend a lot of time on "Waiting. A more effective way is to execute the request and then execute other tasks. When the device completes the request, it then notifies the operating system through interruption. In this way, multiple unfinished tasks can exist simultaneously in the system.
No matter what the CPU is doing, some necessary hardware support must be provided to interrupt the device. Almost all general-purpose processors such as alpha AXP use an approximate method. Some physical pins of the CPU are designed to change the voltage (for example, from + 5 V to-5 V), causing the CPU to stop the current job and start executing the special code for handling the interrupt: the interrupt handler. One of these pins is connected to a periodic clock and receives an interruption every 1‰ seconds. Other pins can be connected to other devices in the system, such as the SCSI controller.
The system often uses the interrupt controller to group device interruptions before sending signals to the CPU interrupt pin. This reduces the number of interrupt pins on the CPU and increases the flexibility of the system design. The interrupt controller controls the interrupt by shielding and status registers. You can enable or disable the interruption by setting some bits in the shield register. You can read the Status Register to obtain the interruption in the active state of the system.
Some interruptions in the system are hard-wired. For example, the periodic timer of the real-time clock may be fixed to Pin 3 of the interrupt controller. Other pins connected to the controller can only be determined by the Control card inserted into the specific ISA or PCI slot. For example, pin 4 in the interrupt controller may be connected to the PCIe slot No. 0, but an Ethernet card may be inserted in the slot one day and changed to the SCSI Controller in a few days. In short, each system has its own interrupt routing mechanism, and the operating system should be able to handle these situations flexibly.
Most modern general-purpose microprocessors use an approximate method to handle interruptions. When a hardware interruption occurs, the CPU stops executing the current command and jumps to the memory where the Interrupt Processing code or interrupt processing code instruction branch is included. This code is executed in a special CPU mode: interrupt mode. Normally, no other interruptions occur in this mode. However, there are exceptions. Some CPUs classify the interrupt priority, and higher-priority interruptions may occur. This means that the first-level interrupt processing code must be carefully written, and the interrupt processing process should have its own stack, this allows you to store the CPU execution status (General registers and context of all CPUs) before the process is interrupted ). Some CPUs have a set of special registers-they exist only in the interrupt mode and can be used in the interrupt mode to save the execution context required for execution.
After the interrupt processing is completed, the CPU status will be retained and the interrupt will be released. The CPU will continue to do the work before the interruption occurs. The more refined the Interrupt Processing code, the better. This will reduce the time and frequency of the operating system blocking on the interrupt.
7.1 Programmable Interrupt Controller
System designers are free to choose the interrupt structure. Generally, ibm pc compatibility uses Intel 82c59a-2 CMOS Programmable Interrupt Controller or its derivation. This controller was generated before the birth of the PC, and its programmability is reflected in those registers located in the well-known ISA memory location. Non-Intel systems, such as alpha AXP-based PCs, are not subject to these architecture constraints and often use different interrupt controllers.
Figure 7.1 shows two eight-bit controllers connected to each other. Each controller has a mask and interrupt Status Register: pic1 and pic2. The two shielded registers are located at isa I/O space 0x21 and 0xa1 respectively, and the status registers are located at 0x20 and 0xa0. A specific position in the shielding register will enable a certain interruption, and write 0 to block it. Unfortunately, the interrupt shield register is only written, so you cannot read the value you write. This also means that Linux must save a local copy of the write value of the shielded register. Generally, these stored values are modified in the interrupt enable and shield routines, and these full screen codes are written into registers each time.
When an interrupt occurs, the Interrupt Processing code reads the two interrupt status registers (ISR ). It regards ISR in 0x20 as a low 8-bit 16-bit interrupt register and ISR in 0xa0 as its high 8-bit. In this way, ISR 1st-bit interruption in 0xa0 will be considered as system interruption 9. Because the second digit on pic1 is used for hierarchical connection to pic2, it cannot be used for other purposes. Any interruption on pic2 will cause the second digit of pic1 to be placed.
7.2 initialize the data structure of Interrupt Processing
The core interrupt processing data structure is established when the device driver requests the system interrupt control. To do this, the device driver uses a set of Linux core functions to request interruptions, enabling interruption and blocking.
Each device driver will call these processes to register the address of the interrupt processing routine.
Some interruptions because the traditional PC architecture is fixed, the driver only needs to request its interruptions during its initialization. The drive of a floppy disk is used in this way; its interrupt number is 6 in total. Sometimes the device driver may not know the interrupt number used by the device. This is not a big problem for PCI device drivers. They can always know the disconnections. However, there is no convenient way to get the interrupt number for the driver of the ISA Device. Linux solves this problem by letting the device drivers detect their interrupt numbers.
The device driver first forces the device to cause an interruption. All unallocated interruptions in the system are enabled. In this case, the interrupt caused by the device can be sent out through the programmable interrupt controller. Linux then reads the interrupt Status Register and returns its content to the device driver. If the value is not 0, one or more interruptions occur in the detection. The device driver will then disable the detection and block all unallocated interruptions.
If the ISA Device Driver finds the IRQ of the device, you can request Device Control as usual.
PCI-based systems are more dynamic than ISA-based systems. The interrupt pin used by the ISA Device is usually set and fixed in the device driver by a jumper on the hardware device. When the system starts and initializes PCI, the pci bios or PCI sub-system allocates the interruption. Each PCI device can use any interruption in A, B, C, or D. This interruption is determined when the device is established and usually the default interruption of most devices is. PCI interrupt connections A, B, C, and D in the PCI slot are correctly routed to the interrupt controller. Therefore, pin a on PCIe slot 4 may be routed to pin 6 on the interrupt controller, and Pin B on PCIe slot 7 may be routed to pin 7 on the interrupt controller.
How to route PCI interruptions depends entirely on the specific system. Generally, you can set the code to understand the PCI interrupt routing topology. On an Intel-based PC, the system BIOS code makes these settings at startup, and the Linux core completes this task in a system without BIOS (such as alpha AXP.
The PCI configuration code writes the pin number of the interrupt controller corresponding to each device to the PCI configuration header. You can obtain the PCI interrupt routing topology, the PCI slot number of the device, and the PCI interrupt pin setting code to determine the interrupt pin (or IRQ) number. The interrupt pins used by the device are stored in the interrupt connection domain reserved for this purpose in the PCI configuration header of the device. This information is read when the device driver is running and used to control interrupt requests from the Linux core.
There may be many PCI interrupt sources in the system, such as when using a PCI-PCI bridge. The number of these interrupt sources may exceed the number of pins in the system's programmable interrupt controller. In this case, the PCI device must share the interrupt number-one pin on the interrupt controller may be used by multiple PCI devices at the same time. In Linux, the first requestor of an interruption declares whether the interruption can be shared. Interrupted sharing causes an entry in the irq_action array to point to several irqaction data structures at the same time. When a shared interrupt occurs, Linux calls all the interrupt processing processes corresponding to the interrupt source. If a service is not interrupted, any device drivers that share the interrupt (all PCI device drivers) must prepare calls to the interrupt handling process.
7.3 interrupt handling
Figure 7.2 Linux Interrupt Processing Data Structure
A basic task of the Linux interrupt processing subsystem is to route the interrupt to the correct position in the Interrupt Processing code. The code must understand the interrupt topology of the system. For example, a floppy disk controller interrupt on Pin 6 on the interrupt controller must be identified and routed to the Interrupt Processing code driven by the system's floppy disk device. Linux uses a set of pointers to call addresses that contain routines that process system interruptions. These routines belong to the device driver corresponding to this device, and it is responsible for requesting the interruption of its request for each device driver during device initialization. Figure 7.2 shows an irq_action pointer pointing to a group of irqactions. Each irqaction data structure contains information related to the interrupt processing, including the address of the interrupt processing routine. The number of interruptions and how they are handled will change according to the changes in the architecture and system. The Interrupt Processing code in Linux is related to the architecture. This also means that the size of the irq_action array varies with the number of interrupt sources.
When an interrupt occurs, Linux first reads the interrupt Status Register in the Programmable Interrupt Controller to determine the interrupt source and converts it to the offset value in the irq_action array. For example, the interrupt controller Pin 6 from the floppy controller is converted into 7th pointers in the Interrupt Processing Array. If there is no corresponding interrupt processing process for this interrupt, the Linux core will record this error, otherwise it will call the interrupt processing routine in all irqaction data structures corresponding to this interrupt source.
When Linux core calls the interrupt handling process of the device driver, the cause of the interruption and corresponding solutions must be identified. To find out the cause of the interruption, the device driver must read the status register on the device where the interruption occurs. The device may report an error or the processing of the notification request has been completed. For example, the floppy disk controller may report that it has completed the correct positioning of a sector by the floppy disk reading head. Once the cause of the interruption is determined, the device driver must complete more work. In this case, the Linux core will postpone these operations. This avoids the CPU from spending too much time in the interrupted mode. We will discuss the driver interruption in detail.
Interrupt and interrupt handling