This interrupted series of articles mainly discusses Linux in mobile devices. The examples in this article are basically based on the arm system architecture, and the principles of other architectures are similar, the difference is only the hardware abstraction layer. The kernel version is 3.3. Although the kernel version is constantly improved, since the last change to the current general interrupt subsystem, the big framework has not changed much.
/*************************************** **************************************** **********************/
Statement: the content of this blog is created at http://blog.csdn.net/droidphone. please refer to it for help. Thank you!
/*************************************** **************************************** **********************/
1. device, interrupt controller, and CPU
In a complete device, interrupt-related hardware can be divided into three categories: device, interrupt controller, and CPU, shows the composition structure of Interrupt hardware in an SMP system:
Figure 1.1 hardware composition of the interrupt System
DeviceA device is the source of an interruption. When a device needs to request a service, it initiates a hardware interruption signal. Generally, the signal is connected to the interrupt controller, the interrupt controller performs further processing. In modern mobile devices, devices that initiate an interruption can be located outside the SOC (System-on-chip) chip or inside the SOC, because most SOC currently integrates a large number of hardware IP addresses, such as I2C, SPI, and display controller.
Interrupt ControllerThe Interrupt Controller is responsible for collecting all the interrupts initiated by the interrupt source. The existing interrupt controllers are almost programmable. Through programming the interrupt controller, we can control the priority of each interrupt source, the type of the interrupt appliance, and enable or disable an interrupt source. In the SMP system, you can even control the CPU to which an interrupt source is sent for processing. For the SOC of the ARM architecture, the most frequently used interrupt controller is the vector interrupt controller. after entering the multi-core era, the applications of the general interrupt controller are gradually increasing.
CPUThe CPU is a part of the final response to the interruption. It controls and manages every interruption in the system by programming the Programmable Interrupt Controller. When the Interrupt Controller determines that an interruption can be processed, the Interrupt Controller will notify one or several CPUs to handle the interrupt according to the previous settings. Although the interrupt controller can notify several CPUs to process the interrupt at the same time, in fact, at last, there will be only one CPU corresponding to this interrupt request, but the specific CPU response may be random. The Interrupt Controller ensures this feature on the hardware, however, this also relies on the operating system's software implementation for the interrupted system. In the SMP system, the CPU also passes through IPI (Inter
Processor interrupt.
2. IRQ No.
Each registered interrupt source in the system will be assigned a unique number to identify the interrupt, which is called the IRQ Number. The IRQ Number runs through the general interrupt subsystem of Linux. On mobile devices, the IRQ Number of each interrupt source is included in some arch-related header files, such as ARCH/XXX/Mach-xxx/include/irqs. h. When a driver requests an interrupted service, it uses the IRQ Number to register the interrupt. When the interrupt occurs, the CPU usually obtains the relevant information from the interrupt controller and then calculates the corresponding IRQ Number, then pass the IRQ Number to the corresponding driver.
3. Apply for interruption in the driver
The Linux interrupt sub-system provides drivers with a series of APIS, one of which is used to request an interruption from the system:
int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id)
Where,
- IRQ is the IRQ Number to apply,
- Handler is a service function for interrupt processing. It works in the interrupt context. If not, null can be input, but it cannot be null at the same time as thread_fn;
- Thread_fn is the callback function for thread interruption. It works in the context of the kernel process. If not, null can be input, but it cannot be null at the same time as handler;
- Irqflags are some signs of the interrupt. You can specify the electrical type of the interrupt and whether it is shared;
- Devname specifies the interrupt name;
- Dev_id is used to share the cookie data during interruption. It is usually used to identify the device that initiates the interruption;
The detailed working mechanism of this API will be discussed later.
4. Software abstraction of the general interrupt subsystem (generic IRQ)
Before the emergence of the general interrupt subsystem (generic IRQ), the kernel uses _ do_irq to handle all the interruptions, which means that the _ do_irq must handle various types of interruptions, this will increase the complexity of the software, the layers are not clear, and the code reusability is not good. In fact, the kernel version 2.6.38 ,__ do_irq has completely disappeared from the kernel code. The prototype of the general interrupt subsystem first appeared in the arm system. At the beginning, the kernel developers differentiated the three interrupt types:
- Level type)
- Edge type)
- Simple Type)
Later, we added the fast EOI type to some interrupt controllers that need to respond to EOI (end of Interrupt) and the per CPU type to SMP. After abstracting these different interrupt types, it becomes the traffic control layer of the interrupt sub-system. To make all the architecture reusable, the interrupt controller is further encapsulated to form the hardware encapsulation layer in the interrupt subsystem. The following figure shows the hierarchy of the general interrupt subsystem:
Figure 4.1 General interrupt subsystem hierarchy
Hardware encapsulation LayerIt contains all the Code related to the architecture, including the abstract encapsulation of the interrupt controller, arch-related interrupt initialization, and the initialization of data structures related to each IRQ, the CPU interrupt entry is also implemented in arch-related code. The general logic layer of Interrupt accesses and controls the behavior of the interrupt controller through standard encapsulated interfaces (which is actually the interface defined by struct irq_chip). After obtaining the IRQ Number, the System-related interrupt entry function, the standard functions provided by the general logic layer of interruption are used to transmit interrupt calls to the central cut-off control layer. Let's take a look at some definitions of irq_chip:
struct irq_chip {const char*name;unsigned int(*irq_startup)(struct irq_data *data);void(*irq_shutdown)(struct irq_data *data);void(*irq_enable)(struct irq_data *data);void(*irq_disable)(struct irq_data *data);void(*irq_ack)(struct irq_data *data);void(*irq_mask)(struct irq_data *data);void(*irq_mask_ack)(struct irq_data *data);void(*irq_unmask)(struct irq_data *data);void(*irq_eoi)(struct irq_data *data);int(*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);int(*irq_retrigger)(struct irq_data *data);int(*irq_set_type)(struct irq_data *data, unsigned int flow_type);int(*irq_set_wake)(struct irq_data *data, unsigned int on); ......};
Obviously, the structure definition above is actually an abstraction of the interrupt controller interface. We only need to implement the above interfaces (not all) for each interrupt controller ), and associate it with the corresponding IRQ. The upper implementation can access the interrupt controller through these interfaces. In addition, the Code of the same interrupt controller can be easily reused by different platforms.
Central cut-off control layerThe central cut-off control refers to the reasonable and correct handling of continuous interruptions. For example, how to handle an interruption when it is being processed, and when to block the interruption, when to enable the interrupt, and when to respond to the interrupt controller. This layer implements the process of central cut-off control operations unrelated to the system and hardware. It is designed for different interrupted electrical types (Level, edge ......), the corresponding standard throttling processing functions are implemented. In these processing functions, the interrupt control is finally transferred to the processing function or the disconnection process passed in when the driver registers the interrupt. At present, the kernel provides the following implementation of the main interrupt control functions (only part of the list ):
- Handle_simple_irq ();
- Handle_level_irq (); cut-off control handler in the Level
- Handle_edge_irq (); edge-triggered throttling Handler
- Handle_fasteoi_irq (); specifies the interrupt control handler used by The EOI interrupt processor.
- Handle_percpu_irq (); this IRQ is used only when a single CPU responds
Interrupt general logic layerThis layer manages several important data of the interrupt system and provides a series of auxiliary management functions. At the same time, this layer also implements and manages interrupt threads, and implements and manages shared interruptions and nested interruptions. In addition, it also provides some interface functions, they serve as a bridge between the hardware encapsulation layer and the cut-off control layer and the driver API layer, such as the following API:
- Generic_handle_irq ();
- Irq_to_desc ();
- Irq_set_chip ();
- Irq_set_chained_handler ();
Driver APIThis part provides a series of APIS for the driver to apply for/release the interruption to the system, enable/disable the interruption, set the interruption type, and set the features of the interrupt wake-up system. Drivers usually only use the APIS provided by this layer to develop drivers. Other details are "hidden" by the other software layers, driver developers do not need to pay attention to the underlying implementation, which seems to be a wonderful thing, but I think that to write a good interrupt code, take some time to understand the implementation of other layers. Some of the APIs are as follows:
- Enable_irq ();
- Disable_irq ();
- Disable_irq_nosync ();
- Request_threaded_irq ();
- Irq_set_affinity ();
I will not introduce each layer in detail here. I will discuss it in other articles in this series.
5. IRQ description structure: struct irq_desc
Almost all general interrupt subsystems are structured around irq_desc. Each irq in the system corresponds to an irq_desc structure. There are two ways to organize all irq_desc structures:
Array-basedThe platform-related board-level code defines the constant nr_irqs based on the number of IRQ in the system in advance. In kernel/IRQ/irqdesc. C, this constant is used to define the irq_desc structure array:
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {[0 ... NR_IRQS-1] = {.handle_irq= handle_bad_irq,.depth= 1,.lock= __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),}};
Base treeWhen config_sparse_irq is selected, the kernel uses the base tree (Radix tree) to manage the irq_desc structure. In this way, the irq_desc structure can be dynamically allocated, for systems with a large number of IRQ or non-consecutive IRQ numbers, managing irq_desc in this way is advantageous for memory saving, moreover, for external devices with built-in interrupt controllers that manage multiple interrupt sources, they can dynamically apply for the irq_desc structure corresponding to these interrupt sources in the driver, instead of retaining the memory required by the irq_desc structure in the compilation phase of the system.
Let's take a look at some definitions of irq_desc:
struct irq_data {unsigned intirq;unsigned longhwirq;unsigned intnode;unsigned intstate_use_accessors;struct irq_chip*chip;struct irq_domain*domain;void*handler_data;void*chip_data;struct msi_desc*msi_desc;#ifdef CONFIG_SMPcpumask_var_taffinity;#endif};
struct irq_desc {struct irq_datairq_data;unsigned int __percpu*kstat_irqs;irq_flow_handler_thandle_irq;#ifdef CONFIG_IRQ_PREFLOW_FASTEOIirq_preflow_handler_tpreflow_handler;#endifstruct irqaction*action;/* IRQ action list */unsigned intstatus_use_accessors;unsigned intdepth;/* nested irq disables */unsigned intwake_depth;/* nested wake enables */unsigned intirq_count;/* For detecting broken IRQs */raw_spinlock_tlock;struct cpumask*percpu_enabled;#ifdef CONFIG_SMPconst struct cpumask*affinity_hint;struct irq_affinity_notify *affinity_notify;#ifdef CONFIG_GENERIC_PENDING_IRQcpumask_var_tpending_mask;#endif#endifwait_queue_head_t wait_for_threads;const char*name;} ____cacheline_internodealigned_in_smp;
Explain the main fields in irq_desc:
Irq_dataThis embedded structure was introduced in version 2.6.37. The previous kernel version directly places the fields in this structure in the irq_desc structure, then, the IRQ Number is input as the parameter in the chip-> XXX () callback of the hardware encapsulation layer, but the underlying functions often need to access-> handler_data,-> chip_data, -> msi_desc and other fields. You need to use irq_to_desc (IRQ) to obtain the irq_desc structure pointer and then access the above fields. This reduces the performance, especially when sparse is configured.
This is especially true in IRQ systems, because it means the search operation of the Base tree. To solve this problem, the kernel developer encapsulates the fields required by several low-level functions into a single structure, and changes the parameters used during the call to the pointer passed in to the structure. For the same purpose, why not directly input the irq_desc structure pointer? Because this will undermine the encapsulation of layers, we do not want the lower-level code to see what we should not see, that's all.
Kstat_irqsSome statistics used for IRQ, which can be queried from the proc file system.
ActionThe interrupt response linked list. When an IRQ is triggered, the kernel traverses the linked list, calls the callback handler in the action structure, or activates the interrupt thread, multiple devices share the same IRQ, which is common in peripheral devices.
Status_use_accessorsRecord the status of this IRQ. The Kernel provides a series of auxiliary functions of irq_settings_xxx to access this field. For details, see kernel/IRQ/settings. h.
DepthIt is used to manage the nested depth management of the enable_irq () and disable_irq () APIs. This value is subtracted from 1 each time enable_irq is enabled, and 1 is added for each disable_irq operation, only when depth = 0 is sent to the hardware encapsulation layer to disable IRQ. Only when depth = 1 is sent to the hardware encapsulation layer to enable IRQ. The number of disable nesting times can be more than the number of enable times. In this case, the value of depth is greater than 1. When the value of depth is 1, after the call to enable IRQ is sent to the hardware encapsulation layer, after depth is subtracted from 1, depth is 0, which is in a balanced state. We can only call disable_irq. If enable_irq is called at this time, the kernel reports a warning of IRQ imbalance, prompting drivers to check their code.
LockIt is used to protect the spin lock of the irq_desc structure.
Affinity_hitIt is used to prompt the user space and serves as the basis for optimizing the relationship between IRQ and CPU.
Pending_maskIt is used to adjust the balance of IRQ among various CPUs.
Wait_for_threadsUsed for synchronize_irq (), waiting for all threads of the IRQ to finish.
Fields in the irq_data structure:
IRQThe IRQ Number corresponding to the structure.
HwirqThe hardware IRQ Number, which is different from the above IRQ;
NodeIt is usually used for hwing between hwirq and IRQ;
State_use_accessorsThe status information required by the hardware encapsulation layer. Do not directly access this field. The kernel defines a set of functions used to access this field: irqd_xxxx (). For details, see include/Linux/IRQ. h.
ChipIrq_chip structure pointer to the interrupt controller to which the IRQ belongs
Handler_dataPrivate Data Pointer of each IRQ. This field is used by the hardware encapsulation layer. For example, it is used as a multiplexing interrupt of the underlying hardware.
Chip_dataPrivate Data of the interrupt controller. This field is used by the hardware switch layer.
Msi_descMSI or MSI-X interrupt mechanism for PCIe bus.
AffinityRecord the relationship between the IRQ and the CPU. It is actually a bit-mask. Each bit represents a CPU, and after the bit is set, it indicates that the CPU may process the IRQ.
This is the first article in the general interrupt subsystem series. The implementation principles of each software layer are not described here, but it is necessary to briefly introduce the entire architecture:
- The system startup phase depends on the Kernel configuration. The kernel allocates enough irq_desc structures through an array or base tree;
- Initialize interrupt-related hardware, especially the interrupt controller, based on different architectures;
- Fill in the default fields for the irq_desc structure of each required IRQ, such as the IRQ Number and irq_chip pointer, and configure the Stream Control Handler according to different interrupt types;
- In the initialization phase, the device driver uses request_threaded_irq () API to request service interruption. Two important parameters are handler and thread_fn;
- When a device triggers an interrupt, the CPU enters the preset interrupt entry, which belongs to the Code related to the underlying system. It obtains the IRQ Number through the interrupt controller, after processing some fields in the irq_data structure, the control is passed to the central control layer (via irq_desc-> handle_irq );
- After necessary throttling, use the irq_desc-> action linked list to retrieve the handler and thread_fn registered when the driver requests an interruption, or you can call the handler callback, or start a thread to execute thread_fn, or both;
- At this point, the driver finally responds and processes the interruption.
6. Interrupt the proc file interface of the subsystem
Under the/proc directory, there are two files and subdirectories related to the interrupt subsystem, which are:
- /Proc/interrupts: File
- /Proc/IRQ: subdirectory
When interrupts is read, The IRQ Number is displayed in sequence, the number of times each CPU processes the IRQ, the name of the interrupt controller, the IRQ name, and the name used by the driver to register the IRQ, the following is an example:
Under the/proc/IRQ directory, a subdirectory named IRQ is created for each registered IRQ. Each subdirectory has the following entries:
- Relationship between smp_affinity IRQ and CPU;
- Smp_affinity_hint read-only entry for IRQ balancing in user space;
- Spurious can obtain statistics on the number of times this IRQ was processed and not processed;
- Handler_name The Name Of The Handler passed in when the driver registers this IRQ;
Different IRQ entries may not all appear. The following is an example of a device:
# Cd/proc/IRQ
# Ls
Ls
332
248
......
......
12
11
Default_smp_affinity
# Lls 332
Bcmsdh_sdmmc
Spurious
Node
Affinity_hint
Smp_affinity
# Cat 332/smp_affinity
3
It can be seen that the above is a device that uses dual-core CPU, because the smp_affinity value is 3, each interruption of the system can be processed by two CPUs by default.
This chapter ends. The following plan:
Interrupt subsystem 2: arch-related hardware encapsulation Layer
Linux interrupt (Interrupt) subsystem 3: Central cut-off control Processing Layer
Linux interrupt (Interrupt) subsystem 4: Driver Interface Layer
Linux interrupt (Interrupt) subsystem 5: software interrupt (softirq)