Linux4.x之Gpio分析(七)中断流程2

中间我们插播了一下通用中断子系统的内容,补了一下基础知识,现在回到代码中。

开始前又要打断一下,我们先回顾一下之前分析的代码:

我们试图 从GPIO1_1 管脚的中断找到通过内核 API : request_irq 注册的中断处理函数。
我们关注4部分的处理:

  1. CPU的中断处理函数[mechine]
  2. GIC的中断处理函数
  3. GPIO控制器处理函数
  4. 驱动程序注册的中断处理函数

在(五)中我们已经分析到 generic_handle_irq 函数,这部分是指CPU的中断处理,从中断向量到 generic_handle_irq 函数,那么我们继续走。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//kernel/irq/irqdesc.c 
int generic_handle_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);

if (!desc)
return -EINVAL;
generic_handle_irq_desc(irq, desc);
return 0;
}
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
desc->handle_irq(irq, desc);
}

GPIO1_1的设备描述符的初始化

这里我们发现通过 irq_to_desc 我们找到该中断的中断描述符,然后调用了用 中段描述符中记录的 high_level handle
这里我们得先看看我们关于 GPIO1_1 的中断描述符是什么时候申请并存放到系统的 中断描述符表 中的呢?

GPIO1_1的设备描述符分配

所以我们现在关心两个方面的内容:

  1. 系统中断号的分配
  2. handle_irq 也就是 high level 处理函数的初始化

我们想起来我们在最开始分析GPIOLIB库的时候当时跳过的中断的一些内容,当时我们还看不懂中断操作的意义,现在在退回去看看。

1
2
3
4
//driver/gpio/gpio-mxc.c
//mxc_gpio_probe
irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); //申请了32个中断描述符
mxc_gpio_init_gc(port, irq_base); // init gpio_generc_control

这里只有两行代码,我们先分析申请中断描述符部分:

1
2
#define irq_alloc_descs(irq, from, cnt, node)   \
__irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)

我们展开宏就得到了

__irq_alloc_descs(-1,0,32,numa_node_id(),THIS_MODULE);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
static DECLARE_BITMAP(allocated_irqs, IRQ_BITMAP_BITS);
int __ref __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,struct module *owner)
{
int start, ret;

if (!cnt)
return -EINVAL;

if (irq >= 0) {
if (from > irq)
return -EINVAL;
from = irq;
} else {
from = arch_dynirq_lower_bound(from);
}

mutex_lock(&sparse_irq_lock);

start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS, from, cnt, 0);
ret = -EEXIST;
if (irq >=0 && start != irq)
goto err;

if (start + cnt > nr_irqs) {
ret = irq_expand_nr_irqs(start + cnt);
if (ret)
goto err;
}
bitmap_set(allocated_irqs, start, cnt);
mutex_unlock(&sparse_irq_lock);
return alloc_descs(start, cnt, node, owner);
}


static int alloc_descs(unsigned int start, unsigned int cnt, int node,struct module *owner)
{
struct irq_desc *desc;
int i;
for (i = 0; i < cnt; i++) {
desc = alloc_desc(start + i, node, owner);
if (!desc)
goto err;
mutex_lock(&sparse_irq_lock);
irq_insert_desc(start + i, desc);//将中断描述符存到中断描述符表中
mutex_unlock(&sparse_irq_lock);
}
return start;
}


static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
{
struct irq_desc *desc;
gfp_t gfp = GFP_KERNEL;

desc = kzalloc_node(sizeof(*desc), gfp, node);
if (!desc)
return NULL;
/* allocate based on nr_cpu_ids */
desc->kstat_irqs = alloc_percpu(unsigned int);
if (!desc->kstat_irqs)
goto err_desc;

if (alloc_masks(desc, gfp, node))
goto err_kstat;

raw_spin_lock_init(&desc->lock);
lockdep_set_class(&desc->lock, &irq_desc_lock_class);

desc_set_defaults(irq, desc, node, owner);//给中断描述符设置默认的参数

return desc;

err_kstat:
free_percpu(desc->kstat_irqs);
err_desc:
kfree(desc);
return NULL;
}

这里系统是通过位图来存放系统的中断号,这里我们一口气申请了32个中断号,因为GPIO1控制器上有32个管脚都可以做中断使用。

我们分别看一下两个函数:

  • desc_set_defaults //填充默认的参数
  • irq_insert_desc // 将描述符存到描述符表中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
