4.4.5. 创建软硬中断号映射
4.4.5.1. of_platform_default_populate_init
static int __init of_platform_default_populate_init(void)
|--//Handle certain compatibles explicitly
|--for_each_matching_node(node, reserved_mem_matches)
| of_platform_device_create(node, NULL, NULL);
|--node = of_find_node_by_path("/firmware");
|--if (node)
| of_platform_populate(node, NULL, NULL, NULL);
| of_node_put(node);
| //Populate everything else
|--of_platform_default_populate(NULL, NULL, NULL);
|--of_platform_populate(root, of_default_bus_match_table, lookup,parent);
|--for_each_child_of_node(root, child)
//Create a device for a node and its children
of_platform_bus_create(child, of_default_bus_match_table, lookup, parent, true);
| //对amba设备的处理,包含对中断号映射处理
|--if (of_device_is_compatible(bus, "arm,primecell"))
| of_amba_device_create(bus, bus_id, platform_data, parent);
| //Alloc, initialize and register an of_device
|--of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
| //对platform device的处理
|--for_each_child_of_node(bus, child)
of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
start_kernel–>arch_call_rest_init—->…—–>do_initcalls会调用of_platform_default_populate_init,此处我们重点关注of_amba_device_create,其中包含了软硬中断的映射
of_amba_device_create(bus, bus_id, platform_data, parent)
|--struct amba_device *dev;
|--dev = amba_device_alloc(NULL, 0, 0);
|--初始化dev通用设备信息
|--for (i = 0; i < AMBA_NR_IRQS; i++)
| //创建软硬中断号映射并将软中断号保存在dev->irq[i]
| dev->irq[i] = irq_of_parse_and_map(node, i);
| |--struct of_phandle_args oirq;
| | //解析中断属性存放到oirq->args[]中
| |--of_irq_parse_one(dev, index, &oirq);
| |--irq_create_of_mapping(&oirq)
| |--struct irq_fwspec fwspec;
| |--of_phandle_args_to_fwspec(oirq->np, oirq->args,oirq->args_count, &fwspec);
| |--irq_create_fwspec_mapping(&fwspec);
|--of_address_to_resource(node, 0, &dev->res);
|--amba_device_add(dev, &iomem_resource);
of_amba_device_create的过程会通过irq_of_parse_and_map为每一个硬件中断号创建映射,并将分配的软中断号保存在dev->irq[i]中
irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
|--domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
| //对硬中断号进行转换保存在hwirq中,对于gic,GIC硬中断号=dts硬中断号+32
|--irq_domain_translate(domain, fwspec, &hwirq, &type)
| //如果已经映射过则通过硬件中断号查找到虚拟中断号
|--virq = irq_find_mapping(domain, hwirq);
| //否则将根据硬件中断号,分配软件虚拟中断号, 期间会创建irq_desc
|--if (irq_domain_is_hierarchy(domain)) //级联的domain
| virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec);
| else
| virq = irq_create_mapping(domain, hwirq);
|--irq_data = irq_get_irq_data(virq);
| //设置触发类型到irq_data, 它将在request_threaded_irq->__setup_irq时会使用来设置irqaction
|--irqd_set_trigger_type(irq_data, type);
|--return virq;
4.4.5.2. irq_create_mapping
irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq)
| //Map a hardware interrupt into linux irq space,每个硬中断号只能映射到一个软中断号
|--irq_create_mapping_affinity(host, hwirq, NULL);
|--struct device_node *of_node;
|--of_node = irq_domain_get_of_node(domain);
| //Check if mapping already exists,如果存在,通过硬中断号,可以找到软中断号
|--virq = irq_find_mapping(domain, hwirq);
| if (virq)
| return virq;
|--virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node),affinity);
| //建立软中断号和硬中断号的映射关系
|--irq_domain_associate(domain, virq, hwirq)
irq_create_mapping首先通过irq_find_mapping检查是否软硬中断号映射已经存在,如果不存在则通过irq_domain_alloc_descs分配中断描述符,并返回软中断号,irq_domain_associate主要是通过线性映射或radix tree映射,以硬中断号为索引,建立硬中断号与软中断号的映射关系