linux内核中设备中断
1、获取软件中断号
1.1 rc = of_irq_parse_one(dev, index, &oirq);解析dts中device node对中断的配置
platform_get_irq(struct platform_device *dev, unsigned int num)
--->of_irq_get(dev, index)
--->--->of_irq_parse_one(device, index, out_irq):解析解析dts中device node对中断的配置
{
p = of_irq_find_parent(device);
out_irq->np = p;
out_irq->args_count = intsize;
for (i = 0; i < intsize; i++) {
res = of_property_read_u32_index(device, "interrupts",
(index * intsize) + i,
out_irq->args + i);
}
}
例如
以下是dts文件中i2c节点关于中断的定义, 这里主要看软解是如何解析中断的
i2c0: i2c@5a800000
{
interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
};
解析的目的是初始化struct of_phandle_args结构体,该结构体定义如下:
struct of_phandle_args
{
struct device_node *np;
int args_count;
uint32_t args[MAX_PHANDLE_ARGS];
};
解析的结果为:
out_irq->np = interrupt-parent = gic node
out_irq->args[0] = GIC_SPI;
out_irq->args[1] = 硬件中断号 = 220
out_irq->args[2] = 中断触发类型 = IRQ_TYPE_LEVEL_HIGH
1.2 domain = irq_find_host(oirq.np);找到interrupt controller对应的irq domain,对于i2c来说,其对应的中断控制器为gic。
通过匹配irq_domain_list中的fwnode参数来找当前终端控制器对应的domain, 那么domain又是在什么时候加入irq_domain_list中的呢
irq_find_matching_fwspec(){
list_for_each_entry(h, &irq_domain_list, link) {
rc = ((fwnode != NULL) && (h->fwnode == fwnode) &&
((bus_token == DOMAIN_BUS_ANY) ||
(h->bus_token == bus_token)));
if (rc) {
found = h;
break;
}
}
}
1.3 找到gic终端控制器对应的domain之后,进行map, 将硬件中断号转化为软件中断号
irq_create_of_mapping(struct of_phandle_args *irq_data)
1、将of_phandle_args转化为struct irq_fwspec
of_phandle_args_to_fwspec(irq_data->np, irq_data->args, irq_data->args_count, &fwspec)
{
fwspec->fwnode = np ? &np->fwnode : NULL;
fwspec->param_count = count;
for (i = 0; i < count; i++)
fwspec->param[i] = args[i];
}
2、irq_create_fwspec_mapping
先找到终端控制器对应的domain
domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
解析结构体struct irq_fwspec, 获取hwirq和type
irq_domain_translate(domain, fwspec, &hwirq, &type)
若hwirq已经被映射
hwirq还未被映射,建立映射,virq = irq_domain_alloc_irqs
2、为获得的中断号分配中断处理函数
devm_request_irq
devm_request_threaded_irq
request_threaded_irq
1. 将虚拟的irq转化为desc, desc = irq_to_desc(irq);
2. 如果handler和thread_fn都不存在,直接return;如果只是handler不存在,使用default handler直接唤醒thread
3. 为action分配内存,然后初始化action
4. 注册irqaction __setup_irq(irq, desc, action);
参考:https://blog.csdn.net/pandy_gao/article/details/79309712