内核中断笔记irq

struct device 
{
	struct irq_domain	*msi_domain; // 设备关联的是在---->irq-gic-v3-its-pci-msi.c中创建,
}

struct irq_domain
{
	void *host_data;
	struct irq_domain_ops *ops;
}


irq_domain的创建最终通过:
 __irq_domain_add函数:
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
				    irq_hw_number_t hwirq_max, int direct_max,
				    const struct irq_domain_ops *ops,  //提供ops
				    void *host_data)   //额外的host_data。有不同的意义。

层次结构:具体是irq_domain_alloc_irq_data函数建立:

系统创建的irq_domain:总共4个。通过parent成员组成 层次结构。根为ffff8020c0030400。

[    0.000000] ===__irq_domain_add domain ffff8020c0030400 name irqchip@(____ptrval____) ===    irq-gic-v3.c
[    0.000000] ===__irq_domain_add domain ffff8020c0030500 name irqchip@(____ptrval____) ===    irq-gic-v3-its.c
[    0.002937] ===__irq_domain_add domain ffff8020c0032100 name irqchip@(____ptrval____) ===    irq-gic-v3-its-pci-msi

具体创建过程:

第一个:boot核init_IRQ 函数最终调用到irq_gic_v3.c中

host_data: 是struct gic_chip_data gic_data

irq_domain_ops:gic_irq_domain_ops

参考:irq_gic_v3.c :gic_init_bases函数

[    0.000000] ===__irq_domain_add domain ffff8020c0030400 name irqchip@(____ptrr
val____) ===
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.19.0 #100
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x180
[    0.000000]  show_stack+0x24/0x30
[    0.000000]  dump_stack+0x90/0xb4
[    0.000000]  __irq_domain_add+0x1e4/0x398
[    0.000000]  gic_init_bases+0xd4/0x2dc
[    0.000000]  gic_acpi_init+0x158/0x270
[    0.000000]  acpi_match_madt+0x4c/0x84
[    0.000000]  acpi_table_parse_entries_array+0x140/0x218
[    0.000000]  acpi_table_parse_entries+0x70/0x98
[    0.000000]  acpi_table_parse_madt+0x40/0x50
[    0.000000]  __acpi_probe_device_table+0x88/0xe0
[    0.000000]  irqchip_init+0x38/0x40
[    0.000000]  init_IRQ+0xfc/0x130
[    0.000000]  start_kernel+0x330/0x4b8

  

irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED);

第二个 irq_gic_v3调用了irq_gic_v3_its中的函数创建,作为parent传递。

host_data是msi_domain_info(ops:its_msi_domain_ops)

irq_domain_ops是its_domain_ops .

参考:its_probe_one->its_init_domain函数

[    0.000000] ===__irq_domain_add domain ffff8020c0030500 name irqchip@(____ptrr
val____) ===
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.19.0 #100
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x180
[    0.000000]  show_stack+0x24/0x30
[    0.000000]  dump_stack+0x90/0xb4
[    0.000000]  __irq_domain_add+0x1e4/0x398
[    0.000000]  its_probe_one+0x8cc/0x9bc
[    0.000000]  gic_acpi_parse_madt_its+0x104/0x144
[    0.000000]  acpi_table_parse_entries_array+0x140/0x218
[    0.000000]  acpi_table_parse_entries+0x70/0x98
[    0.000000]  acpi_table_parse_madt+0x40/0x50
[    0.000000]  its_init+0x1bc/0x490
[    0.000000]  gic_init_bases+0x1d4/0x2dc
[    0.000000]  gic_acpi_init+0x158/0x270
[    0.000000]  acpi_match_madt+0x4c/0x84
[    0.000000]  acpi_table_parse_entries_array+0x140/0x218
[    0.000000]  acpi_table_parse_entries+0x70/0x98
[    0.000000]  acpi_table_parse_madt+0x40/0x50
[    0.000000]  __acpi_probe_device_table+0x88/0xe0
[    0.000000]  irqchip_init+0x38/0x40



irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_NEXUS);

第三个 最后的do_one_initcall 调用its_pci_msi_init中函数创建,在msi_create_irq_domain函数下创建。

host_data:  msi_domain_info ( ops:its_pci_msi_ops)

irq_domain_ops是 kernel/irq/msi.c提供的msi_domain_ops。

        irq_domain_ops在kernel/irq/msi.c和drivers/pci/msi.c也有,在不同的每个地方都提供了部分回调。

参考:its_pci_msi_init_one->pci_msi_create_irq_domain->msi_create_irq_domain .....

[    0.002937] ===__irq_domain_add domain ffff8020c0032100 name irqchip@(____ptrr
val____) ===
[    0.002939] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.0 #100
[    0.002941] Call trace:
[    0.002944]  dump_backtrace+0x0/0x180
[    0.002946]  show_stack+0x24/0x30
[    0.002948]  dump_stack+0x90/0xb4
[    0.002950]  __irq_domain_add+0x1e4/0x398
[    0.002953]  irq_domain_create_hierarchy+0x88/0x90
[    0.002955]  msi_create_irq_domain+0x50/0x160
[    0.002959]  pci_msi_create_irq_domain+0x80/0x160
[    0.002961]  its_pci_msi_init_one+0x94/0xd8
[    0.002963]  its_pci_msi_parse_madt+0x60/0x90
[    0.002965]  acpi_table_parse_entries_array+0x140/0x218
[    0.002967]  acpi_table_parse_entries+0x70/0x98
[    0.002969]  acpi_table_parse_madt+0x40/0x50
[    0.002971]  its_pci_msi_init+0xb8/0xcc
[    0.002973]  do_one_initcall+0x54/0x1d8
[    0.002976]  kernel_init_freeable+0x160/0x328
[    0.002978]  kernel_init+0x18/0x110
[    0.002980]  ret_from_fork+0x10/0x18



irq_domain_update_bus_token(domain, DOMAIN_BUS_PCI_MSI);
int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
                            unsigned int nr_irqs, int node, void *arg,
                            bool realloc, const struct cpumask *affinity)
{
        int i, ret, virq;

        if (domain == NULL) {
                domain = irq_default_domain;
                if (WARN(!domain, "domain is NULL; cannot allocate IRQ\n"))
                        return -EINVAL;
        }

        if (!domain->ops->alloc) {
                pr_debug("domain->ops->alloc() is NULL\n");
                return -ENOSYS;
        }

        if (realloc && irq_base >= 0) {
                virq = irq_base;
        } else {
                virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node,
                                              affinity); //创建irq_desc
                if (virq < 0) {
                        pr_debug("cannot allocate IRQ(base %d, count %d)\n",
                                 irq_base, nr_irqs);
                        return virq;
                }
        }

        if (irq_domain_alloc_irq_data(domain, virq, nr_irqs)) {  //irq_data 也会创建层次,更加parent。
                pr_debug("cannot allocate memory for IRQ%d\n", virq);
                ret = -ENOMEM;
                goto out_free_desc;
        }

        mutex_lock(&irq_domain_mutex);
        ret = irq_domain_alloc_irqs_hierarchy(domain, virq, nr_irqs, arg); //层次调用,下面日志内容,通过irq_domain_set_hwirq_and_chip 打印。
        if (ret < 0) {
                mutex_unlock(&irq_domain_mutex);
                goto out_free_irq_data;
        }
        for (i = 0; i < nr_irqs; i++)
                irq_domain_insert_irq(virq + i);
        mutex_unlock(&irq_domain_mutex);

        return virq;

out_free_irq_data:
        irq_domain_free_irq_data(virq, nr_irqs);
out_free_desc:
        irq_free_descs(virq, nr_irqs);
        return ret;
}

irq_domain_set_hwirq_and_chip 函数kernel/irq/irqdomain.c

从父到子创建。实际顺序是反的。alloc先从子到父。。

pci设备的MSI中断hwirq和virq的创建:

irq-gic-v3-its-pci-msi.c中的接口调用:

这个3145732 hwirq在函数drivers/pci/msi.c:pci_msi_domain_calc_hwirq中计算。__irq_domain_alloc_irqs下通过ops->set_desc。调到pci_msi_domain_set_desc。到pci_msi_domain_calc_hwirq

[   13.595814] ===irq_domain_set_hwirq_and_chip domain ffff8020c0032100 irq_dataa
 ffff8020c1b70c28  virq 32 hwirq 3145732 ===
[   13.606754] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.0 #100
[   13.612830] Hardware name: Phytium FT2004/FT2004, BIOS V1006 Apr  7 2020
[   13.619514] Call trace:
[   13.621947]  dump_backtrace+0x0/0x180
[   13.625595]  show_stack+0x24/0x30
[   13.628896]  dump_stack+0x90/0xb4
[   13.632196]  irq_domain_set_hwirq_and_chip+0x78/0xd8
[   13.637145]  msi_domain_ops_init+0x3c/0x80
[   13.641227]  msi_domain_alloc+0xb8/0x160
[   13.645135]  __irq_domain_alloc_irqs+0x150/0x338
[   13.649737]  msi_domain_alloc_irqs+0xa8/0x308
[   13.654079]  pci_msi_setup_msi_irqs+0x64/0x78
[   13.658421]  __pci_enable_msix+0x320/0x540
[   13.662502]  pci_alloc_irq_vectors_affinity+0x120/0x160

下面是gic-irq-v3-its.c中的alloc函数

[   13.447145] ===irq_domain_set_hwirq_and_chip domain ffff8020c0030500 irq_dataa
 ffff8020d6c8cb00  virq 32 hwirq 8197 ===
[   13.457825] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.0 #100
[   13.463902] Hardware name: Phytium FT2004/FT2004, BIOS V1006 Apr  7 2020
[   13.470586] Call trace:
[   13.473019]  dump_backtrace+0x0/0x180
[   13.476667]  show_stack+0x24/0x30
[   13.479967]  dump_stack+0x90/0xb4
[   13.483267]  irq_domain_set_hwirq_and_chip+0x78/0xd8
[   13.488216]  its_irq_domain_alloc+0x58/0x168
[   13.492471]  irq_domain_alloc_irqs_parent+0x48/0x60
[   13.497334]  msi_domain_alloc+0x7c/0x160
[   13.501242]  __irq_domain_alloc_irqs+0x150/0x338
[   13.505844]  msi_domain_alloc_irqs+0xa8/0x308
[   13.510186]  pci_msi_setup_msi_irqs+0x64/0x78
[   13.514527]  __pci_enable_msix+0x320/0x540
[   13.518609]  pci_alloc_irq_vectors_affinity+0x120/0x160

