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);