GatherPpbInfo的主要内容还是填充PCI_IO_DEVICE *PciIoDevice
用以保存当前桥设备的信息。因此函数第一步还是创建设备的结构体
PciIoDevice = CreatePciIoDevice (
Bridge,
Pci,
Bus,
Device,
Func
);
if (PciIoDevice == NULL) {
return NULL;
}
接下来是对设备寄存器进行的一些初始化的操作,这些操作就是向寄存器中写入相应的初始值
if (gFullEnumeration) {
PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
//
// Initialize the bridge control register
//
PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
}
接下来是对PCI Bridge的Bar寄存器进行解析,由于PCI Bridge 只有两个Bar寄存器,所以只需判断第一次解析后的起始地址是否仍然为Bar寄存器的地址,就可以知道是否需要进行下一次的解析。解析Bar寄存器的函数 PciParseBar
详细分析过了 详见UEFI—— 读取Bar寄存器的实现(函数GatherDeviceInfo 解析)
//
// PPB can have two BARs
//
if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {
//
// Not 64-bit bar
//
PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);
}
接下来需要判断的是当前的桥是否支持32bit 的IO配置
//
// Test whether it support 32 decode or not
//
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
if (Value != 0) {
if ((Value & 0x01) != 0) {
PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
} else {
PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
}
}
根据PCIe Spec中的定义 如果I/O Base中的bit 3:0 为0 表示当前只支持16bit IO配置,若为1 表示支持32bit IO配置
接下来同样的分析 Prefetchable Memory Base 寄存器的情况
//
// Test if it supports 64 memory or not
//
// The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit
// registers:
// 0 - the bridge supports only 32 bit addresses.
// 1 - the bridge supports 64-bit addresses.
//
PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff);
PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16);
if (!EFI_ERROR (Status) &&
((PrefetchableMemoryBase & 0x000f) == 0x0001) &&
((PrefetchableMemoryLimit & 0x000f) == 0x0001))
{
Status = BarExisted (
PciIoDevice,
0x28,
NULL,
NULL
);
if (!EFI_ERROR (Status)) {
PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
} else {
PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
}
}
如果PrefetchableMemoryBase & PrefetchableMemoryLimit 两个寄存器的低两位都是01 则表示可以支持 64bit PrefetchableMemory,若是00 则表示只支持32bit的PrefetchableMemory。然后对Prefetchable Base Upper 32 Bits进行判断,如果当前这个寄存器存在有效值,则表示当前桥是 64bit PrefetchableMemory的 否则就是32bit PrefetchableMemory的
接下来对必须要支持的属性进行添加
//
// Memory 32 code is required for ppb
//
PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
以上的操作都是填充 PciIoDevice->Decodes 这一属性
接下来的操作和热插拔相关,目前不在讨论范围内
GetResourcePaddingPpb (PciIoDevice);