drivers/pci/msi.c函数 pci_msi_setup_msi_irqs中通过dev_get_msi_domain获取的是irq-gic-v3-its-pci-msi.c下创建的domain。然后根据其中的parent,调用irq_domain_alloc_irqs_parent从父节点的domain创建hwirq和virq的映射。

这个是gic-irq-v3.c中的:和its的hwirq是一样的,这个hwirq是gic_irq_domain_translate里面的fwspec->param[] 获取的,在its中its_irq_gic_domain_alloc 设置好的。
[   13.130169] ===irq_domain_set_hwirq_and_chip domain ffff8020c0030400 irq_dataa
 ffff8020d6c8f600  virq 32 hwirq 8197 ===
[   13.140852] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.0 #100
[   13.146929] Hardware name: Phytium FT2004/FT2004, BIOS V1006 Apr  7 2020
[   13.153613] Call trace:
[   13.156047]  dump_backtrace+0x0/0x180
[   13.159695]  show_stack+0x24/0x30
[   13.162996]  dump_stack+0x90/0xb4
[   13.166297]  irq_domain_set_hwirq_and_chip+0x78/0xd8
[   13.171246]  irq_domain_set_info+0x58/0x90
[   13.175327]  gic_irq_domain_alloc+0xdc/0x268
[   13.179582]  irq_domain_alloc_irqs_parent+0x48/0x60
[   13.184445]  its_irq_gic_domain_alloc+0xd4/0xf8
[   13.188960]  its_irq_domain_alloc+0xd0/0x168
[   13.193215]  irq_domain_alloc_irqs_parent+0x48/0x60
[   13.198078]  msi_domain_alloc+0x7c/0x160
[   13.201985]  __irq_domain_alloc_irqs+0x150/0x338
[   13.206587]  msi_domain_alloc_irqs+0xa8/0x308
[   13.210930]  pci_msi_setup_msi_irqs+0x64/0x78
[   13.215271]  __pci_enable_msix+0x320/0x540
[   13.219353]  pci_alloc_irq_vectors_affinity+0x120/0x160

pci驱动初始化irq中断:pci_alloc_irq_vectors_affinity 跟踪:

pci_alloc_irq_vectors_affinity (drivers/pci/msi.c)
	__pci_enable_msi_range
		msi_capability_init              暂分析msi部分
			pci_msi_setup_msi_irqs 			(drivers/pci/msi.c)
				msi_domain_alloc_irqs 		(kernel/irq/msi.c)
					ops->domain_alloc_irqs  (kernel/irq/msi.c) //msi_domain_ops->__msi_domain_alloc_irqs


函数:	
__msi_domain_alloc_irqs (kernel/irq/msi.c)
	msi_domain_prepare_irqs    (一个pci/x 设备分配一个its_devie :调用its_create_device 分配its_device)
 for_each_msi_entry循环:
	ops->set_desc   (kernel/irq/msi.c) (pci_msi_domain_calc_hwirq)计算出的全局唯一ID ,作为最上面的irq_data的hwirq                
	__irq_domain_alloc_irqs  //kernel/irq/irqdomain.c
			irq_domain_alloc_descs (kernel/irq/irqdomain.c) ---分配多个irq_desc
			irq_domain_alloc_irq_data (kernel/irq/irqdomain.c) ---建立irq_doamin。irq_data的层次结构
			irq_domain_alloc_irqs_hierarchy (kernel/irq/irqdomain.c)
	irq_set_msi_desc_off 		//设置msi_entry->irq 。该msi_desc 的irq_base
	irq_domain_insert_irq
	irq_domain_activate_irq   //激活msi/x中断 ,往相关的寄存器写入gic的地址。
		
	
函数:	
irq_domain_alloc_irqs_hierarchy
	domain->ops->alloc(domain, irq_base, nr_irqs, arg)  //kernel/irq/msi.c :irq_domain_ops->alloc(msi_domain_alloc)
		msi_domain_alloc
			irq_domain_alloc_irqs_parent
				irq_domain_alloc_irqs_hierarchy(domain->parent,irq_base,nr_irqsa,arg) ......层级调用 irq-gic-v3-its
					domain->ops->alloc                 //drivers/irqchip/irq-gic-v3-its.c 提供 its_irq_domain_alloc
						its_irq_domain_alloc			//drivers/irqchip/irq-gic-v3-its.c
							its_irq_gic_domain_alloc
								irq_domain_alloc_irqs_parent  //kernel/irq/irqdomain.c
									irq_domain_alloc_irqs_hierarchy(domain->parent, irq_base, nr_irqs, arg);  ----------------层级调用到irq-gic-v3
										domain->ops->alloc     //drivers/irqchip/irq-gic-v3.c  提供gic_irq_domain_alloc
											gic_irq_domain_alloc  //drivers/irqchip/irq-gic-v3.c
												gic_irq_domain_map
													irq_domain_set_info          //kernel/irq/irqdomain.c
														irq_domain_set_hwirq_and_chip  设置最底层的hwirq和irq,irq_chip
														
							irq_domain_set_hwirq_and_chip       //设置irq_data 的hwirq和irq ,irq_chip //drivers/irqchip/irq-gic-v3-its.c
			msi_domain_ops->msi_init                      kernel/irq/msi.c 提供msi_domain_ops_init
				irq_domain_set_hwirq_and_chip		设置最上层的hwirq和irq ,irq_chip
				
				
				
dmesg日志:
不同irq_domain_ops->alloc:先后关系
[   11.265652] ===gic_irq_domain_alloc domain ffff8022c0038f00 virq 47 hwirq 8205 nr_irq 1     //首先是最底层的irq-gic-v3.c
[   11.273733] ===its_irq_domain_alloc domain ffff8022c0039000 virq 47 hwirq 8205 nr_irqs 1    //其次是中级的irq-gic-v3-its.c
[   11.281899] ===msi_domain_alloc doamin ffff8022c003ad00 virq 47  hwirq 7864320 nr_irqs 1		//最后是irq-gic-v3-its-pci-msi.c 使用 kernel/irq/msi.c 的alloc

可以看出:
    每个层级的irq_data的virq是一致的,是同一个虚拟中断号。而hwirq 除了最上层的是pci_msi_domain_calc_hwirq 计算出的全局唯一ID,其它是irq-gic-v3-its.c 中根据gic驱动得出
	

设置irq_data 中    的hwirq和irq ,irq_chip
irq_domain_set_hwirq_and_chip:

其中irq_chip代表的中断芯片的配置,分别定义了三个
drivers/irqchip/irq-gic-v3.c:  gic_chip /"GICv3"
drivers/irqchip/irq-gic-v3-its.c: its_irq_chip /"ITS"
drivers/irqchip/irq-gic-v3-its-pci-msi.c: its_msi_irq_chip /"ITS-MSI"

激活msi/msix中断:

irq_domain_activate_irq
    __irq_domain_activate_irq
        domain->ops->activate //kernel/irq/msi.c 中irq_domain_ops->activate (msi_domain_activate)
            msi_domain_activate
                irq_chip_write_msi_msg




static int msi_domain_activate(struct irq_domain *domain,
                               struct irq_data *irq_data, bool early)
{
        struct msi_msg msg[2] = { [1] = { }, };

        BUG_ON(irq_chip_compose_msi_msg(irq_data, msg));
        msi_check_level(irq_data->domain, msg);
        irq_chip_write_msi_msg(irq_data, msg);
        return 0;
}


static inline void irq_chip_write_msi_msg(struct irq_data *data,
					  struct msi_msg *msg)
{
	data->chip->irq_write_msi_msg(data, msg);
}


__pci_write_msi_msg 函数是具体的写操作、

激活msi/msix中断: 


irq_domain_activate_irq
    __irq_domain_activate_irq
        domain->ops->activate //kernel/irq/msi.c 中irq_domain_ops->activate (msi_domain_activate)
            msi_domain_activate  //kernel/irq/msi.c
                irq_chip_compose_msi_msg
                irq_chip_write_msi_msg  //写msi/x 相关寄存器。写入gic地址。
                    irq_data->chip->irq_write_msi_msg(data, msg);  //此时irq_domain是its_pci_msi创建的,irq_data的 chip数据是 irq-gic-v3-its-pci-msi.c  --- irq_chip "ITS-MSI"



激活需要写入msi/x消息:
static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
{
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
        struct its_node *its;
        u64 addr;

        its = its_dev->its;
        addr = its->get_msi_base(its_dev); //调用its_irq_get_msi_base函数

        msg->address_lo         = lower_32_bits(addr); //gic——its的地址
        msg->address_hi         = upper_32_bits(addr);
        msg->data               = its_get_event_id(d);  //data
        printk("===its_irq_compose_msi_msg its_device %llx  address %llx_%llx data %u\n",msg->address_hi,msg->address_lo,msg->data);
        iommu_dma_map_msi_msg(d->irq, msg);
}  

//data的值实际上就是hwirq和当前设备的起始中断号的差。 如果一个设备只有一个,那么这个差值就是0。
static inline u32 its_get_event_id(struct irq_data *d)
{
	struct its_device *its_dev = irq_data_get_irq_chip_data(d);
	return d->hwirq - its_dev->event_map.lpi_base;
}

//获取gic——ITS的地址
static u64 its_irq_get_msi_base(struct its_device *its_dev)
{
        struct its_node *its = its_dev->its;

        return its->phys_base + GITS_TRANSLATER;
}

its_irq_compose_msi_msg:合成msi_msg。

PS:关于补丁中修改的its驱动“msi中断控制器XXXXXXXXXX”的理解:msi_base 没有转换成iova,直接使用。正常使会通过smmu进行转换的。。。
its_irq_compose_msi_msg 中注释了iommu_dma_compose_msi_msg这句话调用。
原函数的意思是需要准备msi_msg。其中有msi_base的地址(its_base+GIC_TRANSLATOR) 


