Embedded Linux driver development] [XII article take you interrupt Linux Development

  Can a thinking person, that is really a boundless power of the people.


A, Cortex-A7 series introduction interrupt

  Cortex-A7 cores only eight abort, abort the eight interrupt vector table is as follows:

Vector address terminal type Interrupt Mode
0x00 Reset interrupt (Rest) Privileged mode (SVC)
0x04 Undefined instruction interrupt (Undefined Instruction) Pause mode undefined instruction (Undef)
0x08 Soft interrupt (Software Interrupt, SWI) Privileged mode (SVC)
0x0C Instruction prefetch abort interrupt (Prefetch Abort) Suspend mode
0x10 Data Access abort interrupt (Data Abort) Suspend mode
0x14 Unused (Not Used) Unused
0x18 IRQ 中断(IRQ Interrupt) External interrupt mode (IRQ)
0x1C FIQ interrupt (FIQ Interrupt) Fast interrupt mode (FIQ)

  Cortex-A7 interrupt controller called the GIC. [Analogy] STM32 NVIC the GIC can switch interrupt, set the interrupt priority! Cortex-A7 used version is GIC V2, this version supports up to eight cores. GIC will be numerous interrupt sources into three categories: SPI, PPI, SGI. We focus on SPI (Shared Peripheral Interrupt, shared interrupts). Those are all external interrupt SPI interrupt (attention! SPI bus that is not interrupted). Such key interrupt, the serial port interrupt, etc., all of these interrupts can be processed Core, Core is not limited to the specific.

  CPU Cortex-A core of all external interrupts belong to this IRQ interrupts, when any of the external interrupt occurred will trigger IRQ interrupts. In IRQ interrupt service function which can be read from the specified register to determine what specifically happened is interrupted, so we focus on the IRQ interrupt!

  To distinguish different interrupt introduced terminal number. SPI (shared interrupts) assigned to interrupt number in the range of ID32 ~ ID1019, a total of 998 terminal numbers. Like GPIO interrupt, serial port interrupts these external interrupts are there, as to correspond to a specific ID which interrupt, then by the semiconductor manufacturers to define the actual situation.

Two, Linux interrupt handling

  Linux system to interrupt the evolution of treatment is to use kernel threads to handle interrupts. About processes and threads, there are also brief knowledge under process and thread.

  • Linux unit in resource allocation is the process, the unit is scheduled thread.
  • In a process where there may be multiple threads that share open file handles, global variables, and so on.
  • These threads are independent of each other between, "run", that is: each thread has its own stack.

  Linux system contains not only the hardware interrupt, software interrupt there. Us one by one!

2.1 hardware interrupt

Here Insert Picture Description
For Linux, a hardware interrupt is generated, called "hardware interrupt" (hard irq). The key interrupt, the serial port interrupt, and each has a hardware interrupt handler corresponding.

2.2 software interrupt

Here Insert Picture Description

  • When a software interrupt production?
    • Determined by software, for X number of software interrupt, just put its flag set to 1 to indicate the occurrence of the interrupt.
  • When a software interrupt handling?
    • Software interrupt Well, not so frantic, free and then deal with it better. What free time? You can not always wait for it? Linux systems, various hardware interrupts occur frequently, at least every 10ms timer interrupt occurs once, it takes a clever? After processing in hardware interrupt, software interrupt again ? I'll do!
  • What software interrupt?
    • Check the kernel source include / linux / interrupt.h
enum
{
	HI_SOFTIRQ=0,
	TIMER_SOFTIRQ,
	NET_TX_SOFTIRQ,
	NET_RX_SOFTIRQ,
	BLOCK_SOFTIRQ,
	IRQ_POLL_SOFTIRQ,
	TASKLET_SOFTIRQ,
	SCHED_SOFTIRQ,
	HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the
			    numbering. Sigh! */
	RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */

	NR_SOFTIRQS
};
  • How to trigger a software interrupt?
    • The core functions are raise_softirq, easily understanding is provided softirq_veq [nr] the flag.
extern void raise_softirq(unsigned int nr);
  • How to set a software interrupt handler?
extern void open_softirq(int nr, void (*action)(struct softirq_action *));

Mentioned later interrupted tasklet lower half is the use of software interrupt implementation.

2.3 interrupt handling principles
2.3.1 can not be nested interrupt handling

  Interrupt nesting sudden outbreak, then the stack will grow, it will eventually run out of the stack. Therefore, in order to prevent this from happening, but also to simplify the handling of the interrupt, the interrupt on Linux systems can not be nested: A i.e. before the current interrupt is not processed, an interrupt will not respond to other B (higher priority even though it ).

2.3.1 interrupt processing as quickly as possible

  In the single-chip system, assuming that interrupt handling is very slow, and that the application can not be executed during this time: The system is very inactive. In an SMP system, assuming that interrupt processing is slow, it is processing other threads on this interrupt to the CPU can not execute . In the process the interrupt, the CPU is not possible scheduling process, so the sooner the better interrupt handling to make other interrupt can be handled as soon as possible ── process scheduling is implemented by a timer interrupt .

  In the Linux system using interrupts, irq interrupt just for a registered interrupt handler handler.

  • Use request_irq registered Handler, the function prototype is as follows:
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
	    const char *name, void *dev)

  However, an interrupt handling is a lot to do, no way to speed up. For example, for key interrupt, we need to wait tens of milliseconds to eliminate mechanical jitter . Are you going to wait for the handler in it? For the computer, this is a very long period of time. How to do?

  At this time, "the bottom half" of thought process will be resulting.

