Tiano下的PCI中断

最近老和总线纠缠不清,这不PCI又来捣乱,要说俺对于PCI总线的认识,那可是“相~当~”的无知。不过无知者无畏,本着“实践是检验真理的唯一标准”的原则,花了几天时间在TIANO/Linux下一通折腾,小有心得,记载如下:
 
大部分是根据调试Linux/TIANO的现象自己的猜测,应该基本正确。

先从硬件说起:
对于PCI总线,一共有8个中断线(INTA~INTH),采用电平触发可共享。
对于PCI设备,DEVICE和SLOT含义等价。每个SLOT有4个中断引脚(PINA~PIND),
设计好的PCI板卡可以使用4个中断引脚之中的任意N个。显然只有板卡设计者知
道设备用了SLOT上的哪些中断引脚,告诉BIOS的方法就是在每个FUNCTION的PCI
配置空间IRQ Pin(0x3D)处显示用了哪个PIN脚,为0表示不产生中断。
对于每个PCI SLOT上的4个中断引脚如何对应系统PCI总线上的8条中断线,这个
是固定的平台相关的或者说只有BIOS知道。
例如,Bridgeport平台上,BUS4 DEVICE0的eth0(FUNC0)和eth1(FUNC1)分别占
用PINA和PIND中断引脚,在这个SLOT上PINA对应PCI中断线INTC,PINB对应INTD。
然后需要把INTA~INTH映射到8259A上,这个是通过南桥ICHx上的LPC(D31:F0)实
现的,0x60~0x63和0x68~0x6B的8个寄存器就记录了8个PIRQ到8259A的16个中断
号之间的映射关系。可以这样想象,ICH有8条PCI中断线和系统中所有PCI SLOTs
相连,一旦某条中断线发生了中断,ICH就根据相应的PIRQ映射寄存器的值,向CPU
报告。对于CPU来说,只知道经典的IRQx被触发了。
映射关系建好后,BIOS再根据映射后的IRQ号写入每个FUNCTION的IRQ Line(0x3C),
以次告诉设备驱动或者OS,设备用了哪个IRQ号。

再说软件:
首先,无论是传统BIOS还是TIANO,都需要建立一张表来告诉OS,PCI SLOT上的4个中
断引脚和系统PCI总线上的8条中断线之间关系。
PLATFORM/IntelEpg/Bridgeport/Dxe/LegacyBiosPlatform/LegacyBiosPlatform.c
变量mPirqTableHead就是这张表,由于之前少了条E1000的映射信息,才导致了前不久
网卡没有中断无法工作的情况。因此需要在表内加入
0x04,0x00,0x62,0xDEF8,0x63,0xDEF8,0x60,0xDEF8,0x61,0xDEF8,0x00,0x00,
其中4个0x6x数字表示相应的PINx所对应的PIRQ,例如PINA的0x62表示其对应INTC中断线,
4个0xDEF8是掩码,表示16个8259A中断中那些不能被PIRQ拿来映射。
对于TIANO来说完成PIRQ到8259A的映射,实现在
CSM/LegacyBios/Dxe/LegacyPci.c的PciProgramAllInterruptLineRegisters()中
大概的思路是
先PLATFORM/IntelEpg/Bridgeport/Dxe/LegacyBiosPlatform/LegacyBiosPlatform.c
LegacyBiosPlatform->TranslatePirq()计算各个PIRQ的映射关系,也就是先读ICH对
应的PIRQ映射寄存器值,为0就为其分配8259A的一个空闲中断号,没空闲的就和别人复
用一个IRQ号。总之只要保证所有相等的PIRQ都对应一个IRQ号。
然后CHIPSET/IntelIch/LegacyInterrupt/Dxe/LegacyInterrupt.c
LegacyInterrupt->WritePirq()写入ICH对应的PIRQ映射寄存器中。
最后把各个IRQ号写入设备的IRQ Line(0x3C)中,把8259A的相应的中断线配成电平触发模式。
假如,mPirqTableHead表少了E1000映射关系,也可以在Linux做手脚,
/arch/i386/pci/irq.c的pirq_get_info()硬编码一条映射信息返回。
Linux关于PIRQ主要集中在/arch/i386/pci/irq.c的pcibios_lookup_irq()中
也就是PIRQ TABLE和LPC(pirq_router_dev)以及dev->irq这3个信息间绕来绕去。
值得注意的是dev->irq
先是来源于/drivers/pci/probe.c的pci_setup_device(),后者通过调用
pci_read_irq()也就是读取设备的IRQ Line(0x3C)。
如果为0,在pcibios_lookup_irq()结尾处的代码,会把它变为其他具有相同PIRQ号的
设备的IRQ号,当然如果不是0,而且又不和其他具有相同PIRQ号的设备的IRQ号一致,
那就出错。另外,如果BIOS没有进行PIRQ到8259A的映射,pcibios_lookup_irq()中间
的代码会进行类似的算法进行分配。
另外,如果由于种种原因,导致设备的IRQ Line(0x3C)的值和实际ICH对应的PIRQ映射
寄存器值不一致,例如,TIANO的PIRQ表中没加入E1000的PIRQ信息,但是,引导Linux
时候调用了TIANO的PciProgramAllInterruptLineRegisters(),此时可以在
arch/i386/pci/fixup.c中加入
static void __devinit pci_fixup_e1000(struct pci_dev *d)
{
  unsigned int  irq;
  if (PCI_FUNC(d->devfn) == 0)
    irq = 0x0;//0x7;
  else
    irq = 0x0;//0x9;
  pci_write_config_byte(d, PCI_INTERRUPT_LINE, irq);
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1096, pci_fixup_e1000);
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值