static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
{
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
        struct its_node *its;
        u64 addr;

        its = its_dev->its;
        addr = its->get_msi_base(its_dev); 

        msg->address_lo         = lower_32_bits(addr);
        msg->address_hi         = upper_32_bits(addr);
        msg->data               = its_get_event_id(d);

        iommu_dma_compose_msi_msg(irq_data_get_msi_desc(d), msg); //将msi_base的地址通过 iova地址。
}

void iommu_dma_compose_msi_msg(struct msi_desc *desc,
                               struct msi_msg *msg)
{
        struct device *dev = msi_desc_to_dev(desc);
        const struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
        const struct iommu_dma_msi_page *msi_page;

        msi_page = msi_desc_get_iommu_cookie(desc); 

        if (!domain || !domain->iova_cookie || WARN_ON(!msi_page))
                return;
 
        msg->address_hi = upper_32_bits(msi_page->iova); // 地址是msi_page的iova 这个是什么是否分配的 ?? 是在its的alloc回调its_irq_domain_alloc->iommu_dma_prepare_msi
        msg->address_lo &= cookie_msi_granule(domain->iova_cookie) - 1;
        msg->address_lo += lower_32_bits(msi_page->iova);
}

iommu_dma_prepare_msi函数将	分配iommu_dma_msi_page结构体,记录msi_addr和iova。
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
{
        struct device *dev = msi_desc_to_dev(desc);
        struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
        struct iommu_dma_msi_page *msi_page;
        static DEFINE_MUTEX(msi_prepare_lock); /* see below */

        if (!domain || !domain->iova_cookie) {
                desc->iommu_cookie = NULL;
                return 0;
        }

        /*
         * In fact the whole prepare operation should already be serialised by
         * irq_domain_mutex further up the callchain, but that's pretty subtle
         * on its own, so consider this locking as failsafe documentation...
         */
        mutex_lock(&msi_prepare_lock);
        msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain);
        mutex_unlock(&msi_prepare_lock);

        msi_desc_set_iommu_cookie(desc, msi_page); //将msi_page设置到irq_desc->iommu_cookie

        if (!msi_page)
                return -ENOMEM;
        return 0;
}
			


                
                
                
                

分配的8192开始的号,,怎么开始?its_alloc_device_irq 确定msi的硬件中断号
its_device->event_map.lpi_base->lpi_base号怎么来的 ?

分配的8192开始的号,,怎么开始?its_alloc_device_irq 确定msi的硬件中断号
its_device->event_map.lpi_base->lpi_base号怎么来的 ?

gic_its初始化
its_init
	its_alloc_lpi_tables
		its_lpi_init
			free_lpi_range(8192, lpis);
				mk_lpi_range  //创建lpi_range
				list_add(&new->entry, &lpi_range_list);
				

设备初始化irq	
its_create_device	
	its_lpi_alloc
		alloc_lpi_range //为每个its_device 分配dev->event_map.lpi_base。每次在前面已经分配的后面。



msi计算hwirq过程
__pci_enable_msi_range
  msi_domain_alloc_irqs
	  info->ops->domain_alloc_irqs //kernel/irq/msi.c
	  :__msi_domain_alloc_irqs
		msi_domain_prepare_irqs
			->msi_prepare
		ops->set_desc  //pci_msi_domain_set_desc->pci_msi_domain_calc_hwirq ,计算pci设备的hwirq,通过BDF
		__irq_domain_alloc_irqs     //这个是所有irq创建都需要使用的。
			irq_domain_alloc_descs
				//创建irq_desc和virq
			irq_domain_alloc_irqs_hierarchy
				domain->ops->alloc //调用msi domain的alloc:msi_domain_alloc  ,对应其它的就直接gic_irq_domain_alloc
					msi_domain_alloc	 //msi提供的 ,hwirq前面set_desc已经计算了。
						its_irq_domain_alloc  //its的alloc
								(->its_alloc_device_irq 计算hwirq=lpi_base + idx) 
							gic_irq_domain_alloc   //gic的alloc
								(->irq_domain_set_info->gic_irq_domain_translate 计算hwirq,msi消息id)

初始化msi中断号:一个its硬件

static int __init its_alloc_lpi_tables(void)
{
        phys_addr_t paddr;

        lpi_id_bits = min_t(u32, GICD_TYPER_ID_BITS(gic_rdists->gicd_typer),
                                ITS_MAX_LPI_NRBITS);
        gic_rdists->prop_page = its_allocate_prop_table(GFP_NOWAIT);
        if (!gic_rdists->prop_page) {
                pr_err("Failed to allocate PROPBASE\n");
                return -ENOMEM;
        }

        paddr = page_to_phys(gic_rdists->prop_page);
        pr_info("===GIC: using LPI property table @%pa lpi_id_bits %u \n", &paddr,lpi_id_bits); //这里实测16 。 16个bit位????
        return its_lpi_init(lpi_id_bits);
}


static int __init its_lpi_init(u32 id_bits)
{
        u32 lpis = (1UL << id_bits) - 8192; //左移16位为65536 。意思是总共65536 - 8192个中断?
        u32 numlpis;
        int err;

        numlpis = 1UL << GICD_TYPER_NUM_LPIS(gic_rdists->gicd_typer);

        if (numlpis > 2 && !WARN_ON(numlpis > lpis)) {
                lpis = numlpis;
                pr_info("ITS: Using hypervisor restricted LPI range [%u]\n",
                        lpis);
        }

        /*
         * Initializing the allocator is just the same as freeing the
         * full range of LPIs.
         */
        err = free_lpi_range(8192, lpis);  //这里会初始化新的lpi_range 。并加入到lpi_range_list,从8192开始计算。总共65536 - 8192 个
        pr_info("===ITS: Allocator initialized for %u LPIs\n", lpis);
        return err;
}


static int free_lpi_range(u32 base, u32 nr_lpis)
{
        struct lpi_range *new;
        int err = 0;

        mutex_lock(&lpi_range_lock);

        new = mk_lpi_range(base, nr_lpis);
        if (!new) {
                err = -ENOMEM;
                goto out;
        }

        list_add(&new->entry, &lpi_range_list);
        list_sort(NULL, &lpi_range_list, lpi_range_cmp);
        merge_lpi_ranges();
out:
        mutex_unlock(&lpi_range_lock);
        return err;
}

分配中断号:

static int alloc_lpi_range(u32 nr_lpis, u32 *base)
{
        struct lpi_range *range, *tmp;
        int err = -ENOSPC;

        mutex_lock(&lpi_range_lock);

        list_for_each_entry_safe(range, tmp, &lpi_range_list, entry) {
                if (range->span >= nr_lpis) {
                        *base = range->base_id;
                        range->base_id += nr_lpis;
                        range->span -= nr_lpis;

                        if (range->span == 0) {
                                list_del(&range->entry);
                                kfree(range);
                        }

                        err = 0;
                        break;
                }
        }

        mutex_unlock(&lpi_range_lock);

        pr_info("==ITS: alloc %u:%u\n", *base, nr_lpis);
        dump_stack();
        return err;
}

dmesg日志:
[    6.293629] ==ITS: alloc 8192:1
[    6.615759] ==ITS: alloc 8193:1
[    6.905502] ==ITS: alloc 8194:1
[    7.280835] ==ITS: alloc 8195:1
[    7.582356] ==ITS: alloc 8196:1
[    7.902356] ==ITS: alloc 8197:1
[    8.198276] ==ITS: alloc 8198:1
[    8.489553] ==ITS: alloc 8199:1
[    8.787372] ==ITS: alloc 8200:1
[   11.019360] ==ITS: alloc 8201:4
[   12.709670] ==ITS: alloc 8205:1
[   16.354248] ==ITS: alloc 8206:1

pci设备注册irq相关的handle:

前面初始化的时会返回多个连续virq。

static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
{
        int i;
        int err;
        struct pci_dev *pdev = test->pdev;
        struct device *dev = &pdev->dev;

        for (i = 0; i < test->num_irqs; i++) {
                err = devm_request_irq(dev, pci_irq_vector(pdev, i),  //第i个virq
                                       pci_endpoint_test_irqhandler,
                                       IRQF_SHARED, DRV_MODULE_NAME, test);
                if (err)
                        goto fail;
        }

        return true;

}

获取第nr个virq

int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
{
	if (dev->msix_enabled) { //msix 有多个,一个irq对应一个msi_desc。
		struct msi_desc *entry;
		int i = 0;

		for_each_pci_msi_entry(entry, dev) {
			if (i == nr)
				return entry->irq; 
			i++;
		}
		WARN_ON_ONCE(1);
		return -EINVAL;
	}

	if (dev->msi_enabled) { //msi只有一个msi_desc 。里面记录了irq_base和nvec_used
		struct msi_desc *entry = first_pci_msi_entry(dev);

		if (WARN_ON_ONCE(nr >= entry->nvec_used))
			return -EINVAL;
	} else {
		if (WARN_ON_ONCE(nr > 0))
			return -EINVAL;
	}

	return dev->irq + nr; //从base 开始增加 nr 个。
}

pci_irq_vector 返回第n个irq号。用来申请irq_request。

1:根据irq找到irq_data
    根据irq找到irq_desc->irq_data

两种方式:
irq_get_irq_data:             获取virq关联的第一层irq_data。
irq_domain_get_irq_data:根据irq和domain 找到irq_data。   首先获取virq关联的第一层irq_data ,然后遍历irq_data的parent,比较doamin是否相对。

中断触发后调用gic_handle_irq函数:drivers/irqchip/irq-gic-v3.c

static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
        u32 irqnr;

        do {
                irqnr = gic_read_iar();

                if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
                        int err;

                        if (static_branch_likely(&supports_deactivate_key))
                                gic_write_eoir(irqnr);
                        else
                                isb();

                        err = handle_domain_irq(gic_data.domain, irqnr, regs);  //使用的是gic_data.domain。也就是irq_gic_v3.c创建的doamin。 其会根据hwirq找到virq。并执行handle
                        if (err) {
                                WARN_ONCE(true, "Unexpected interrupt received!\n");
                                if (static_branch_likely(&supports_deactivate_key)) {
                                        if (irqnr < 8192)
                                                gic_write_dir(irqnr);
                                } else {
                                        gic_write_eoir(irqnr);
                                }
                        }
                        continue;
                }