2.4 to deal with things too much, split into: the top half, bottom half

  When an interrupt to spend a lot of time to process, the downside is it: at this time, other interrupts can not be processed . In other words, during this time, the system is shut interrupted. If an interrupt is to do so many things, we can split it into two parts: urgent, not urgent? In the handler function only in an emergency thing, and then re-open break, let the system to function properly; things that are not urgent, after reprocessing, handling interrupts is open.

Here Insert Picture Description
  Achieve lower half of the interruption There are many ways, the first to understand two major: tasklet (small task), work queue (job queue).

2.4.1 lower half is not too long to do time-consuming: tasklet

  Suppose we break into the top half, bottom half. When an interrupt occurs, the upper half of the lower half of the code when and how the
call?

  When the lower half of the more time-consuming but can tolerate, and its processing is relatively simple, can be used to deal with tasklet bottom half. tasklet is to use a software interrupt to achieve .

Here Insert Picture Description
Paste the code a glance:

Here Insert Picture Description
Use it to simplify the flow chart:

Here Insert Picture Description

  A hardware interrupt is assumed that the upper half of the function irq_top_half_A, the lower half irq_bottom_half_A. Use analysis of scenarios, in order to understand the essence of the above code.

  • . A hardware interrupt process A, no other interrupts occur :
    a beginning, preempt_count = 0;
    flowchart described above ① ~ ⑨ are sequentially executed, the upper half, the lower half of the code is executed once.

  • . B A hardware interrupt processing, again interrupt occurs A :
    start, preempt_count = 0;
    when performing the first ⑥, after an opening, the interrupt so that the CPU A again to the interrupt vector table.
    Note: At this time preempt_count equal to 1 and interrupt the lower half of the code is not running.
    And from ① CPU starts executing the interrupt again in the upper half of the code A:
    In the first step ① preempt_count equal to 2;
    in step ③ preempt_count equal to 1;
    the first step ④ preempt_count found equal to 1, it terminates the current interrupt processing 2nd ;
    Note: the focus here, after the second interruption occurred, interrupted the first processing step ⑦ first interruption. When this second breakpoint A processed, CPU will continue to carry out the first step ⑦.