struct module *owner)
{
int cpu;

desc->irq_data.irq = irq;
desc->irq_data.chip = &no_irq_chip;
desc->irq_data.chip_data = NULL;
desc->irq_data.handler_data = NULL;
desc->irq_data.msi_desc = NULL;
irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS);
irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
desc->handle_irq = handle_bad_irq;
desc->depth = 1;
desc->irq_count = 0;
desc->irqs_unhandled = 0;
desc->name = NULL;
desc->owner = owner;
for_each_possible_cpu(cpu)
*per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
desc_smp_init(desc, node);
}

这里我们看到默认的参数几乎都是没用的参数,说明了后续我们需要一步步填充这些参数。
下面我们看看如何存储的,因为我们配置了CONFIG_RADIX_TREE
我们之前说过设备描述符的存储方式有两种

  1. 静态的数组
  2. radix_tree

我们可以看到代码很简单,就是将irq作为关键字和对应的数据描述符存到基树中
然后我们通过irq 使用 irq_to_desc 函数就能找到数据描述符。

1
2
3
4
5
6
7
8
9
10
11
12
static RADIX_TREE(irq_desc_tree, GFP_KERNEL);

static void irq_insert_desc(unsigned int irq, struct irq_desc *desc)
{
radix_tree_insert(&irq_desc_tree, irq, desc);
}


struct irq_desc *irq_to_desc(unsigned int irq)
{
return radix_tree_lookup(&irq_desc_tree, irq);
}

GPIO1_1的中断处理函数初始化

好!我们该去看看初始化 mxc_gpio_init_gc了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;

gc = irq_alloc_generic_chip("gpio-mxc", 1, irq_base, port->base, handle_level_irq);
gc->private = port;
ct = gc->chip_types;
ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->chip.irq_set_type = gpio_set_irq_type;
ct->chip.irq_set_wake = gpio_set_wake_irq;
ct->regs.ack = GPIO_ISR;
ct->regs.mask = GPIO_IMR;
irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
}

这里我们看到是对 struct irq_chip_genericc 和 struct irq_chip_type 结构的初始化.
这里irq_chip_generic是通用的中断控制器,irq_chip_type 中断控制器的类型,我们在之前一章都见到过。
第6行: gc = irq_alloc_generic_chip(“gpio-mxc”, 1, irq_base, port->base, handle_level_irq); 用来分配一个通用控制器
第16行: irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); 用来注册通用控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct irq_chip_generic *irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base, void __iomem *reg_base, irq_flow_handler_t handler)
{
struct irq_chip_generic *gc;
unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type);

gc = kzalloc(sz, GFP_KERNEL);
if (gc) {
irq_init_generic_chip(gc, name, num_ct, irq_base, reg_base, handler);
}
return gc;
}

static void irq_init_generic_chip(struct irq_chip_generic *gc, const char *name, int num_ct, unsigned int irq_base,void __iomem *reg_base, irq_flow_handler_t handler)
{
raw_spin_lock_init(&gc->lock);
gc->num_ct = num_ct;
gc->irq_base = irq_base;
gc->reg_base = reg_base;
gc->chip_types->chip.name = name;
gc->chip_types->handler = handler;
}

这里分配比较简单,就是填充了irq_chip_generic控制器的各种参数:
其中最重要的是irq_flow_handler_t 类型的中断流控函数,之前我们提到过
通用中断子系统实现了以下这些标准流控回调函数,这些函数都定义在:kernel/irq/chip.c中

  1. handle_simple_irq 用于简易流控处理;
  2. handle_level_irq 用于电平触发中断的流控处理;
  3. handle_edge_irq 用于边沿触发中断的流控处理;
  4. handle_fasteoi_irq 用于需要响应eoi的中断控制器;
  5. handle_percpu_irq 用于只在单一cpu响应的中断;
  6. handle_nested_irq 用于处理使用线程的嵌套中断;

这里我们使用了电平触发方式的流控函数。
最后我们看看注册的函数irq_setup_generic_chip 如何实现,这里我们看看传入了设备描述符BIT_MAP位号开始地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
enum irq_gc_flags flags, unsigned int clr,
unsigned int set)
{
struct irq_chip_type *ct = gc->chip_types;
struct irq_chip *chip = &ct->chip;
unsigned int i;

raw_spin_lock(&gc_lock);
list_add_tail(&gc->list, &gc_list);
raw_spin_unlock(&gc_lock);

irq_gc_init_mask_cache(gc, flags);

//为每一个中断设置流控函数
for (i = gc->irq_base; msk; msk >>= 1, i++) {
if (!(msk & 0x01))
continue;

if (flags & IRQ_GC_INIT_NESTED_LOCK)
irq_set_lockdep_class(i, &irq_nested_lock_class);

if (!(flags & IRQ_GC_NO_MASK)) {
struct irq_data *d = irq_get_irq_data(i);

if (chip->irq_calc_mask)
chip->irq_calc_mask(d);
else
d->mask = 1 << (i - gc->irq_base);
}
irq_set_chip_and_handler(i, chip, ct->handler);//设置流控的函数
irq_set_chip_data(i, gc);//desc->irq_data.chip_data = data;
irq_modify_status(i, clr, set);//
}
gc->irq_cnt = i - gc->irq_base;
}