。。。。

}

/GSIGSI :Global System Interrupt,是ACPI spec规定的全局中断表。. 它为多IOAPIC情况下确定了系统唯一的一个中断号。. 例如IOAPIC1有24个IRQ,IOAPIC2也有24个IRQ,则IOAPIC2 的GSI是从24开始,GSI = 24 + IRQ(IOAPIC2)。. SCI :System Control Interrupt,系统控制中断,是ACPI定义的,专用于ACPI电源管理的一个IRQ。. 它在Intel平台上常常与南桥的电源管理模块一起,当外部EC等发生Event后会引发SCI。. Windows的SCI ISR程序就是著名的acpi.sys。.

非PCI的 中断hwirq和virq

[    0.000000] ===irq_domain_set_hwirq_and_chip domain ffff8020c0030400 irq_dataa
 ffff8020c0042828  virq 3 hwirq 27 ===
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.19.0 #100
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x180
[    0.000000]  show_stack+0x24/0x30
[    0.000000]  dump_stack+0x90/0xb4
[    0.000000]  irq_domain_set_hwirq_and_chip+0x78/0xd8
[    0.000000]  irq_domain_set_info+0x58/0x90
[    0.000000]  gic_irq_domain_alloc+0x170/0x268
[    0.000000]  __irq_domain_alloc_irqs+0x150/0x338
[    0.000000]  irq_create_fwspec_mapping+0x118/0x318
[    0.000000]  acpi_register_gsi+0x6c/0xa8   //在这里会设置硬件中断号:fwspec.param[0] = gsi
[    0.000000]  map_gt_gsi+0x30/0x3c
[    0.000000]  acpi_gtdt_map_ppi+0x4c/0x78
[    0.000000]  arch_timer_acpi_init+0xa4/0x280
[    0.000000]  acpi_table_parse+0xa4/0xdc

=================================================================

[    0.000000] ===irq_domain_set_hwirq_and_chip domain ffff8020c0030400 irq_data ffff8020c0042428  virq 1 hwirq 25 ===
[    0.000000] ===irq_domain_set_hwirq_and_chip domain ffff8020c0030400 irq_data ffff8020c0042628  virq 2 hwirq 30 ===
[    0.000000] ===irq_domain_set_hwirq_and_chip domain ffff8020c0030400 irq_data ffff8020c0042828  virq 3 hwirq 27 ===
.........

irq_create_fwspec_mapping :

​

unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
{
	struct irq_domain *domain;
	struct irq_data *irq_data;
	irq_hw_number_t hwirq;
	unsigned int type = IRQ_TYPE_NONE;
	int virq;

	if (fwspec->fwnode) {
		domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED); //irq-gic-v3.c irq_domain
		if (!domain)
			domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_ANY);
	} else {
		domain = irq_default_domain;
	}

	if (!domain) {
		pr_warn("no irq domain found for %s !\n",
			of_node_full_name(to_of_node(fwspec->fwnode)));
		return 0;
	}

	if (irq_domain_translate(domain, fwspec, &hwirq, &type))
		return 0;


	if (irq_domain_is_hierarchy(domain)) {
		virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec); //__irq_domain_alloc_irqs->分配virq。调用irq_domain_alloc_irqs_hierarchy:调用gic_irq_v3下的irq_domain->ops->alloc .....
		if (virq <= 0)
			return 0;
	} else {
		/* Create mapping */
		virq = irq_create_mapping(domain, hwirq);
		if (!virq)
			return virq;
	}

}



static int irq_domain_translate(struct irq_domain *d,
				struct irq_fwspec *fwspec,
				irq_hw_number_t *hwirq, unsigned int *type)
{
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
	if (d->ops->translate)
		return d->ops->translate(d, fwspec, hwirq, type); //gic_irq_domain_translate
#endif
	if (d->ops->xlate)
		return d->ops->xlate(d, to_of_node(fwspec->fwnode),
				     fwspec->param, fwspec->param_count,
				     hwirq, type);

	/* If domain has no translation, then we assume interrupt line */
	*hwirq = fwspec->param[0];
	return 0;
}



static int gic_irq_domain_translate(struct irq_domain *d,
                                    struct irq_fwspec *fwspec,
                                    unsigned long *hwirq,
                                    unsigned int *type)
{
。。。
        if (is_fwnode_irqchip(fwspec->fwnode)) {
                if(fwspec->param_count != 2)
                        return -EINVAL;

                *hwirq = fwspec->param[0];  //fwspec中记录了hwirq,在函数acpi_register_gsi
                *type = fwspec->param[1];

                WARN_ON(*type == IRQ_TYPE_NONE);
                return 0;
        }

。。。。


}

​

irq_create_fwspec_mapping后续调用: 

irq_create_fwspec_mapping
	irq_domain_alloc_irqs
		__irq_domain_alloc_irqs  //后续流程参考msi

比如acpi创建platform过程中

[    5.094866]  irq_create_fwspec_mapping+0x60/0x310
[    5.099555]  acpi_register_gsi+0x64/0xa4
[    5.103464]  acpi_dev_resource_interrupt+0x170/0x1c0
[    5.108414]  acpi_dev_process_resource+0xe0/0x160
[    5.113104]  acpi_walk_resource_buffer+0x68/0xc8
[    5.117706]  acpi_walk_resources+0xb0/0xf8
[    5.121788]  acpi_dev_get_resources+0xcc/0x130
[    5.126217]  acpi_create_platform_device+0xac/0x2b0
[    5.131080]  acpi_bus_attach+0x274/0x284
[    5.134989]  acpi_bus_attach+0x80/0x284
[    5.138810]  acpi_bus_attach+0x80/0x284
[    5.142632]  acpi_bus_scan+0x50/0xb0
[    5.146193]  acpi_scan_init+0x120/0x284
[    5.150015]  acpi_init+0x2c8/0x33c
[    5.153402]  do_one_initcall+0x50/0x2f0
[    5.157224]  kernel_init_freeable+0x340/0x3cc
[    5.161567]  kernel_init+0x20/0x140
[    5.165042]  ret_from_fork+0x10/0x18

platform_get_irq 函数:

drivers/base/platform.c

int platform_get_irq(struct platform_device *dev, unsigned int num)
{
#ifdef CONFIG_SPARC
	/* sparc does not have irqs represented as IORESOURCE_IRQ resources */
	if (!dev || num >= dev->archdata.num_irqs)
		return -ENXIO;
	return dev->archdata.irqs[num];
#else
	struct resource *r;
	if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
		int ret;

		ret = of_irq_get(dev->dev.of_node, num);
		if (ret > 0 || ret == -EPROBE_DEFER)
			return ret;
	}

	r = platform_get_resource(dev, IORESOURCE_IRQ, num); //中断是一种资源IORESOURCE_IRQ,参考acpi创建platform_device的文章
	if (has_acpi_companion(&dev->dev)) {
		if (r && r->flags & IORESOURCE_DISABLED) {
			int ret;

			ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r);
			if (ret)
				return ret;
		}
	}

	/*
	 * The resources may pass trigger flags to the irqs that need
	 * to be set up. It so happens that the trigger flags for
	 * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER*
	 * settings.
	 */
	if (r && r->flags & IORESOURCE_BITS) {
		struct irq_data *irqd;

		irqd = irq_get_irq_data(r->start);
		if (!irqd)
			return -ENXIO;
		irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS);
	}

	return r ? r->start : -ENXIO;
#endif
}

pci设备如关联设置msi_domain (irq_domain):

apic表的git:其中translation ID用来表示id。



static void pci_set_msi_domain(struct pci_dev *dev)
{
	struct irq_domain *d;

	/*
	 * If the platform or firmware interfaces cannot supply a
	 * device-specific MSI domain, then inherit the default domain
	 * from the host bridge itself.
	 */
	d = pci_dev_msi_domain(dev);
	if (!d)
		d = dev_get_msi_domain(&dev->bus->dev);

	dev_set_msi_domain(&dev->dev, d);  //设置msi_domain为找到的irq_domain
}

static struct irq_domain *pci_dev_msi_domain(struct pci_dev *dev)
{
	struct irq_domain *d;

	/*
	 * If a domain has been set through the pcibios_add_device()
	 * callback, then this is the one (platform code knows best).
	 */
	d = dev_get_msi_domain(&dev->dev);
	if (d)
		return d;

	/*
	 * Let's see if we have a firmware interface able to provide
	 * the domain.
	 */
	d = pci_msi_get_device_domain(dev);
	if (d)
		return d;

	return NULL;
}
	

struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
{
	struct irq_domain *dom;
	u32 rid = pci_dev_id(pdev);

	pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
	dom = of_msi_map_get_device_domain(&pdev->dev, rid, DOMAIN_BUS_PCI_MSI);
	if (!dom)
		dom = iort_get_device_domain(&pdev->dev, rid,
					     DOMAIN_BUS_PCI_MSI);
	return dom;
}


struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
					  enum irq_domain_bus_token bus_token)
{
	struct fwnode_handle *handle;
	int its_id;

	if (iort_dev_find_its_id(dev, id, 0, &its_id))  //参考这个获取its_id,其实就是translation id
		return NULL;

	handle = iort_find_domain_token(its_id);
	if (!handle)
		return NULL;

	return irq_find_matching_fwnode(handle, bus_token);
}

translation id 如何用?

上面用的了IORT的acpi表:

[2D0h 0720   1]                         Type : 00
[2D1h 0721   2]                       Length : 0018
[2D3h 0723   1]                     Revision : 00
[2D4h 0724   4]                     Reserved : 00000000
[2D8h 0728   4]                Mapping Count : 00000000
[2DCh 0732   4]               Mapping Offset : 00000000

[2E0h 0736   4]                     ItsCount : 00000001
[2E4h 0740   4]                  Identifiers : 0000001C  //这个和translation id匹配

[2E8h 0744   1]                         Type : 00
[2E9h 0745   2]                       Length : 0018
[2EBh 0747   1]                     Revision : 00
[2ECh 0748   4]                     Reserved : 00000000
[2F0h 0752   4]                Mapping Count : 00000000
[2F4h 0756   4]               Mapping Offset : 00000000

[2F8h 0760   4]                     ItsCount : 00000001
[2FCh 0764   4]                  Identifiers : 0000001D

