Linux Kernel interrupt implementation

Source: Internet
Author: User

 

Interrupted kernel implementation

I. interrupted use

The Linux kernel needs to manage all the hardware devices connected to the computer, which is undoubtedly part of it. To manage these devices, you must first communicate with them. Generally, there are two solutions to achieve the communication between the kernel and the device:

(1)Round Robin (Polling)Let the kernel regularly query the status of the device and then make corresponding processing;

(2)Interrupt (Interrupt)Enable the hardware to send signals to the kernel as needed (change the kernel to active hardware ).

The first solution will make the kernel do a lot of useless work, because Round Robin will always be executed cyclically repeatedly, consuming a lot of CPU time, so the efficiency is low, so the second solution is generally used.

From the perspective of physics, interruption is an electrical signal generated by hardware devices and directly sent to the input pin of the interrupt controller (such as 8259a, then the interrupt controller sends the corresponding signal to the processor. Once the processor detects this signal, it will interrupt the work it is currently processing and then process the interruption. After that, the processor will notify the operating system that an interruption has occurred, so that the operating system can properly handle the interruption.

Different devices have different interruptions, and the same device may be disconnected temporarily. Each interruption is identified by a unique number, which is usually called an interrupt request line.

Ii. Categories of interruptions

There are two types of interruptions: synchronization and one-step interruption:

(1) Synchronization interruption: it is generated by the CPU control unit during command execution. It is called synchronization because the CPU is interrupted only after a command is executed, it does not occur during code instruction execution, such as system calls or invalid commands.

(2) asynchronous interrupt: it refers to the random generation by other hardware devices according to the CPU clock signal, that is, the interrupt can occur between commands, such as a keyboard interrupt. The arrival of these hardware interruptions is unpredictable for the processor and must respond in a timely manner, so it will stop the current process.

The following content mainly discusses asynchronous interrupt.

Iii. Interrupt Descriptor Table

The Linux kernel interrupt processing model structure is as follows:

The following table analyzes the data structure involved in this table:

(1) the Linux kernel defines the Interrupt Routine Descriptor Table named irq_desc, which can be found in the File Include/Linux/IRQ. h:

Struct irqdesc irq_desc [nr_irqs]; // nr_irqs indicates the number of interrupt sources.

Structirq_desc_t {

Init flags;

Struct irqaction * action;

};

(2) irq_desc is an array pointing to the irq_desc_t structure. The irq_desc_t structure is the descriptor of each device interruption service routine. The member action in the irq_desc_t struct points to the irqaction struct linked list corresponding to the interrupt number. The irqaction struct is defined as follows:

/* Include/Linux/interrupt. H */

Struct irqaction {
Irq_handler_t handler;/* points to the interrupted service program */
Unsigned long flags;/* interrupt flag */
Unsigned long mask;/* Interrupt Mask */
Const char * Name;/* I/O device name
Void * dev_id;/* device ID */
Struct irqaction * Next;/* points to the next descriptor */
Int IRQ;/* IRQ line */
Struct proc_dir_entry * dir;/* the descriptor pointing to the/proc/IRQ/n directory related to irqn */
};

The key handler Member points to the interrupt service program of the device, which is established when request_irq is executed.

(3) During driver initialization, if an interrupt is used, the request_irq () function is usually called to create the irqaction struct corresponding to the driver, register it with irq_desc [irq_num]-> action linked list. Iqr_num is the interrupt number applied by the driver.

The following is a prototype of the request_irq () function:
/* Kernel/IRQ/manage. C */
Int request_irq (unsigned int IRQ,
Irqreturn_t (* Handler) (INT, void *, struct pt_regs *),
Unsigned long irqflags,
Const char * devname,
Void * dev_id );

The IRQ parameter is the device interruption identifier. when registering with the irq_desc [] array, it is used as the subscript of the array. Write the first address of the irqaction struct whose interrupt number is IRQ to irq_desc [IRQ]-> action. In this way, the device's interrupt request number is associated with the device's interrupt service routine irqaction.

In this way, after the CPU receives the interrupt request, it can find the interrupt service program of the device through irq_desc [] based on the interrupt number. Shows the process.

4. Shared interruptions

The iqraction struct of different devices that share the interrupt will be added to the irqaction linked list pointed by the action Member of the irq_desc struct corresponding to the interrupt number. When the kernel is interrupted, it calls all handler functions in the linked list in turn. Therefore, if the driver needs to use the shared interrupt mechanism, the interrupt handler must be able to identify whether its own hardware is interrupted. It is usually determined by reading the interrupt flag Flag provided by the hardware device.

When kernel sharing is interrupted, request_irq must provide the dev_id parameter and the value of dev_id must be unique. So what exactly is the use of the unique dev_id value provided here?

The kernel does not determine which device on the shared interrupt line has an interruption. It cyclically executes all interrupt processing functions (irqaction-> handler functions) registered online ). Therefore, the irqaction-> handler function is responsible for identifying whether your hardware device has encountered an interruption and then executing the interrupt processing function. It is usually determined by reading the interrupt flag Flag provided by the hardware device.

Now that the kernel cyclically executes all irqaction-> handler functions for online registration of the interrupt, it submits the process of identifying which hardware device has an interrupt to the interrupt handler itself, what is the use of the dev_id parameter of request_irq?

(1) Use dev_id when the interrupt handler is released. When calling free_irq to deregister the interrupt handler function (the interrupt handler function is also canceled when the driver is uninstalled ), because dev_id is unique, you can use it to determine how to delete a specified one from multiple interrupt handlers on the shared interrupt line. Without this parameter, it is impossible for the kernel to know which handler is to be deleted for the given interrupt line.

(2) Pass the device struct that uses the interrupt handler to the interrupt handler. First, let's look at two basic conditions:

1) Each device struct in the kernel must be unique, so it meets the unique dev_id requirement.
2) The dev_id parameter is passed to the interrupted service program in the event of an interruption.
A typical interrupted service program is defined as follows:
Static irqreturn_t intr_handler (int irq, void * dev_id, struct pt_regs * regs );
That is, the dev_id parameter of request_irq is passed to the dev_id of the interrupted service program. Therefore, the device structure of the driver can be passed to the interrupt service program through dev_id. There are two main roles to do this:

1) The interrupt service program may use the information in the device struct. Therefore, we can use this mechanism to pass the device structure to the dev_id parameter of request_irq, this is a common approach for most drivers.

2) As mentioned above, if shared interrupt is used, the interrupt handler itself needs to be able to identify whether its own device has encountered an interrupt. This is usually determined by reading the interrupt flag signs provided by the hardware device.

The device struct defined in the driver usually contains the IO address of the device. With the offset, you can calculate the IO address information of the interrupt Status Register and the interrupt flag Flag flag. Therefore, another function of passing the device struct to the device interrupt handler through dev_id is to use the shared interrupt function to read the device structure (dev_id) the flag address information provided in the interrupt flag is used to determine whether the device is interrupted, and then determine whether to continue or skip to the next irqaction-> handler function and then determine whether to execute. Of course, if you already know the IO address of the device interrupt Status Register, you can also select readl to determine the address information directly.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.