First, the interrupt action
Linux kernel needs to manage all the hardware devices connected to the computer. If you want to manage these devices, first of all, and they communicate with each other for the job.
Generally there are two options available to achieve this functionality:
- Poll (polling) kernel to regularly query the state of the device, and then make the appropriate treatment;
- Interrupt (interrupt) so that hardware signals (kernel becomes active initiative for the hardware) to the kernel when needed.
Use a polling way will take up more CPU time and low efficiency. For example: To read when there is a button is not pressed, a process needs to continue to query the keys have not been pressed. So this task was a lot of CPU time, CPU makes a lot of wasted effort. Use interrupt provide such a mechanism. When the button is not pressed, suspends the current process, the control to the other processes. When the button is pressed when the operating system is set to the current process activity, allowing the process to continue.
Two, linux interrupt management
linux kernel interrupt all uniform numbers, using a
irq_desc
structure array describing interrupted. An array entry (or a set of interrupt, which share the interrupt number) to use an interrupt.
struct irq_desc
A record structure, the name of the interrupt, the interrupt status, to access the underlying hardware interfaces (enabled interrupt, maskable interrupt, clearing the interrupt), the interrupt handler of the inlet,
through which the user can call the interrupt handler registration.
1、struct irq_desc
struct irq_desc
In theinclude\linux\irq.h
definition file inside
struct irq_desc {
irq_flow_handler_t handle_irq; /* 当前中断的处理函数入口 */
struct irq_chip *chip; /* 底层硬件访问 */
...
struct irqaction *action; /* 用户注册的中断处理函数链表 */
unsigned int status; /* IRQ状态 */
...
const char *name; /* 中断函数名 */
} ____cacheline_internodealigned_in_smp;
a. handle_irq
handle_irq
Is this or is this group of interrupt handler entrance. When an interrupt occurs, it will callasm_do_IRQ
the function. In this function call inside the interrupt number correspondingirq_desc
array itemhandle_irq
.
Inhandle_irq
use the insidechip
interface member to enable the shield, clear the interrupt. Eleven will call the user registered inaction
the list inside the handler.
b. struct irq_chip
struct irq_chip in the
include\linux\irq.h
definition file inside
struct irq_chip {
const char *name;
/* 启动中断,如果不设置则缺省为 "enable" */
unsigned int (*startup)(unsigned int irq);
/* 关闭中断,如果不设置则缺省为 "disable" */
void (*shutdown)(unsigned int irq);
/* 使能中断,如果不设置则缺省为"unmask" */
void (*enable)(unsigned int irq);
/* 禁止中断,如果不设置则缺省为"mask" */
void (*disable)(unsigned int irq);
/* 响应中断,一般是清除当前的中断,使得可以接收下一个中断 */
void (*ack)(unsigned int irq);
/* 屏蔽中断源 */
void (*mask)(unsigned int irq);
/* 屏蔽和响应中断 */
void (*mask_ack)(unsigned int irq);
/* 开启中断 */
void (*unmask)(unsigned int irq);
....
};
c. struct irqaction
struct irqaction
In the structureinclude\linux\interrupt.h
definition files inside.
Each interrupt handler are registered users with airqaction
structure to describe an interrupt (e.g. shared interrupts) may have a plurality of handlers.
Theirirqaction
structureaction
into a linked list of chain headers
struct irqaction {
/* 用户注册的中断处理函数 */
irq_handler_t handler;
/* 中断的标志,是否是共享中断,中断的触发方式是电平触发,还是边沿触发 */
unsigned long flags;
cpumask_t mask;
/* 用户注册时,给的中断的名字 */
const char *name;
/* handler 中断函数的参数,也可以用来区分共享中断 */
void *dev_id;
/* 链表的指针 */
struct irqaction *next;
/* 中断号 */
int irq;
struct proc_dir_entry *dir;
};
2. Summary
For
struct irq_desc
arrays,struct irq_chip
structures, andstruct irqaction
the relationship between the three, as shown below:
Third, the interrupt handler initialization
1, the interrupt handler initialization
In the
init\Main.c
documentstart_kernel
function which callsinit_IRQ()
function it is to interrupt initialization architecture
2, init_IRQ function
init_IRQ
It used to initialize the interrupt handling architecture, thearch\arm\kernel\irq.c
file inside
void __init init_IRQ(void)
{
int irq;
/* 初始化irq_desc[] 每一项的中断状态 */
for (irq = 0; irq < NR_IRQS; irq++)
irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
...
/* 架构相关的中断初始化函数 */
init_arch_irq();
}
3、 init_arch_irq
init_arch_irq
Is a function pointer,arch\arm\kernel\setup.c
the filesetup_arch()
function is initialized
void __init setup_arch(char **cmdline_p)
{
...
init_arch_irq = mdesc->init_irq;
...
}
mdesc->init_irq
Points to thearch\arm\plat-s3c24xx\irq.c
files3c24xx_init_irq()
functions.
MACHINE_START(S3C2440, "SMDK2440")
A macro is used to define thestruct machine_desc
structure of
the structures inarch\arm\mach-s3c2440\Mach-smdk2440.c
the definition file and initializes insideinit_irq
pointings3c24xx_init_irq()
function
MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks <[email protected]> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
/* init_irq成员在这里初始化 */
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
4, s3c24xx_init_irq function
s3c24xx_init_irq()
Functionarch\arm\plat-s3c24xx\irq.c
definition (as part of the code block of code), for all his chip operating all associated data structures (irq_desc [irq] .chip) ,, and the initialization handler entry (irq_desc [irq] .handle_irq).
InIRQ_EINT0
andIRQ_EINT3
, for example,set_irq_chip
the function that willirq_desc[irqno].chip = &s3c_irq_eint0t4
, after it canirq_desc[irqno].chip
be provided a touch-way function pointers structure, enabling the interrupt, the interrupt mask
set_irq_handler
function is provided to the interrupt handler entryirq_desc[irqno].handle_irq = handle_edge_irq
interrupt occurs,handle_edge_irq
it calls the handler registered user specific
irq_desc[irqno].falgs
settings forIRQF_VALID
void __init s3c24xx_init_irq(void)
{
...
/* external interrupts */
for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
irqdbf("registering irq %d (ext int)\n", irqno);
set_irq_chip(irqno, &s3c_irq_eint0t4);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
irqdbf("registering irq %d (extended s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irqext_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
...
}
5, set_irq_chip function
int set_irq_chip(unsigned int irq, struct irq_chip *chip)
{
struct irq_desc *desc;
unsigned long flags;
/* 判断是否超过最大的中断号 */
if (irq >= NR_IRQS) {
printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
WARN_ON(1);
return -EINVAL;
}
if (!chip)
chip = &no_irq_chip;
/* 通过中断号找到irq_desc数组对应的数组项 */
desc = irq_desc + irq;
spin_lock_irqsave(&desc->lock, flags);
/* 判断 chip 的成员即&s3c_irq_eint0t4的成员是否为空,如果为空就设置为默认的操作函数 */
irq_chip_set_defaults(chip);
/* 设置irq_desc[].chip成员 */
desc->chip = chip;
spin_unlock_irqrestore(&desc->lock, flags);
return 0;
5, set_irq_handler function
set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
__set_irq_handler(irq, handle, 0, NULL);
}
/***************************************************************************************/
__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
const char *name)
{
struct irq_desc *desc;
unsigned long flags;
/* 通过中断号找到irq_desc数组对应的数组项 */
desc = irq_desc + irq;
...
/* 中间还会做一些判断 */
...
/* 设置中断处理函数,名字*/
desc->handle_irq = handle;
desc->name = name;
/* 设置中断的状态,开启中断 */
if (handle != handle_bad_irq && is_chained) {
desc->status &= ~IRQ_DISABLED;
desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
desc->depth = 0;
desc->chip->unmask(irq);
}
}
6, set_irq_flags function
void set_irq_flags(unsigned int irq, unsigned int iflags)
{
struct irq_desc *desc;
unsigned long flags;
if (irq >= NR_IRQS) {
printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
return;
}
/* 找到数组项 */
desc = irq_desc + irq;
spin_lock_irqsave(&desc->lock, flags);
/* 设置中断状态 */
desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
if (iflags & IRQF_VALID)
desc->status &= ~IRQ_NOREQUEST;
if (iflags & IRQF_PROBE)
desc->status &= ~IRQ_NOPROBE;
if (!(iflags & IRQF_NOAUTOEN))
desc->status &= ~IRQ_NOAUTOEN;
spin_unlock_irqrestore(&desc->lock, flags);
}
IV Summary
Initialization process interrupt processing architecture of the fact that for
irq_desc[]
each of the initialization of the array is initialized.
A break or a set of interrupt byirq_desc[]
an array of items to manage.
An array of items inside thehandle_irq
chip
action
three important structure members.
- handle_irq is the current interrupt handler
- chip associated underlying hardware handler (interrupt trigger mode, maskable interrupt, the interrupt enable)
- action list head, user registration processing function which are linked to this list, when an interrupt occurs, it calls registered users come from inside the interrupt service function