这里也就是为给设备描述符中的参数做初始化,我们具体的看一下,之前设置的默认参数这么块就重新设定了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle)
{
irq_set_chip_and_handler_name(irq, chip, handle, NULL);
}


void irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle, const char *name)
{
irq_set_chip(irq, chip); //desc->irq_data.chip = chip;
__irq_set_handler(irq, handle, 0, name);// desc->handle_irq = handle;
// desc->name = name;

}


void __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,const char *name)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);

if (!desc)
return;

if (!handle) {
handle = handle_bad_irq;
} else {
struct irq_data *irq_data = &desc->irq_data;
if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
goto out;
}

/* Uninstall? */
if (handle == handle_bad_irq) {
if (desc->irq_data.chip != &no_irq_chip)
mask_ack_irq(desc);
irq_state_set_disabled(desc);
desc->depth = 1;
}
desc->handle_irq = handle;
desc->name = name;

if (handle != handle_bad_irq && is_chained) {
irq_settings_set_noprobe(desc); //desc->status_use_accessors |= _IRQ_NOPROBE;
irq_settings_set_norequest(desc);// desc->status_use_accessors |= _IRQ_NOREQUEST;
irq_settings_set_nothread(desc); // desc->status_use_accessors |= _IRQ_NOTHREAD;
irq_startup(desc, true);
}
}

这里我们又见到 __irq_set_handler 函数了,我们之前在GIC中注册中断控制器时,传入的参数是is_chained是1,
这样就区分了主中断控制器和级联的中断控制器。

好!我们接着来看 handle_level_irq 的流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
void
handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
raw_spin_lock(&desc->lock);
mask_ack_irq(desc);//1.2步骤

if (!irq_may_run(desc))
goto out_unlock;

desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
kstat_incr_irqs_this_cpu(irq, desc);

/*
* If its disabled or no action available
* keep it masked and get out of here
*/
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
desc->istate |= IRQS_PENDING;
goto out_unlock;
}

handle_irq_event(desc);

cond_unmask_irq(desc);//步骤3

out_unlock:
raw_spin_unlock(&desc->lock);
}


irqreturn_t handle_irq_event(struct irq_desc *desc)
{
struct irqaction *action = desc->action;
irqreturn_t ret;

desc->istate &= ~IRQS_PENDING;
irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);//
raw_spin_unlock(&desc->lock);

ret = handle_irq_event_percpu(desc, action);

raw_spin_lock(&desc->lock);
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
return ret;
}


irqreturn_t
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
{
irqreturn_t retval = IRQ_NONE;
unsigned int flags = 0, irq = desc->irq_data.irq;

do {
irqreturn_t res;

trace_irq_handler_entry(irq, action);
res = action->handler(irq, action->dev_id);
trace_irq_handler_exit(irq, action, res);

if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
irq, action->handler))
local_irq_disable();

switch (res) {
case IRQ_WAKE_THREAD:
__irq_wake_thread(desc, action);

/* Fall through to add to randomness */
case IRQ_HANDLED:
flags |= action->flags;
break;

default:
break;
}

retval |= res;
action = action->next;
} while (action);

add_interrupt_randomness(irq, flags);

if (!noirqdebug)
note_interrupt(irq, desc, retval);
return retval;
}

我们总结一下流程handle_level_irq,最后就调用desc中 action->handler ,也就是之前提的 specific handler :

1
2
3
4
5
handle_level_irq(irq, desc) 
handle_irq_event(desc);
struct irqaction *action = desc->action;
handle_irq_event_percpu(desc, action);
res = action->handler(irq, action->dev_id);

中断控制器(GPIO1)的设备描述符初始化

分析到这里总觉得怪怪的,恭喜你看出了一点端倪。
我们之前设备树中看到的中断号明明是66、67 ,这里怎么是随意的分配的呢?
是了,我们这个驱动程序写的略微让人感到迷惑!
驱动的做法是将GPIO1控制器的中断与IO口的中断做了一个分离,GPIO1的中断号是66、67 GPIO1_1—-GPIO1_16的中断号是后面又分配的。
也就是说驱动发生后,GIC只知道66或67号硬件中断发生了,至于哪里GPIO1控制器他的哪个管脚根本就不关心。
那么哪一个GPIO口发生的由GPIO1控制去全权负责!
所以我们刚看到的一系列分析还少了一步,!
按照之前的逻辑我们也看两个步骤

  1. 系统中断号的分配[这里是硬件编号为66、67的虚拟中断号的分配]
  2. handle_irq 也就是 high level 处理函数的初始化 [GPIO1的中断处理函数]