iort_dev_find_its_id 日志 

[root@localhost ~]# dmesg |grep ===
[    2.191551] ===iort_dev_find_its_id dev 0000:01:00.0 id 256     2.194216] ===iort_dev_find_its_id dev 0000:01:00.1 id 257 idx 0 its->its_counts 1 its->identifiers[0] 2 
[    2.194546] ===iort_dev_find_its_id dev 0000:02:00.0 id 512 idx 0 its->its_counts 1 its->identifiers[0] 3 
[    2.194667] ===iort_dev_find_its_id dev 0000:02:00.1 id 513 idx 0 its->its_counts 1 its->identifiers[0] 3 
[    2.194786] ===iort_dev_find_its_id dev 0000:02:00.2 id 514 idx 0 its->its_counts 1 its->identifiers[0] 3 
[    2.209618] ===iort_dev_find_its_id dev 0000:04:00.0 id 1024 idx 0 its->its_counts 1 its->identifiers[0] 3 
[    2.224086] ===iort_dev_find_its_id dev 0001:01:00.0 id 256 idx 0 its->its_counts 1 its->identifiers[0] 6 
[    2.246036] ===iort_dev_find_its_id dev 0004:03:00.0 id 768 idx 0 its->its_counts 1 its->identifiers[0] 19 
[    2.261645] ===iort_dev_find_its_id dev 0004:04:00.0 id 1024 idx 0 its->its_counts 1 its->identifiers[0] 19 
[    2.276042] ===iort_dev_find_its_id dev 0005:01:00.0 id 256 idx 0 its->its_counts 1 its->identifiers[0] 22 
[    2.279045] ===iort_dev_find_its_id dev 0006:04:00.0 id 1024 idx 0 its->its_counts 1 its->identifiers[0] 27 
下面两个第0个die的设备。找到node都是ffff000075cfd5b0。根据output_refrence为78找到,表中78位置的type为0的its,its->identifiers[0] 19
[    1.712186] ===iort_dev_find_its_id start dev 0000:03:00.0 node ffff000075cfd5b0 type 2 
[    1.712189] ===iort_node_map_id 0 node ffff000075cfd5b0 type 2 mapping_offset 24 mapping_count 2 
[    1.712193] ===iort_node_map_id 1 iort_table ffff000075cfd098 rc 0 out_ref 0 map->output_reference 78 node ffff000075cfd110 
[    1.712197] ===iort_node_map_id 0 node ffff000075cfd110 type 0 mapping_offset 0 mapping_count 0 
[    1.712200] ===iort_dev_find_its_id end dev 0000:03:00.0 node ffff000075cfd110 type 0 
[    1.712204] ===iort_dev_find_its_id final dev 0000:03:00.0 id 768 idx 0 its->its_counts 1 its->identifiers[0] 3 

[    1.721490] ===iort_dev_find_its_id start dev 0000:04:00.0 node ffff000075cfd5b0 type 2 
[    1.721493] ===iort_node_map_id 0 node ffff000075cfd5b0 type 2 mapping_offset 24 mapping_count 2 
[    1.721497] ===iort_node_map_id 1 iort_table ffff000075cfd098 rc 0 out_ref 0 map->output_reference 78 node ffff000075cfd110 
[    1.721501] ===iort_node_map_id 0 node ffff000075cfd110 type 0 mapping_offset 0 mapping_count 0 
[    1.721504] ===iort_dev_find_its_id end dev 0000:04:00.0 node ffff000075cfd110 type 0 
[    1.721507] ===iort_dev_find_its_id final dev 0000:04:00.0 id 1024 idx 0 its->its_counts 1 its->identifiers[0] 3 



第4个die。找到node。根据output_refrence为1f8找到表中1f8位置的type为0的its,,its->identifiers[0] 19
[    1.756757] ===iort_dev_find_its_id start dev 0004:03:00.0 node ffff000075cfd6a4 type 2 
[    1.756760] ===iort_node_map_id 0 node ffff000075cfd6a4 type 2 mapping_offset 24 mapping_count 2 
[    1.756764] ===iort_node_map_id 1 iort_table ffff000075cfd098 rc 0 out_ref 0 map->output_reference 1f8 node ffff000075cfd290 
[    1.756768] ===iort_node_map_id 0 node ffff000075cfd290 type 0 mapping_offset 0 mapping_count 0 
[    1.756771] ===iort_dev_find_its_id end dev 0004:03:00.0 node ffff000075cfd290 type 0 
[    1.756775] ===iort_dev_find_its_id final dev 0004:03:00.0 id 768 idx 0 its->its_counts 1 its->identifiers[0] 19

die 4的acpi表内容: 

[1F8h 0504   1]                         Type : 00         //偏移1F8
[1F9h 0505   2]                       Length : 0018
[1FBh 0507   1]                     Revision : 00
[1FCh 0508   4]                     Reserved : 00000000
[200h 0512   4]                Mapping Count : 00000000
[204h 0516   4]               Mapping Offset : 00000000

[208h 0520   4]                     ItsCount : 00000001
[20Ch 0524   4]                  Identifiers : 00000013    //0x13


。。。。。。

[61Ch 1564   8]            Memory Properties : [IORT Memory Access Properties]
[61Ch 1564   4]              Cache Coherency : 00000001
[620h 1568   1]        Hints (decoded below) : 00
                                   Transient : 0
                              Write Allocate : 0
                               Read Allocate : 0
                                    Override : 0
[621h 1569   2]                     Reserved : 0000
[623h 1571   1] Memory Flags (decoded below) : 03
                                   Coherency : 1
                            Device Attribute : 1
[624h 1572   4]                ATS Attribute : 00000000
[628h 1576   4]           PCI Segment Number : 00000004   //die4 
[62Ch 1580   1]            Memory Size Limit : 30
[62Dh 1581   3]                     Reserved : 000000

[630h 1584   4]                   Input base : 00000100
[634h 1588   4]                     ID Count : 000001FF
[638h 1592   4]                  Output Base : 00000100
[63Ch 1596   4]             Output Reference : 00000998
[640h 1600   4]        Flags (decoded below) : 00000000
                              Single Mapping : 0

[644h 1604   4]                   Input base : 00000300
[648h 1608   4]                     ID Count : 000003FF
[64Ch 1612   4]                  Output Base : 00000300
[650h 1616   4]             Output Reference : 000001F8    //偏移位置1F8
[654h 1620   4]        Flags (decoded below) : 00000000
                              Single Mapping : 0

其他:

系统内所有的软件irq号:通过alloc_desc来分配数字号。
[root@localhost ~]# ls /sys/kernel/irq/
1   13  17  20  24  28  31  35  39  42  46  5   53  57  60  64  7
10  14  18  21  25  29  32  36  4   43  47  50  54  58  61  65  8
11  15  19  22  26  3   33  37  40  44  48  51  55  59  62  66  9
12  16  2   23  27  30  34  38  41  45  49  52  56  6   63  67

系统内所有已经注册中断处理函数的,有效irq统计(类似通过request_irq)
[root@localhost ~]# cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
  9:          0          0          0          0          0          0          0          0     GICv3  25 Level     vgic
 10:      11627      14660       7527      26592       8022       6787       5500       5248     GICv3  30 Level     arch_timer
 11:          0          0          0          0          0          0          0          0     GICv3  27 Level     kvm guest vtimer
 13:        211          0          0          0          0          0          0          0     GICv3  39 Level     uart-pl011
 17:          0          0          0          0          0          0          0          0     GICv3  81 Level     enaphyt4i0
 18:          0          0          0          0          0          0          0          0     GICv3  82 Level     enaphyt4i1
 21:          0          0          0          0          0          0          0          0     GICv3  44 Level     PHYT0003:00
 22:         26          0          0          0          0          0          0          0     GICv3  45 Level     PHYT0003:01
 23:          0          0          0          0          0          0          0          0     GICv3  46 Level     PHYT0003:02
 24:          0          0          0          0          0          0          0          0     GICv3  47 Level     PHYT0003:03
 29:          4          0          0          0          0          0          0          0     GICv3  80 Level     phytium_mbox_link
 36:          0          0          0          0          0          0          0          0     GICv3  23 Level     arm-pmu
 57:          0          0       3084          0          0          0          0        804   ITS-MSI 2621440 Edge      ahci[0000:05:00.0]
 58:          0          0          0         27          0          0          0          0   ITS-MSI 2097152 Edge      xhci_hcd
 59:          0          0          0          0          0          0          0          0   ITS-MSI 2099200 Edge      xhci_hcd
 60:          0          0          0          0          0          0          0          0   ITS-MSI 2101248 Edge      xhci_hcd
 61:          0          0          0          0          0          0         24          0   ITS-MSI 2103296 Edge      xhci_hcd
 62:          0          0          0          0          0          0          0         30   ITS-MSI 2105344 Edge      xhci_hcd
 63:          0          0          0          0          0          0          0          0   ITS-MSI 2107392 Edge      xhci_hcd
 64:          0        338          0          0          0        235        169          0   ITS-MSI 2109440 Edge      xhci_hcd
 65:          0          0          0          0          0          0          0          0   ITS-MSI 2111488 Edge      xhci_hcd
 66:          0          0          0          2          0          0          0          0   ITS-MSI 7342080 Edge      phytium-mci
 67:          0          0          0          0          2          0          0          0   ITS-MSI 7344128 Edge      phytium-mci
IPI0:      1609       1403       1490       1614       4722       4049       7434       3299       Rescheduling interrupts
IPI1:     12383        501       1225        453       1310        942        743        614       Function call interrupts
IPI2:         0          0          0          0          0          0          0          0       CPU stop interrupts
IPI3:         0          0          0          0          0          0          0          0       CPU stop (for crash dump) interrupts
IPI4:         0          0          0          0          0          0          0          0       Timer broadcast interrupts
IPI5:       113         83        139        141        514        302        343        389       IRQ work interrupts
IPI6:         0          0          0          0          0          0          0          0       CPU wake-up interrupts
Err:          0


