ARM Linux irqControler
/创建硬件中断号和desc->irq_data的关系,保存在domain->revmap_tree,软件中断号在之前就保存在desc->irq_data.irq中,建立了软硬件中断号的联系。-> 查找 GPIO1.1 virq 的 irq_desc -> 调用其 ->handle_irq (e.g., handle_edge_irq)-> 查找 SPI 66 的 irq_desc -> 调用其 -
一、设备树信息
①、#interrupt-cells,指定中断源的信息 cells 个数。
②、interrupt-controller,表示当前节点为中断控制器。
③、interrupts,指定中断号,触发方式等。
④、interrupt-parent,指定父中断,也就是中断控制器。
二、中断的注册过程
1)终端号分成软件中断号和硬件中断号。
2)void __init of_irq_init(const struct of_device_id *matches) =>> gic 初始化
3)在gpio-mxc中,有:
mxc_gpio_probe
port->irq_high = platform_get_irq(pdev, 1);
port->irq = platform_get_irq(pdev, 0);
这个 1和0的区别是interrupts属性下的中断1和中断0
gpio1: gpio@0209c000 {
compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
reg = <0x0209c000 0x4000>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
4)irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); //分配软件中断号和desc,创建联系
irq_base是这和GPIO中的32个引脚对应的中断的软中断起始号。
1.
#define irq_alloc_descs(irq, from, cnt, node) \
__irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
2.
alloc_descs(start, cnt, node, owner);
3.
for (i = 0; i < cnt; i++) {
desc = alloc_desc(start + i, node, owner); // desc_set_defaults(irq, desc, node, owner); 将irq保存到desc->irq_data.irq
if (!desc)
goto err;
mutex_lock(&sparse_irq_lock);
irq_insert_desc(start + i, desc); //radix_tree_insert(&irq_desc_tree, irq, desc); 创建irq和desc的关系,保存在全局数据irq_desc_tree中
mutex_unlock(&sparse_irq_lock);
}
5)port->domain = irq_domain_add_legacy(np, 32, irq_base, 0, &irq_domain_simple_ops, NULL);
1.
void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base, irq_hw_number_t hwirq_base, int count)
2.
int irq_domain_associate(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq)
3.
struct irq_data *irq_data = irq_get_irq_data(virq); //获取desc->irq_data
irq_data->hwirq = hwirq;
irq_data->domain = domain;
radix_tree_insert(&domain->revmap_tree, hwirq, irq_data); //创建硬件中断号和desc->irq_data的关系,保存在domain->revmap_tree,软件中断号在之前就保存在desc->irq_data.irq中,建立了软硬件中断号的联系。
6)mxc_gpio_init_gc(port, irq_base);
1.初始化了某个引脚中断的desc->handler !!!
三、调用过程
硬件中断 (GPIO1.1 电平变化)
1)GPIO 控制器 (mxc_gpio) 标记中断状态
2)GPIO 控制器触发其 GIC 中断线 (e.g., SPI 66)
3)GIC 接收中断 SPI 66
4) CPU 异常 -> gic_handle_irq() ,找到全局的domain
5)handle_domain_irq(gic->domain, irqnr, regs); //这里的irqnr是硬件中断号GIC_SPI 67
6)int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, bool lookup, struct pt_regs *regs)
7)if (lookup)
irq = irq_find_mapping(domain, hwirq); //这里的irq是软件中断号
8) 在 irq_find_mapping函数中,有
data = radix_tree_lookup(&domain->revmap_tree, hwirq);
rcu_read_unlock();
return data ? data->irq : 0;
9) generic_handle_irq(irq);
a) 找到了软件中断号,进而就可以找到irq_desc
struct irq_desc *desc = irq_to_desc(irq);
if (!desc)
return -EINVAL;
generic_handle_irq_desc(irq, desc);
b)static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc)
c)generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); //其中irq_find_mapping(port->domain, irqoffset)又找到gpio某个引脚的中断的软件中断号
d)进而调用到我们注册的中断函数
-> 查找 SPI 66 的 irq_desc -> 调用其 ->handle_irq (即 mxc_gpio_irq_handler)
-> mxc_gpio_irq_handler: 读取 GPIO ISR, 发现 bit1 (GPIO1.1) 触发
-> 计算/映射 GPIO1.1 的 Linux 虚拟中断号 (virq)
-> generic_handle_irq(GPIO1.1 的 virq) // <--- 你的 callback 是在这里被调用的!
-> 查找 GPIO1.1 virq 的 irq_desc -> 调用其 ->handle_irq (e.g., handle_edge_irq)
-> 遍历 action 链表 -> 调用 action->handler (即你的 callback 函数)
更多推荐
所有评论(0)