linux pcie设备中断冲突,linux设备驱动之pci设备的中断请求

由上图可以看到.所有中线引脚都是连在中断请求路径互连器(下面简称为PIR)上的,然后再由它控制到8259A的连接.有一点要特别注意.在APIC中是没有PIR的,因为APIC本身就是一个可编程控制器.在本节的讨论中,我们只讨论8259A的情况.

至于中断控制器的输入引脚是和哪一个8259A的IRQ线相联.这是由PIR芯片所控制的.

闲言少述,我们从代码中看一下是怎样处理这个IRQ号的.相应的处理是在pcibios_irq_init()中完成的.先看下它的调用方式:

subsys_initcall(pcibios_irq_init);

pcibios_irq_init()是在subsys_initcall宏被调用的.在编译的时候被放至了init区域,kernel启动的时候会调用此函数.

在分析函数之前,我们先要有以下几点基本的概念:

1: PIR其实也是一个PCI设备.所以它也有对应的总线号,设备号等.也可以通过PCI寻址方式对它进行配置

2: 在确定PCI设备的中断号之前,我们需要知道.PCI设备是连在PIR的哪一个输入线上,这也是一个复杂的过程,幸好bios为我们提供了这样的功能.

好了,转入具体的代码:

static int __init pcibios_irq_init(void)

{

DBG(KERN_DEBUG "PCI: IRQ init\n");

if (pcibios_enable_irq || raw_pci_ops == NULL)

return 0;

dmi_check_system(pciirq_dmi_table);

pirq_table = pirq_find_routing_table();

#ifdef CONFIG_PCI_BIOS

if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))

pirq_table = pcibios_get_irq_routing_table();

#endif

if (pirq_table) {

pirq_peer_trick();

pirq_find_router(&pirq_router);

if (pirq_table->exclusive_irqs) {

int i;

for (i=0; i<16; i++)

if (!(pirq_table->exclusive_irqs & (1 << i)))

pirq_penalty[i] += 100;

}

/* If we're using the I/O APIC, avoid using the PCI IRQ routing table */

if (io_apic_assign_pci_irqs)

pirq_table = NULL;

}

pcibios_enable_irq = pirq_enable_irq;

pcibios_fixup_irqs();

return 0;

}

函数先调用pirq_find_routing_table()来寻找bios提供的中断路径表,代码如下 :

static struct irq_routing_table * __init pirq_find_routing_table(void)

{

u8 *addr;

struct irq_routing_table *rt;

if (pirq_table_addr) {

rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr));

if (rt)

return rt;

printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n");

}

for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {

rt = pirq_check_routing_table(addr);

if (rt)

return rt;

}

return NULL;

}

如果指定了中断路径表的地址.那直接判断它是否合法就可以了.如果没有指定,那就需要搜索bios的映射区了.

转入pirq_check_routing_table().代码如下:

static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr)

{

struct irq_routing_table *rt;

int i;

u8 sum;

rt = (struct irq_routing_table *) addr;

if (rt->signature != PIRQ_SIGNATURE ||

rt->version != PIRQ_VERSION ||

//是否低四位对齐

rt->size % 16 ||

rt->size < sizeof(struct irq_routing_table))

return NULL;

sum = 0;

//所有的值加起来必须为零.因为它后面多了一个checksum

for (i=0; i < rt->size; i++)

sum += addr[i];

if (!sum) {

DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", rt);

return rt;

}

return NULL;

}

Bios提供的中断路径表有自己的格式.对应格式的结构如下所示 :

struct irq_routing_table {

//恒定义为PIRQ_SIGNATURE

u32 signature;                    /* PIRQ_SIGNATURE should be here */

//恒为PIRQ_VERSION

u16 version;                        /* PIRQ_VERSION */

//表的大小

u16 size;                     /* Table size in bytes */

//PIR的总线号和设备功能号

u8 rtr_bus, rtr_devfn;                   /* Where the interrupt router lies */

//分配给PIR专用的IRQ

u16 exclusive_irqs;            /* IRQs devoted exclusively to PCI usage */

//PIR芯片的厂商和设备号

u16 rt

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值