中断先分配内核虚拟irq号:
比如在arm64系统gicv3中线通过gic_init_bases提前创建了8个包括IPI和Err中断号,从1到8(/proc/interrupts中的IPI显示从0开始)
[    0.000000] ===alloc_desc of irq 1
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1b4
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  alloc_desc+0x1dc/0x1ec
[    0.000000]  __irq_alloc_descs+0x190/0x2f0
[    0.000000]  irq_domain_alloc_descs.part.0+0x60/0xc0
[    0.000000]  __irq_domain_alloc_irqs+0x2b0/0x480
[    0.000000]  gic_init_bases+0x500/0x59c
[    0.000000]  gic_acpi_init+0x138/0x280
[    0.000000]  acpi_match_madt+0x50/0x88
[    0.000000]  acpi_table_parse_entries_array+0x170/0x260
[    0.000000]  acpi_table_parse_entries+0x48/0x70
[    0.000000]  acpi_table_parse_madt+0x34/0x40
[    0.000000]  __acpi_probe_device_table+0x90/0xec
[    0.000000]  irqchip_init+0x40/0x4c
[    0.000000]  init_IRQ+0xd0/0x104
[    0.000000]  start_kernel+0x350/0x554
[    0.000000] ===alloc_desc of irq 2
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1b4
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  alloc_desc+0x1dc/0x1ec
[    0.000000]  __irq_alloc_descs+0x190/0x2f0
[    0.000000]  irq_domain_alloc_descs.part.0+0x60/0xc0
[    0.000000]  __irq_domain_alloc_irqs+0x2b0/0x480
[    0.000000]  gic_init_bases+0x500/0x59c
[    0.000000]  gic_acpi_init+0x138/0x280
[    0.000000]  acpi_match_madt+0x50/0x88
[    0.000000]  acpi_table_parse_entries_array+0x170/0x260
[    0.000000]  acpi_table_parse_entries+0x48/0x70
[    0.000000]  acpi_table_parse_madt+0x34/0x40
[    0.000000]  __acpi_probe_device_table+0x90/0xec
[    0.000000]  irqchip_init+0x40/0x4c
[    0.000000]  init_IRQ+0xd0/0x104
[    0.000000]  start_kernel+0x350/0x554
[    0.000000] ===alloc_desc of irq 3
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1b4
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  alloc_desc+0x1dc/0x1ec
[    0.000000]  __irq_alloc_descs+0x190/0x2f0
[    0.000000]  irq_domain_alloc_descs.part.0+0x60/0xc0
[    0.000000]  __irq_domain_alloc_irqs+0x2b0/0x480
[    0.000000]  gic_init_bases+0x500/0x59c
[    0.000000]  gic_acpi_init+0x138/0x280
....

[    0.000000] ===alloc_desc of irq 8
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1b4
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  alloc_desc+0x1dc/0x1ec
[    0.000000]  __irq_alloc_descs+0x190/0x2f0
[    0.000000]  irq_domain_alloc_descs.part.0+0x60/0xc0
[    0.000000]  __irq_domain_alloc_irqs+0x2b0/0x480
[    0.000000]  gic_init_bases+0x500/0x59c
[    0.000000]  gic_acpi_init+0x138/0x280
[    0.000000]  acpi_match_madt+0x50/0x88
[    0.000000]  acpi_table_parse_entries_array+0x170/0x260
[    0.000000]  acpi_table_parse_entries+0x48/0x70
[    0.000000]  acpi_table_parse_madt+0x34/0x40
[    0.000000]  __acpi_probe_device_table+0x90/0xec
[    0.000000]  irqchip_init+0x40/0x4c
[    0.000000]  init_IRQ+0xd0/0x104
[    0.000000]  start_kernel+0x350/0x554

=========================================================

[    0.000000] ===alloc_desc of irq 9
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1b4
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  alloc_desc+0x1dc/0x1ec
[    0.000000]  __irq_alloc_descs+0x190/0x2f0
[    0.000000]  irq_domain_alloc_descs.part.0+0x60/0xc0
[    0.000000]  __irq_domain_alloc_irqs+0x2b0/0x480
[    0.000000]  irq_create_fwspec_mapping+0x118/0x324
[    0.000000]  acpi_register_gsi+0x64/0xac
[    0.000000]  gic_acpi_init+0x1a8/0x280
[    0.000000]  acpi_match_madt+0x50/0x88
[    0.000000]  acpi_table_parse_entries_array+0x170/0x260
[    0.000000]  acpi_table_parse_entries+0x48/0x70
[    0.000000]  acpi_table_parse_madt+0x34/0x40
[    0.000000]  __acpi_probe_device_table+0x90/0xec
[    0.000000]  irqchip_init+0x40/0x4c
[    0.000000]  init_IRQ+0xd0/0x104
[    0.000000]  start_kernel+0x350/0x554
[    0.000000] random: get_random_bytes called from start_kernel+0x390/0x554 with crng_init=0
[    0.000000] ===alloc_desc of irq 10
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1b4
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  alloc_desc+0x1dc/0x1ec
[    0.000000]  __irq_alloc_descs+0x190/0x2f0
[    0.000000]  irq_domain_alloc_descs.part.0+0x60/0xc0
[    0.000000]  __irq_domain_alloc_irqs+0x2b0/0x480
[    0.000000]  irq_create_fwspec_mapping+0x118/0x324
[    0.000000]  acpi_register_gsi+0x64/0xac
[    0.000000]  map_gt_gsi+0x2c/0x38
[    0.000000]  acpi_gtdt_map_ppi+0x50/0x7c
[    0.000000]  arch_timer_acpi_init+0x84/0x28c
[    0.000000]  acpi_table_parse+0xa4/0xe8
[    0.000000]  __acpi_probe_device_table+0xa4/0xec
[    0.000000]  timer_probe+0xd0/0x11c
[    0.000000]  time_init+0x24/0x5c
[    0.000000]  start_kernel+0x3f0/0x554
[    0.000000] ===alloc_desc of irq 11
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1b4
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  alloc_desc+0x1dc/0x1ec
[    0.000000]  __irq_alloc_descs+0x190/0x2f0
[    0.000000]  irq_domain_alloc_descs.part.0+0x60/0xc0
[    0.000000]  __irq_domain_alloc_irqs+0x2b0/0x480
[    0.000000]  irq_create_fwspec_mapping+0x118/0x324
[    0.000000]  acpi_register_gsi+0x64/0xac
[    0.000000]  map_gt_gsi+0x2c/0x38
[    0.000000]  acpi_gtdt_map_ppi+0x44/0x7c
[    0.000000]  arch_timer_acpi_init+0x98/0x28c
[    0.000000]  acpi_table_parse+0xa4/0xe8
[    0.000000]  __acpi_probe_device_table+0xa4/0xec
[    0.000000]  timer_probe+0xd0/0x11c
[    0.000000]  time_init+0x24/0x5c
[    0.000000]  start_kernel+0x3f0/0x554
[    0.000000] ===alloc_desc of irq 12
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1b4
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  alloc_desc+0x1dc/0x1ec
[    0.000000]  __irq_alloc_descs+0x190/0x2f0
[    0.000000]  irq_domain_alloc_descs.part.0+0x60/0xc0
[    0.000000]  __irq_domain_alloc_irqs+0x2b0/0x480
[    0.000000]  irq_create_fwspec_mapping+0x118/0x324
[    0.000000]  acpi_register_gsi+0x64/0xac
[    0.000000]  map_gt_gsi+0x2c/0x38
[    0.000000]  acpi_gtdt_map_ppi+0x5c/0x7c
[    0.000000]  arch_timer_acpi_init+0xa8/0x28c
[    0.000000]  acpi_table_parse+0xa4/0xe8
[    0.000000]  __acpi_probe_device_table+0xa4/0xec
[    0.000000]  timer_probe+0xd0/0x11c
[    0.000000]  time_init+0x24/0x5c
[    0.000000]  start_kernel+0x3f0/0x554

13号开的是串口的:
[    0.359015] ===alloc_desc of irq 13
[    0.359022] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.359027] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[    0.359031] Call trace:
[    0.359040]  dump_backtrace+0x0/0x1b4
[    0.359045]  show_stack+0x24/0x70
[    0.359051]  dump_stack+0xd0/0x12c
[    0.359056]  alloc_desc+0x1dc/0x1ec
[    0.359061]  __irq_alloc_descs+0x190/0x2f0
[    0.359065]  irq_domain_alloc_descs.part.0+0x60/0xc0
[    0.359070]  __irq_domain_alloc_irqs+0x2b0/0x480
[    0.359074]  irq_create_fwspec_mapping+0x118/0x324
[    0.359080]  acpi_register_gsi+0x64/0xac
[    0.359085]  acpi_dev_resource_interrupt+0x170/0x1c0
[    0.359089]  acpi_dev_process_resource+0xe8/0x164
[    0.359093]  acpi_walk_resource_buffer+0x68/0xc8
[    0.359097]  acpi_walk_resources+0xb0/0xf8
[    0.359100]  acpi_dev_get_resources+0xcc/0x130
[    0.359104]  acpi_create_platform_device.part.0+0x50/0x240
[    0.359108]  acpi_create_platform_device+0x60/0x90
[    0.359113]  acpi_bus_attach+0x25c/0x270
[    0.359117]  acpi_bus_attach+0x78/0x270
[    0.359121]  acpi_bus_attach+0x78/0x270
[    0.359125]  acpi_bus_scan+0x50/0xb0
[    0.359131]  acpi_scan_init+0x118/0x27c
[    0.359134]  acpi_init+0x2b8/0x32c
[    0.359138]  do_one_initcall+0x50/0x260
[    0.359142]  kernel_init_freeable+0x22c/0x2c0
[    0.359146]  kernel_init+0x20/0x124
[    0.359150]  ret_from_fork+0x10/0x30
MSI:
[   66.494858] ===alloc_desc of irq 67
[   66.499496] CPU: 3 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[   66.510150] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[   66.516820] Call trace:
[   66.520445]  dump_backtrace+0x0/0x1b4
[   66.525273]  show_stack+0x24/0x70
[   66.529781]  dump_stack+0xd0/0x12c
[   66.534347]  alloc_desc+0x1dc/0x1ec
[   66.539037]  __irq_alloc_descs+0x190/0x2f0
[   66.544324]  irq_domain_alloc_descs.part.0+0x60/0xc0
[   66.550508]  __irq_domain_alloc_irqs+0x2b0/0x480
[   66.556339]  __msi_domain_alloc_irqs+0xa0/0x2f0
[   66.562073]  msi_domain_alloc_irqs+0x28/0x34
[   66.567570]  __pci_enable_msi_range+0x4cc/0x5a0
[   66.573289]  pci_enable_msi+0x28/0x40
[   66.578117]  phytium_mci_pci_probe+0x9c/0x230
[   66.583631]  local_pci_probe+0x4c/0xc0
[   66.588517]  pci_device_probe+0x120/0x1c0
[   66.593664]  really_probe+0xec/0x494
[   66.598400]  driver_probe_device+0x64/0xcc
[   66.603574]  device_driver_attach+0xcc/0xd4
[   66.608838]  __driver_attach+0x90/0x130
[   66.613714]  bus_for_each_dev+0x7c/0xe0
[   66.618549]  driver_attach+0x30/0x40
[   66.623082]  bus_add_driver+0x114/0x200
[   66.627824]  driver_register+0x84/0x140
[   66.632539]  __pci_register_driver+0x50/0x5c
[   66.637694]  phytium_mci_pci_driver_init+0x30/0x3c
[   66.643363]  do_one_initcall+0x50/0x260
[   66.648104]  kernel_init_freeable+0x22c/0x2c0

