一说到资源,大家马上想到“利用”两个字。是的,没有利用价值的资源不是真正的资源。大到整个社会,小到个人,都在利用资源实现自己的想法。PCI设备也不例外,想让PCI设备工作,PCI设备驱动一定要有资源可以利用,但是这个资源从何而来?下面就来介绍一下EFI下最为重要的一个驱动:PCIBUS驱动。
在此注明一下,IRQ也是PCI资源重要的一种。但是其并不是PCIBUS驱动所设,之前我也有写过一篇INTERRUPT的文章讲述这一点,所以此篇文章将此忽略。
PCIBUS驱动要为PCI设备分配的资源有哪些呢?换言之,一个PCI设备插到系统中,它需要什么东西才可以正常工作?IO,Memory,IRQ,OpROM。IRQ是CPU查找设备请求访问的触发机制,IO和MEMORY是CPU访问设备所用到的映射机制,OpROM是PCI设备厂商方便用户使用其设备所提供的一个便利机制。想要搞懂如何分配这些资源,首先PCIBUS要找到相应的设备,我们来看一下PCIBUS找设备的过程。
1 PCI扫描
在PLTRST#过后,所有PCI设备均处于初始状态。包括PCI BUS,也只有Host Bridge掌控的BUS0处于正常状态,其余的PCI桥都处于“杂乱无章”的状态。如果想让PCI BUS能够正常工作,能够让CPU发出的PCI访问信息正确路由至PCI设备处,我们必须扫描PCI BUS,为各个PCI 桥分配上正确的Primary Bus,Secondary Bus和SubOrdinate Bus。
EFI BIOS采用深度优先的算法来扫描PCI Bus,具体可查看UDK2014 PCIBUS驱动的PciScanBus函数,这是一个递规的函数。从BUS0开始,见到有扫描的PCI设备为PCI桥的时候,便为该PCI桥分配Secondary Bus,然后立即转入该Secondary Bus的扫描。除了设置PCI Bus Number,PCI BUS驱动还会根据PCI桥下挂的设备资源来设置PCI桥的2个BASE ADRESSRegister以及MEMORY BASE,Limit和IO Base,Limit。
在扫描的过程中,PCI BUS驱动会检查PCI Agent(我也不知道Agent怎么翻译)。如果其支持内存,IO和OpROM,则PCI BUS会计算其大小,然后为其分配基址。下面来看一下,PCI BUS如何获取PCI设备是否支持MEMORY,IO,OpROM的,以及如何获取其大小的。
2PCIBar
一个PCI Agent,有6个PCIBar,在其配置空间的0ffset 0x10至0x24处,每个Bar占4个字节。PCI Agent需不需要Memory和IO,需要多少,是由PCI Agent本身决定的,所以我们要通过访问这些BAR来确定这些资源。
2.1 是否需要MEMORY和IO
在PCIBUS Gather PCI Agent信息的时候,会调用BarExisted()函数来确定某个BAR是否支持MEMORY和IO。我们来看一个函数体:
EFI_STATUS
BarExisted(
IN PCI_IO_DEVICE *PciIoDevice, //指向该PCI Agent结构体
IN UINTN Offset, //这个是BAR的offset,0x10到0x24
OUT UINT32 *BarLengthValue, //用来接收BAR需要的资源长度,这个最重要
OUT UINT32 *OriginalBarValue //PCI AGENT原始值
)
{
EFI_PCI_IO_PROTOCOL *PciIo;
UINT32 OriginalValue;
UINT32 Value;
EFI_TPL OldTpl;
PciIo = &PciIoDevice->PciIo;
// 保存原始的BAR值
PciIo->Pci.Read (PciIo,EfiPciIoWi