中断控制器(GPIO1)的中断号的分配

我们在gic_init时,当发现中断控制器的父节点是自己时,那么说明自己是主中断控制器,那么将自己的父节点设置为NULL,初始化的时会将这个参数传入初始化函数。

1
2
3
4
5
6
7
8
9
10
for_each_matching_node(np, matches) {
desc->dev = np;
desc->interrupt_parent = of_irq_find_parent(np);
if (desc->interrupt_parent == np)
desc->interrupt_parent = NULL;
list_add_tail(&desc->list, &intc_desc_list);
}
}

ret = irq_init_cb(desc->dev, desc->interrupt_parent);

在GIC初始化的代码gic_init_bases中,这里node=NULL
先读gic_irqs支持的中断数量然后用函数irq_alloc_descs分配了从16开始的gic_irqs个中断描述符,
这样所有连接到GIC的设备使用时候直接指定highl_level的控制函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
gic_irqs = (gic_irqs + 1) * 32;
if (gic_irqs > 1020)
gic_irqs = 1020;
gic->gic_irqs = gic_irqs;


if(node) { /* DT case */
gic->domain = irq_domain_add_linear(node, gic_irqs,
&gic_irq_domain_hierarchy_ops,
gic);
} else { /* Non-DT case */
/*
* For primary GICs, skip over SGIs.
* For secondary GICs, skip over PPIs, too.
*/
if (gic_nr == 0 && (irq_start & 31) > 0) {
hwirq_base = 16;
if (irq_start != -1)
irq_start = (irq_start & ~31) + 16;
} else {
hwirq_base = 32;
}

gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */

irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
numa_node_id());

中断控制器(GPIO1)的中断处理函数的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static int mxc_gpio_probe(struct platform_device *pdev)
{
....
port->irq_high = platform_get_irq(pdev, 1);
port->irq = platform_get_irq(pdev, 0);
...
irq_set_chained_handler(port->irq, mx3_gpio_irq_handler);
irq_set_handler_data(port->irq, port);
if (port->irq_high > 0) {
/* setup handler for GPIO 16 to 31 */
irq_set_chained_handler(port->irq_high,mx3_gpio_irq_handler);
irq_set_handler_data(port->irq_high, port);
}
....
}

mxc_gpio_probe中,我们看到获取中断号,然后使用 irq_set_chained_handler 注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc)
{
u32 irq_stat;
struct mxc_gpio_port *port = irq_get_handler_data(irq);
struct irq_chip *chip = irq_get_chip(irq);

chained_irq_enter(chip, desc);

irq_stat = readl(port->base + GPIO_ISR) & readl(port->base + GPIO_IMR);

mxc_gpio_irq_handler(port, irq_stat);

chained_irq_exit(chip, desc);
}


static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat)
{
while (irq_stat != 0) {
int irqoffset = fls(irq_stat) - 1;

if (port->both_edges & (1 << irqoffset))
mxc_flip_edge(port, irqoffset);

generic_handle_irq(irq_find_mapping(port->domain, irqoffset));

irq_stat &= ~(1 << irqoffset);
}
}

我们看GPIO_1控制器的中断处理函数中再一次调用了generic_handle_irq ,是不是很眼熟哇!
饶了一个圈子!!! 然后才迫使GPIO1_1的中断处理程序得到了调用。

GPIO中断控制器的调用逻辑小结

总结一下,中断处理流程是

  1. 电信号CPU触发中断
  2. CPU差中断向量最后跳入了GIC的中断处理函数
  3. GIC中断处理函数通过GIC状态字寄存器得知外设发生中断(GPIO1控制器),也就是知道了硬件GIC硬件中断编号,
    然后通过 irq_find_mapping找到了中断描述符 ,
    接着调用了 generic_handle_irq(irq) 也就是high_level handle(GPIO1控制器的中断处理函数)
  4. GPIO1控制器注册的控制函数为 mx3_gpio_irq_handler ,(这个处理过程与GIC的处理方法类似),找到了哪个IO口触发中断,
    然后通过 irq_find_mapping找到GPIO1_1的中断号,也就是找到了GPIO1_1中断描述符,
    然后调用generic_handle_irq(GPIO_1_1)
  5. 最后运行了刚刚我们分析的 handle_level_irq 函数
  6. 最后调用了驱动程序的中断例程!