======================================================申请/proc/irq/IRQ
通过register_irq_proc来创建/proc/irq/IRQ/目录:
前面12个是早期创建好的。包含IPI和arch_timer等。。

[    0.343295] ===register_irq_proc of irq 1
[    0.343302] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.343307] Call trace:
[    0.343314]  dump_backtrace+0x0/0x1b4
[    0.343319]  show_stack+0x24/0x70
[    0.343324]  dump_stack+0xd0/0x12c
[    0.343329]  register_irq_proc+0xfc/0x1e0
[    0.343332]  init_irq_proc+0x88/0xd0
[    0.343338]  kernel_init_freeable+0x158/0x2c0
[    0.343342]  kernel_init+0x20/0x124
[    0.343346]  ret_from_fork+0x10/0x30
[    0.343355] ===register_irq_proc of irq 2
[    0.343359] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.343363] Call trace:
[    0.343367]  dump_backtrace+0x0/0x1b4
[    0.343371]  show_stack+0x24/0x70
[    0.343375]  dump_stack+0xd0/0x12c
[    0.343378]  register_irq_proc+0xfc/0x1e0
[    0.343382]  init_irq_proc+0x88/0xd0
[    0.343385]  kernel_init_freeable+0x158/0x2c0
[    0.343389]  kernel_init+0x20/0x124
[    0.343393]  ret_from_fork+0x10/0x30
.....

[    0.343785] ===register_irq_proc of irq 12
[    0.343788] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[    0.343792] Call trace:
[    0.343796]  dump_backtrace+0x0/0x1b4
[    0.343800]  show_stack+0x24/0x70
[    0.343804]  dump_stack+0xd0/0x12c
[    0.343807]  register_irq_proc+0xfc/0x1e0
[    0.343811]  init_irq_proc+0x88/0xd0
[    0.343814]  kernel_init_freeable+0x158/0x2c0
[    0.343817]  kernel_init+0x20/0x124
[    0.343821]  ret_from_fork+0x10/0x30

....
[  116.715696] ===register_irq_proc of irq 17
[  116.721631] CPU: 7 PID: 758 Comm: NetworkManager Not tainted 5.10.0-with-dc-g3d8cd6f7086d-dirty #87
[  116.734135] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[  116.741405] Call trace:
[  116.745650]  dump_backtrace+0x0/0x1b4
[  116.751089]  show_stack+0x24/0x70
[  116.756222]  dump_stack+0xd0/0x12c
[  116.761447]  register_irq_proc+0xfc/0x1e0
[  116.767232]  __setup_irq+0x4fc/0x8a0
[  116.772578]  request_threaded_irq+0xe8/0x1b0
[  116.778613]  stmmac_open+0x70c/0xd2c
[  116.783928]  __dev_open+0x108/0x1a0
[  116.789193]  __dev_change_flags+0x170/0x1d0
[  116.795175]  dev_change_flags+0x30/0x70
[  116.800675]  do_setlink+0x21c/0xdac
[  116.805803]  __rtnl_newlink+0x514/0x820
[  116.811250]  rtnl_newlink+0x5c/0x90
[  116.816303]  rtnetlink_rcv_msg+0x128/0x364
[  116.821919]  netlink_rcv_skb+0x68/0x134
[  116.824599] random: crng init done  systemd-random-
[  116.827235]  rtnetlink_rcv+0x24/0x30
[  116.838833]  netlink_unicast+0x244/0x314
[  116.838838]  netlink_sendmsg+0x1b4/0x3cc
[  116.849431]  ____sys_sendmsg+0x14c/0x200
[  116.849435]  ___sys_sendmsg+0x8c/0x100
[  116.859626]  __sys_sendmsg+0x64/0xbc
[  116.859628]  __arm64_sys_sendmsg+0x30/0x40
[  116.859635]  do_el0_svc+0x94/0x1f0
[  116.874329]  el0_svc+0x20/0x30
[  116.874332]  el0_sync_handler+0x1a4/0x1c0
[  116.883648]  el0_sync+0x174/0x180









不同类型的中断建立virq和hwirq的流程:调用doman->alloc

sgi/ipi:一次申请8个,核间


[    0.000000] ===gic_irq_domain_alloc virq 1 to hwirq 0 m
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g1c56f5c219bc-dirty #115
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1c0
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  gic_irq_domain_alloc+0x74/0x2a4
[    0.000000]  __irq_domain_alloc_irqs+0x17c/0x480
[    0.000000]  gic_init_bases+0x504/0x5a4
[    0.000000]  gic_acpi_init+0x138/0x280
[    0.000000]  acpi_match_madt+0x50/0x88
[    0.000000]  acpi_table_parse_entries_array+0x170/0x260
[    0.000000]  acpi_table_parse_entries+0x4c/0x78
[    0.000000]  acpi_table_parse_madt+0x34/0x40
[    0.000000]  __acpi_probe_device_table+0x90/0xec
[    0.000000]  irqchip_init+0x40/0x4c
[    0.000000]  init_IRQ+0xd0/0x104
[    0.000000]  start_kernel+0x354/0x55c

ppi:私有,比如时钟 

	