It can be seen 2 times A hardware interrupt occurs, the upper half of its code is executed two times, but the lower half of the code is only
executed once. So, with a break of the upper half, lower half, while performing many to one relationship.

  • . C A hardware interrupt processing, again interrupt occurs B :
    start, preempt_count = 0;
    when performing the first ⑥, after an opening, the interrupt causes the CPU to jump to B again the interrupt vector table.
    Note: At this time preempt_count equal to 1, and the interruption A lower half of the code is not running.
    And from ① CPU starts executing the interrupt again in the upper half of the code B:
    In the first step ① preempt_count equal to 2;
    in step ③ preempt_count equal to 1;
    the first step ④ preempt_count found equal to 1, it terminates the current interrupt processing 2nd ;
    Note: the focus here, after the second interruption occurred, interrupted the first processing step ⑦ a first interruption of. When the 2nd B interrupt processing is completed, CPU will continue to carry out the first step ⑦.

It can be seen in the first ⑦ step in, it will go to the bottom half of interrupt execution of A, B will be interrupted to perform the lower half of.
So, more than the lower half of disruption, it is bringing together process.

to sum up:

  • a. processing interrupts can be divided into the upper half, lower half
  • b. interrupt half to handle urgent matter, it is performed in the state shut interrupted
  • c. interrupts the lower half, to handle time-consuming, less urgent matter, it is performed in a state where the opening break of
  • d. When interrupt the lower half of the implementation, there may be repeatedly interrupted, there is likely to happen again the same interrupt
  • e. interrupted after the implementation of the upper half, the lower half of the trigger processing interrupts
  • . F interrupts the upper half, the lower half of the execution process, you can not sleep: sleep interrupted, then, who is going after the scheduling process ah?
2.4.2 lower half too much to do and very complex: Work Queue (work queue)

  During the execution of an interrupt in the bottom half, although it is open interrupted during can handle all types of interrupts. But after all, the whole process interrupts not completed, during which APP is unenforceable . To assume that the lower part of the implementation of 1, 2 minutes, in which 1, 2 minutes in APP are unresponsive.

  Who can bear this?

  So, if the interruption is too time-consuming to do, then do not use the software interrupt, but should use kernel threads do: wake-up interrupt kernel threads in the upper half . Kernel threads are the same competition enforcement and APP, APP had the opportunity to perform, the system will not Caton.

Here Insert Picture Description

  This kernel thread is a system to help us create, usually kworker thread, the kernel has many such threads:

Here Insert Picture Description

  kworker threads go on "work queue" (work queue) a taken a "work" (work), it performs the function inside.

Then how do we use work, work queue it?

  • . a created work:

    • You have to write a function, then fill the structure with a work function. such as:
      Here Insert Picture Description
  • . B To perform this function, to submit work to the work queue can be:

    • The following functions will work to the system default work queue: system_wq, it is a queue.
      Here Insert Picture Description
  • c. Who will execute the function work in?

    • Not our business, schedule_work function will not work in the queue, but also to awaken kworker thread. At this time grab thread runs, it will remove the work from the queue, the function performed inside.
  • d. Who submitted work Queue to work ?

    • In the interrupt scenario, you can call the half schedule_work function interrupts.

to sum up:

  • a. very time-consuming interrupt processing, should go into thread
  • b. You can use work, work queue
  • c. In the upper half of the interrupt calls schedule_work function, trigger processing of work
  • d. Since it is running in a thread, and that the corresponding function can sleep.
2.5 New technologies: threaded irq

  The use of threads to handle interrupts, is nothing new. Use work can be achieved, but the need to define the work, calling schedule_work, good trouble ah.

  Too lazy too lazy, on this two-step you do not want to do. Well, the kernel is lazy service, and then popped a function:

Here Insert Picture Description
  You can only provide thread_fn, the system creates a kernel thread for this function. When an interrupt occurs, the kernel thread will execute this function.

  I say lazy joke, kernel developers do not care so much about lazy.

  Before coming to work with a threaded handle interrupts, a worker thread can only be performed by a CPU, more work interrupted by a single worker thread to process, in a single-CPU system can only be endured. However, in an SMP system, obviously there are so many CPU empty, but why let you squeeze in more interrupts this CPU?

  New technology threaded irq, are created for each interrupt a kernel thread ; multiple interrupts kernel threads can be assigned to multiple CPU on the implementation, this will improve the efficiency.

Three, Linux interrupt the important data on your system

Here Insert Picture Description

  You can figure above this figure, for Linux interrupt control systems are basically in place. The core of the structure is irq_desc, for ease of understanding before we said earlier, there is a break in the Linux kernel array for each hardware interrupt, there is an array of items, the array is irq_desc array.

Note: If the kernel is configured CONFIG_SPARSE_IRQ, it will use a radix tree (radix tree) to replace irq_desc array. SPARSE means "sparse", assuming that the size of the array 1000 uses only two array items, it is not a waste of thing? Therefore, in the case of interruption more "sparse" radix tree can be used instead of an array.

3.1 irq_desc array

  irq_desc structure include / linux / irqdesc.h defined in the main content as shown below:

Here Insert Picture Description

  Each entry in the array has a irq_desc function: handle_irq, as well as an action list. To understand them, we need to look at the interrupt structure diagram:

Here Insert Picture Description

  A figure above concern number of interrupts and B interrupt position!

  An external apparatus, the external apparatus B n share a GPIO interrupts, GPIO interrupts plurality converged GIC number A (General Interrupt Controller) is interrupted, GIC again interrupt the CPU. So when software processing is, in turn, first read the GIC get the interrupt number A, subdivided the GPIO interrupt B, which is a final judgment outside the chip was interrupted.

  Therefore, the processing function interrupt sources, there are three:

  • ① GIC handler:

  Suppose irq_desc [A] .handle_irq is XXX_gpio_irq_handler (XXX refers to the manufacturers), the function needs to read the GPIO controller chip, which is a breakdown occurs GPIO interrupt (assumed to be B), again calls irq_desc [B] .handle_irq .

  Note : irq_desc [A] .handle_irq subdivided interrupt B, call the corresponding irq_desc [B] .handle_irq. A CPU interrupt is apparently interrupted feel the top, when GIC interrupt the CPU, CPU reads the state GIC been interrupted A.

  • ② module interrupt handler:

  For example, module B GPIO interrupt issued to the GIC, its processing function is irq_desc [B] .handle_irq. BSP developers will set the corresponding processing function, generally handle_level_irq or handle_edge_irq, Judging from the name is used to handle level-triggered interrupts, edge-triggered interrupt.

  Note : Many causes B GPIO Interrupt occurs, external devices may be 1, the external device may be n, may be just one device, it may be a plurality of devices. So irq_desc [B] .handle_irq would call a linked list of functions that are provided by an external device. These functions judge for themselves whether the interrupt generated by itself, if it is processed.

  • ③ handler external equipment:

  That's "external device" may be a chip, it could always simple button. Their handlers provided by their own drivers, which are the most familiar with the equipment of the "people": it knows how to determine whether a device interrupt, how to handle interrupts.

  For sharing interrupts, GPIO interrupts such as B, it may have a plurality of interrupt sources, each interrupt source corresponding to an interrupt handler. Therefore irq_desc [B] should have a list, storing the processing function of a plurality of interrupt sources. Once the program determines that a GPIO interrupt B, it will function from the list in those taken out, then 11 execution. This list is the action list. The list can be seen at the beginning of this part of the first picture.

3.2 irqaction structure

  irqaction structure include / linux / interrupt.h defined in the main content as shown below:

Here Insert Picture Description
  When you call request_irq, request_threaded_irq register an interrupt handler, the kernel will construct a irqaction structure. Save name, dev_id etc. inside, the most important thing is handler, thread_fn, thread.

  • handler is the upper half of interrupt handling function to deal with urgent matters.
  • thread_fn corresponds to a kernel thread thread, when the handler is finished, Linux kernel will wake up the corresponding kernel threads. Kernel threads, calls thread_fn function.
  • Can provide a handler without providing thread_fn, it degenerates into a general request_irq function. (Only the upper half)
  • Does not provide a handler can only provide thread_fn, completely handled by the kernel thread interrupts. (Only the lower half)
  • Can also provide both handler also provide thread_fn, which is interrupted upper half, lower half.

  There is also a structure called the sedondary irqaction, re-analysis after its action. Dev_id can be passed in the reqeust_irq, why need dev_id? There are 2 Role:

  • ① When the interrupt handler execution, you can use dev_id
  • To unload incoming dev_id ② when interrupted, so as to find the corresponding entry in the action list according dev_id
    must be provided in dev_id shared interrupts, non-shared interrupts can not be provided.
3.3 irq_data structure

  irq_data structure is defined in the include / linux / irq.h, the main contents below:

Here Insert Picture Description
  It is a transit point, there irq_chip pointer, irq_domain pointer is pointing to another structure.

  More interesting is irq and hwirq, which is software irq interrupt number, hwirq is a hardware interrupt number. For example, our example above, the GPIO interrupt B is a software interrupt number, found irq_desc [B] This array entries; in the GPIO interrupt No. x, which is hwirq.

  Who will establish the link between irq, hwirq it? Established by irq_domain. irq_domain will be mapped to local hwirq global irq, what does that mean? For example, there are GPIO controller No. 1 interrupt, UART module also has interrupts No. 1, these two "No. 1 interrupt" is not the same, they belong to different "domains" ──irq_domain.

3.4 irq_domain structure

irq_domain structure include / linux / irqdomain.h defined in the main content as shown below:

Here Insert Picture Description
  When we start from the back of the device tree, how to specify interruption in the device tree, how to interrupt the device tree is converted to irq, irq_domain will play as great. Here's a simple entry-level solution based on talk, in the device tree, you will see this property:

interrupt-parent = <&gpio1>;
interrupts = <5 IRQ_TYPE_EDGE_RISING>;

  It pledged to use gpio1 in the No. 5 interrupt, hwirq is 5. But we will use this function request_irq (irq, handler) in the drive to register interrupt, what irq that? It is a software interrupt number, it should be from the "No. 5 gpio1 interrupt" Convert come.

  Who hwirq convert irq? Gpio1 of the associated data structures, the structure is irq_domain corresponding gpio1.

  irq_domain irq_domain_ops structure has a structure, which has various operating functions, mainly:

  • ① xlate
    used to parse tree interruption device attributes, extracted hwirq, type and other information.

  • ② map
    to hwirq convert irq.

3.5 irq_chip structure

  irq_chip structure is defined in the include / linux / irq.h, the main contents below:

Here Insert Picture Description

  This structure with "chip" chip that is related to the role of the members of which are also listed in the header file clearly, excerpt follows:

* @irq_startup: start up the interrupt (defaults to ->enable if NULL)
* @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL)
* @irq_enable: enable the interrupt (defaults to chip->unmask if NULL)
* @irq_disable: disable the interrupt
* @irq_ack: start of a new interrupt
* @irq_mask: mask an interrupt source
* @irq_mask_ack: ack and mask an interrupt source
* @irq_unmask: unmask an interrupt source
* @irq_eoi: end of interrupt

  After we request_irq, do not need to manually enable interrupts, system calls reason is that in the corresponding irq_chip function to help us enable the interrupt.

  We provide interrupt handler, the main chip does not need to perform the associated clearing interrupt operation, the system also helped us call irq_chip the correlation function.

  But the external device related to clear interrupt operation , we still need to do their own. FIG as above in the "external device 1", "n-external devices", outside the ever-changing device, the kernel can not clear the corresponding interrupt operation.

Published 712 original articles · won praise 1178 · Views 840,000 +

Guess you like

Origin blog.csdn.net/ReCclay/article/details/105233680