驱动程序中的中断例程注册

现在我们来看desc的参数action是什么时候初始化上来的?

现在我们来分析一下非常常用的API: request_irq

这里一共有5个参数:

  1. irq 需要申请的irq编号,我们通常会用gpio2irq()去获取
  2. handler 中断服务回调函数,该回调运行在中断上下文中
  3. thread_fn 如果该参数不为NULL,内核会为该irq创建一个内核线程。
  4. flags 控制中断行为的位标志,如触发方式、共享中断等
  5. name 申请本中断服务的设备名称,同时也作为中断线程的名称。
  6. dev 当多个设备的中断线共享同一个irq时,它会作为handler的参数,用于区分不同的设备。

这里做了irqflags的合理校验后填充 irqaction 结构,最后把大部分工作委托给__setup_irq函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}


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)
{
struct irqaction *action;
struct irq_desc *desc;
int retval;
if (((irqflags & IRQF_SHARED) && !dev_id) ||
(!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) ||
((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND)))
return -EINVAL;

desc = irq_to_desc(irq);
if (!desc)
return -EINVAL;

if (!irq_settings_can_request(desc) ||
WARN_ON(irq_settings_is_per_cpu_devid(desc)))
return -EINVAL;

if (!handler) {
if (!thread_fn)
return -EINVAL;
handler = irq_default_primary_handler;
}

action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;

action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;

chip_bus_lock(desc);
retval = __setup_irq(irq, desc, action);
chip_bus_sync_unlock(desc);
if (retval)
kfree(action);

return retval;
}

这个处理比较长,我们看一下重点:如果action不为空,说明了是共享中断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
old_ptr = &desc->action;
old = *old_ptr;
if (old) {


if (!((old->flags & new->flags) & IRQF_SHARED) ||
((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) ||
((old->flags ^ new->flags) & IRQF_ONESHOT))
goto mismatch;

/* All handlers must agree on per-cpuness */
if ((old->flags & IRQF_PERCPU) !=
(new->flags & IRQF_PERCPU))
goto mismatch;


/* add new interrupt at end of irq queue */
do {
/*
* Or all existing action->thread_mask bits,
* so we can find the next zero bit for this
* new action.
*/
thread_mask |= old->thread_mask;
old_ptr = &old->next;
old = *old_ptr;
} while (old);
shared = 1;
}

如果这不是一个共享中断,或者是共享中断的第一次申请,函数将初始化irq_desc结构中断线程等待结构:
wait_for_threads,disable_irq函数会使用该字段等待所有irq线程的结束。
接下来设置中断控制器的电气触发类型,然后处理一些必要的IRQF_XXXX标志位
最后将将 irqaction 挂到了链表上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
if (!shared) {
ret = irq_request_resources(desc);

init_waitqueue_head(&desc->wait_for_threads);

/* Setup the type (level, edge polarity) if configured: */
if (new->flags & IRQF_TRIGGER_MASK) {
ret = __irq_set_trigger(desc, irq,
new->flags & IRQF_TRIGGER_MASK);

if (ret)
goto out_mask;
}

desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
IRQS_ONESHOT | IRQS_WAITING);
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);

if (new->flags & IRQF_PERCPU) {
irqd_set(&desc->irq_data, IRQD_PER_CPU);
irq_settings_set_per_cpu(desc);
}

if (new->flags & IRQF_ONESHOT)
desc->istate |= IRQS_ONESHOT;

if (irq_settings_can_autoenable(desc))
irq_startup(desc, true);
else
/* Undo nested disables: */
desc->depth = 1;
if (new->flags & IRQF_NOBALANCING) {
irq_settings_set_no_balancing(desc);
irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
}

/* Set default affinity mask once everything is setup */
setup_affinity(irq, desc, mask);


}
new->irq = irq;
*old_ptr = new; //把新的irqaction实例链接到action链表的最后

irq_pm_install_action(desc, new);

/* Reset broken irq detection when installing new handler */
desc->irq_count = 0;
desc->irqs_unhandled = 0;

register_irq_proc(irq, desc);
new->dir = NULL;
register_handler_proc(irq, new);
free_cpumask_var(mask);

这样将就把通用子系统的中断响应流程给走通了。

后记

这个调用流程和普通外设相比多了调用的流程,起初分析的时候比较困惑。
后来想到了多中断控制器级联后,豁然开朗。
接着一气呵成,感觉写的内容超过之前的所有。囧!
豁然开朗!!!!!

客官,小的这记口碎大石值几个钱?