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映射,以硬中断号为索引,建立硬中断号与软中断号的映射关系