[    0.000000] ===gic_irq_domain_alloc virq 10 to hwirq 30 m
[    0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-with-dc-g1c56f5c219bc-dirty #115
[    0.000000] Call trace:
[    0.000000]  dump_backtrace+0x0/0x1c0
[    0.000000]  show_stack+0x24/0x70
[    0.000000]  dump_stack+0xd0/0x12c
[    0.000000]  gic_irq_domain_alloc+0x74/0x2a4
[    0.000000]  __irq_domain_alloc_irqs+0x17c/0x480
[    0.000000]  irq_create_fwspec_mapping+0x11c/0x330
[    0.000000]  acpi_register_gsi+0x68/0xb0
[    0.000000]  map_gt_gsi+0x2c/0x38
[    0.000000]  acpi_gtdt_map_ppi+0x50/0x7c
[    0.000000]  arch_timer_acpi_init+0x88/0x298
[    0.000000]  acpi_table_parse+0xa8/0xf0
[    0.000000]  __acpi_probe_device_table+0xa4/0xec
[    0.000000]  timer_probe+0xd8/0x128
[    0.000000]  time_init+0x24/0x5c
[    0.000000]  start_kernel+0x3f4/0x55c

spi:共享外设,比如串口 

	

[    0.396072] ===gic_irq_domain_alloc virq 13 to hwirq 39 m
[    0.396077] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g1c56f5c219bc-dirty #115
[    0.396085] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[    0.396089] Call trace:
[    0.396098]  dump_backtrace+0x0/0x1c0
[    0.396103]  show_stack+0x24/0x70
[    0.396109]  dump_stack+0xd0/0x12c
[    0.396116]  gic_irq_domain_alloc+0x74/0x2a4  //直接一层gic的domain
[    0.396122]  __irq_domain_alloc_irqs+0x17c/0x480
[    0.396126]  irq_create_fwspec_mapping+0x11c/0x330
[    0.396133]  acpi_register_gsi+0x68/0xb0
[    0.396137]  acpi_dev_resource_interrupt+0x170/0x1c0
[    0.396142]  acpi_dev_process_resource+0xec/0x174
[    0.396147]  acpi_walk_resource_buffer+0x68/0xc8
[    0.396151]  acpi_walk_resources+0xb4/0x100
[    0.396155]  acpi_dev_get_resources+0xd4/0x140
[    0.396160]  acpi_create_platform_device.part.0+0x54/0x240
[    0.396164]  acpi_create_platform_device+0x60/0x90
[    0.396168]  acpi_bus_attach+0x26c/0x280
[    0.396172]  acpi_bus_attach+0x80/0x280
[    0.396175]  acpi_bus_attach+0x80/0x280
[    0.396179]  acpi_bus_scan+0x54/0xbc
[    0.396185]  acpi_scan_init+0x11c/0x284
[    0.396188]  acpi_init+0x2bc/0x334
[    0.396193]  do_one_initcall+0x54/0x26c
[    0.396198]  kernel_init_freeable+0x22c/0x2c0
[    0.396204]  kernel_init+0x20/0x124
[    0.396208]  ret_from_fork+0x10/0x30


msi: pci设备  经过三层alloc


[   20.093421] ===gic_irq_domain_alloc virq 69 to hwirq 8249 m
[   20.093424] CPU: 4 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g1c56f5c219bc-dirty #115
[   20.111113] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[   20.117887] Call trace:
[   20.121583]  dump_backtrace+0x0/0x1c0
[   20.126494]  show_stack+0x24/0x70
[   20.131078]  dump_stack+0xd0/0x12c
[   20.135705]  gic_irq_domain_alloc+0x74/0x2a4  //gic domain alloc
[   20.141244]  irq_domain_alloc_irqs_parent+0x30/0x44
[   20.147385]  its_irq_gic_domain_alloc+0x94/0xdc
[   20.153169]  its_irq_domain_alloc+0xfc/0x154        //its domain alloc
[   20.158720]  irq_domain_alloc_irqs_parent+0x30/0x44
[   20.164856]  msi_domain_alloc+0x84/0x150              //msi domain的alloc
[   20.170020]  __irq_domain_alloc_irqs+0x17c/0x480
[   20.175952]  __msi_domain_alloc_irqs+0xa0/0x2f4
[   20.181754]  msi_domain_alloc_irqs+0x28/0x34
[   20.187322]  __pci_enable_msi_range+0x4d4/0x5b0
[   20.193165]  pci_alloc_irq_vectors_affinity+0xf4/0x150
[   20.199621]  xhci_run+0x1bc/0x5b0
[   20.204204]  usb_add_hcd+0x394/0x6d0
[   20.209057]  usb_hcd_pci_probe+0x1fc/0x3ac
[   20.214329]  xhci_pci_probe+0xfc/0x2e0
[   20.219212]  local_pci_probe+0x4c/0xc0
[   20.224019]  pci_device_probe+0x128/0x1c4
[   20.229041]  really_probe+0xec/0x494
[   20.233591]  driver_probe_device+0x64/0xcc
[   20.238618]  device_driver_attach+0xcc/0xd4
[   20.243700]  __driver_attach+0x90/0x130
[   20.248417]  bus_for_each_dev+0x80/0xe0
[   20.253127]  driver_attach+0x30/0x3c



__pci_enable_msi_range
  msi_domain_alloc_irqs
	  info->ops->domain_alloc_irqs //kernel/irq/msi.c
	  :__msi_domain_alloc_irqs
		msi_domain_prepare_irqs
			->msi_prepare
		ops->set_desc  //pci_msi_domain_set_desc->pci_msi_domain_calc_hwirq ,计算pci设备的hwirq,通过BDF
		__irq_domain_alloc_irqs     //这个是所有irq创建都需要使用的。
			irq_domain_alloc_descs
				//创建irq_desc和virq
			irq_domain_alloc_irqs_hierarchy
				domain->ops->alloc //调用msi domain的alloc:msi_domain_alloc  ,对应其它的就直接gic_irq_domain_alloc
					msi_domain_alloc	 //msi提供的 ,hwirq前面set_desc已经计算了。
						its_irq_domain_alloc  //its的alloc
								(->its_alloc_device_irq 计算hwirq=lpi_base + idx) 
							gic_irq_domain_alloc   //gic的alloc
								(->irq_domain_set_info->gic_irq_domain_translate 计算hwirq,msi消息id)

irq-gic-v3-its-pci-msi.c创建msi domain:DOMAIN_BUS_PCI_MSI 

acpi表中一个ITS。包含四个core。创建一个its_node/一个irq_domain/一个msi_domain_info

一个pci设备的dev_id可以通过its_finnd_device查找/创建对应的its_device。创建的时候加入到its_device_list列表中关联起来。

pci设备默认的domain从bus获取。pci_msi_get_device_domain

bus的domain通过irq_domain_update_bus_token :DOMAIN_BUS_PCI_MSI
[    0.001703] Platform MSI: ITS@0x29a20000 domain created
[    0.001712] ===irq_domain_update_bus_token domain irqchip@0x0000000029a20000-3 
[    0.001717] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g1c56f5c219bc-dirty #116
[    0.001721] Call trace:
[    0.001725]  dump_backtrace+0x0/0x1c0
[    0.001729]  show_stack+0x24/0x70
[    0.001733]  dump_stack+0xd0/0x12c
[    0.001737]  irq_domain_update_bus_token+0x8c/0xc0
[    0.001743]  pci_msi_create_irq_domain+0x58/0x154
[    0.001747]  its_pci_msi_init_one+0x98/0xec
[    0.001751]  its_pci_msi_parse_madt+0x64/0x98
[    0.001755]  acpi_table_parse_entries_array+0x170/0x260
[    0.001759]  acpi_table_parse_entries+0x4c/0x78
[    0.001763]  acpi_table_parse_madt+0x34/0x40
[    0.001766]  its_pci_msi_init+0xc0/0xd8
[    0.001770]  do_one_initcall+0x54/0x26c
[    0.001774]  kernel_init_freeable+0x130/0x2c0
[    0.001778]  kernel_init+0x20/0x124
[    0.001782]  ret_from_fork+0x10/0x30

一个pci设备如何关联到domain? 


pci设备申请msi中断函数,pci_msi_setup_msi_irqs:
static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
        struct irq_domain *domain;

        domain = dev_get_msi_domain(&dev->dev);     //获取device->msi_domain  ?何时设置的 (1)。
        if (domain && irq_domain_is_hierarchy(domain))
                return msi_domain_alloc_irqs(domain, &dev->dev, nvec);  //根据domain申请irq

        return arch_setup_msi_irqs(dev, nvec, type);
}

(1)pci设备扫描的时候
pci_device_add  先是bus
	pci_set_msi_domain
	{	pci_dev_msi_domain
		{	dev_get_msi_domain
		or:pci_msi_get_device_domain         //通过这里获取msi domain
			iort_get_device_domain             //根据iort表信息,结合pci设备dev_id来查找
		}
	or:dev_get_msi_domain
		dev_set_msi_domain //设置msi_domain
	}
	

[    6.291711] ===pci_msi_get_device_domain 0000:00:05.0 domain irqchip@0x0000000029a20000-3
[    6.299877] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.10.0-with-dc-g1c56f5c219bc-dirty #119
[    6.308385] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[    6.313857] Call trace:
[    6.316291]  dump_backtrace+0x0/0x1c0
[    6.319941]  show_stack+0x24/0x70
[    6.323243]  dump_stack+0xd0/0x12c
[    6.326632]  pci_msi_get_device_domain+0xe8/0x100
[    6.331323]  pci_set_msi_domain+0x50/0x84
[    6.335319]  pci_device_add+0x1e0/0x6fc
[    6.339142]  pci_scan_single_device+0x128/0x160
[    6.343659]  pci_scan_slot+0x4c/0x170
[    6.347309]  pci_scan_child_bus_extend+0x5c/0x2b0
[    6.351999]  pci_scan_child_bus+0x20/0x30
[    6.355996]  acpi_pci_root_create+0x21c/0x320
[    6.360339]  pci_acpi_scan_root+0x150/0x24c
[    6.364509]  acpi_pci_root_add+0x2ec/0x4b0
[    6.368592]  acpi_bus_attach+0x10c/0x280
[    6.372501]  acpi_bus_attach+0x80/0x280
[    6.376324]  acpi_bus_attach+0x80/0x280
[    6.380146]  acpi_bus_scan+0x54/0xbc
[    6.383709]  acpi_scan_init+0x11c/0x284
[    6.387532]  acpi_init+0x2bc/0x334
[    6.390921]  do_one_initcall+0x54/0x26c
[    6.394743]  kernel_init_freeable+0x22c/0x2c0
[    6.399087]  kernel_init+0x20/0x124
	

一个pci设备如何找到对应的msi domain: 流程是通过iort表,查找对应的rootcomplex节点。

根据output reference偏移量找到its group节点。

再找到its_id。找到fwnode_handle,这个是一个its设备一个,保存在msi domain和its设备中。

struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
					  enum irq_domain_bus_token bus_token)
{
	struct fwnode_handle *handle;
	int its_id;

	if (iort_dev_find_its_id(dev, id, 0, &its_id)) //获取its_id;   
		return NULL;                                

	handle = iort_find_domain_token(its_id);  //根据找到its_id/translatin_id。遍历所有的its设备,获取fwnode_handle,对应its设备
	if (!handle)
		return NULL;

	return irq_find_matching_fwnode(handle, bus_token); //根据bus_token以及fwnode_handle,遍历所有msi doamin(irq_domain_list) 。msi domain中也有fwnode_handle,如果相同则返回
}	
	
static int iort_dev_find_its_id(struct device *dev, u32 id,
				unsigned int idx, int *its_id)
{
	struct acpi_iort_its_group *its;
	struct acpi_iort_node *node;

	node = iort_find_dev_node(dev);    //找到IORT的ACPI_IORT_NODE_PCI_ROOT_COMPLEX ,根据pci的segment,也就是domain。
	if (!node)
		return -ENXIO;

	node = iort_node_map_id(node, id, NULL, IORT_MSI_TYPE);        //ACPI_IORT_NODE_PCI_ROOT_COMPLEX 类型有个Output Reference 偏移量,指向ACPI_IORT_NODE_ITS_GROUP类型
	if (!node)
		return -ENXIO;

	/* Move to ITS specific data */
	its = (struct acpi_iort_its_group *)node->node_data;   //ACPI_IORT_NODE_ITS_GROUP数据
	if (idx >= its->its_count) {
		dev_err(dev, "requested ITS ID index [%d] overruns ITS entries [%d]\n",
			idx, its->its_count);
		return -ENXIO;
	}

	*its_id = its->identifiers[idx];
	return 0;
}


irq_find_matching_fwnode
	irq_find_matching_fwspec(&fwspec, bus_token);
struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
					    enum irq_domain_bus_token bus_token)
{
	struct irq_domain *h, *found = NULL;
	struct fwnode_handle *fwnode = fwspec->fwnode;
	int rc;

	/* We might want to match the legacy controller last since
	 * it might potentially be set to match all interrupts in
	 * the absence of a device node. This isn't a problem so far
	 * yet though...
	 *
	 * bus_token == DOMAIN_BUS_ANY matches any domain, any other
	 * values must generate an exact match for the domain to be
	 * selected.
	 */
	mutex_lock(&irq_domain_mutex);
	list_for_each_entry(h, &irq_domain_list, link) {  //__irq_domain_add 创建的domain 都挂在这个列表中。
		if (h->ops->select && fwspec->param_count)
			rc = h->ops->select(h, fwspec, bus_token);
		else if (h->ops->match)
			rc = h->ops->match(h, to_of_node(fwnode), bus_token);
		else
			rc = ((fwnode != NULL) && (h->fwnode == fwnode) &&
			      ((bus_token == DOMAIN_BUS_ANY) ||
			       (h->bus_token == bus_token)));

		if (rc) {
			found = h;
			break;
		}
	}
	mutex_unlock(&irq_domain_mutex);
	return found;
}
EXPORT_SYMBOL_GPL(irq_find_matching_fwspec);

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古井无波 2024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值