Linux device driver notes (v) Interrupt processing

Source: Internet
Author: User

< a > Interrupt processing process is as follows:


1, when the interrupt occurs, the CPU executes the exception vector VECTOR_IRQ code.

2, in the VECTOR_IRQ, will eventually call the interrupt processing of the total entry function Asm_do_irq.

3. ASM_DO_IRQ calls the HANDLE_IRQ in the IRQ_DESC array item according to the interrupt number.

4. HADNLE_IRQ uses the functions in the chip member to set up the hardware, such as clearing interrupts, interrupting interrupts, re-enabling interrupts, and so on.

5. Handle_irq invokes the handler function that the user registers in the action list one by one.


< two > installation interrupt handling Routines


function to register/release interrupts :

int REQUEST_IRQ (unsigned int IRQ, irqreturn_t (*handler) (int, void *, struct pt_regs*), unsigned long flags,

const char *dev_name, void *dev_id);

void Free_irq (unsigned int irq, void *dev_id);


unsigned int IRQ: The requested interrupt number

Irqreturn_t (*handler) (int, void *, struct pt_regs*): Installed interrupt handler function pointer

Unsigned long flags: Interrupt management about bitmask options, how interrupts are triggered, such as sa_interrupt, SA_SHIRQ, etc.

const char *dev_name: string passed to Request_irq, break name

void *dev_id: This pointer is used only for shared interrupt signal lines. When sharing is not used, dev_id is set to null.


Interrupt processing routines can be installed when the driver is initialized or when the device is first opened. However, given the limited interruption of resources, the correct location for calling REQUEST_IRQ should be before the device is first opened, and the hardware is told to generate interrupts. The location of the call to Free_irq is the last time the device was shut down, and the hardware was told not to interrupt the processor.


< three > implementing interrupt handling Routines


The interrupt-handling routine is actually a C-function program, but it has the following characteristics because it occurs within the interrupt time:

1. The processing routine cannot send or receive data to the user space because it is not executed in the context of any process.

2, the processing routine can not do any operation that may occur hibernate, such as Call Wait_event, lock a semaphore, etc.

3, the processing routine cannot call the Schdule function.

The function of the interrupt processing routine is to feed information about the interrupt reception to the device, and to read or write the data according to the different meanings of the interrupt being served. One of its typical tasks is that if an interrupt notifies a process that an event has been awaited, such as the arrival of a new data, the process of hibernation on that device is awakened.

Whether fast or slow-processing routines, programmers should write processing routines that perform as short a time as possible. If you need to perform a long computation task, the best way is to use Tasklet or the Task force to schedule the calculation task in a more secure time.


parameters and return values for interrupt handling routines irqreturn_t (*handler) (int, void *, struct pt_regs*) :

int IRQ: Interrupt number

void *dev_id: A customer data type is the private data that is available to the driver, and the void * parameter passed to the REQUEST_IRQ function is returned to the processing routine as a parameter when the interrupt occurs. In general, we will pass a pointer to the data structure of our device for dev_id. For example:

static irqreturn_t sample_interrupt (int irq, void *dev_id, struct pt_regs) {          struct Sample_dev *dev = dev_id;          ......} /* The typical open code associated with this case threads is as follows: */static void Sample_open (struct inode *inode, struct file *filp) {          struct Sample_dev *dev = HWInfo + MINOR (inode->i_rdev);          REQUEST_IRQ (DEV->IRQ, sample_interrupt, 0, "sample", (void *) dev);          ... return 0;}
struct Pt_reg *regs: rarely used.

There are three kinds of return values: Irq_handled;irq_none;irq_retval (HANDLED);


To disable and enable interrupts:

Sometimes the device driver must block the occurrence of interrupts within a single time. Disabling interrupts is divided into disabling individual interrupts and disabling all interrupts.

Disabling a single interrupt

#include <asm/irq.h>

void Disable_irq (int IRQ);

void Disable_irq_nosync (int IRQ);

void Enable_irq (int IRQ);

Disable all interrupts

#include <asm/irq.h>

void Local_irq_save (unsigned long flags);

void local_irq_disable (void);

void Local_irq_restore (unsigned long flags);

void local_irq_enable (void);


< four > top half and bottom part


One of the main problems with interrupt handling is how to accomplish time-consuming tasks within a processing routine. A certain amount of work needs to be done for a corresponding device outage, but the interrupt processing routine needs to be terminated as soon as possible, and the endpoint cannot be blocked for too long, and the two requirements conflict with each other. Linux solves this problem by dividing the interrupt processing routines into two parts. The part that is called the top half is the actual response interrupt routine, which is the interrupt routine registered with REQUEST_IRQ, and the so-called bottom half is a routine that is dispatched by the top half and executed in a later, more secure time. The biggest difference between the top half and bottom half processing routines is that when the bottom half of the processing routine executes, all interrupts are open-this is called a more secure time to run.

The typical case is that the top half holds the device's data into a device-specific buffer and dispatches its bottom half, and then exits, this operation is very fast. The bottom half then performs other necessary work, such as waking up the process, initiating additional I/O operations, and so on. This allows the top half to continue to serve new interrupts during the bottom half of the work.

There are two different mechanisms for the Linux kernel to implement the bottom half: tasklet and work queues. Tasklet is usually the preferred mechanism for the bottom half of processing because it is very fast, but all Tasklet codes must be atomic. The work queue has a higher latency, but allows hibernation.

Tasklet: Tasklet is a special function that can be determined by the system in a security moment when the software interrupt context is scheduled to run.

Use the macro Declare_tasklet declaration tasklet:declare_tasklet (name, function, data), where the parameter name is the name given to Tasklet, A function is one that is called when executing tasklet (it takes a unsigned long parameter and returns void), and data is a unsigned long value that is passed to the Tasklet function.

The function tasklet_schedule is used to dispatch a tasklet run. Examples are as follows:

void Example_do_tasklet (unsigned long) {   ...} Declare_tasklet (Example_tasklet, Example_do_tasklet, 0); irqreturn_t example_interrupt (int irq, void *dev_id, struct PT _regs *regs) {     ...     Tasklet_schedule (&example_tasklet);     ......}
Work queues: A job queue invokes a function at some time in the future, in the context of a particular worker process. Because the work queue function runs in the context of the process, you can hibernate if necessary. Work Queue General Program writing examples are as follows:

static struct Work_struct example_workqueue;init_work (&example_workqueue, (Void (*) (void *)) Example_do_tasklet, NULL); irqreturn_t example_interrupt (int irq, void *dev_id, struct pt_regs *regs) {     ...     Schedule_work (&example_workqueue);     ......}


< five > Interrupt sharing

Install shared processing routines: just like ordinary non-shared interrupts, shared interrupts are also installed through REQUEST_IRQ, but in two different ways:

1. When the request is interrupted, the SA_SHIRQ bit in the flags parameter must be specified.

2. The dev_id parameter must be unique. Any pointer to the address space of the specified module can be used, but dev_id cannot be set to NULL.

When a shared interrupt is requested, REQUEST_IRQ succeeds if one of the following conditions is met:

1, interrupt signal line idle

2. Any processing routine that has registered the interrupt signal line also identifies that the IRQ is shared.

There is one thing to be careful with drivers that use shared processing routines: You cannot use ENABLE_IRQ and DISABLE_IRQ.





Related Article

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.