参考书籍:PCI_Express_Base_Spec
如图所示:输入Lspci -s 00:08:00 -vvv|grep - i deve
输出DevCap、DevCtl、DevCap2、DevCtl2参数,本节重点分析UEFI BIOS怎么设置DevCtl2参数
1、能力指针在PCIE 配置空间偏移34h处,
Pci->Pci.Read (Pci, EfiPciIoWidthUint8, 0x34, 1, &CapabilityPtrEntry); 读到能力指针里的内容作为入口地址。
2、取CapabilityPtrEntry的两个字节进行判断, 如果PCI ExpressCapID 为0x10,为找到能力项的入口地址,如果PCI ExpressCapID 不为0x10,取Next CapabilitiesPointer 的指针地址,查看指针地址的值是否为 0x10,如果是0x10,找到能力项入口地址,如果为00,结束循环,不为0,又不为0x10,继续寻找下一个能力项地址。
3、当找到能力项入口地址,可以看出偏移0x28的两个字节为DeviceCtl2参数入口
4、找到DeviceCtl2,设备寄存器地址,可以对16个bit位进行分析
0-3 :Completion Timeout Value
4:Completion Timeout Disable
5: ARI Fowarding Enable
根据SPI Spec 对各个参数内容进行设置,设置完成,再写到PCI 配置空间里面
UINT8
LocatePciCapability (
EFI_PCI_IO_PROTOCOL *Pci,
IN UINT8 CapabilityId
)
{
UINT8 CapabilityPtrEntry;
UINT8 CapabilityNextPtr;
UINT8 CapabilityIdValue;
Pci->Pci.Read (Pci, EfiPciIoWidthUint8, 0x34, 1, &CapabilityPtrEntry);
CapabilityNextPtr = CapabilityPtrEntry;
while ((CapabilityNextPtr >= 0x40) && ((CapabilityNextPtr + 1) != 0x00)) {
Pci->Pci.Read (Pci, EfiPciIoWidthUint8, CapabilityNextPtr, 1, &CapabilityIdValue);
if (CapabilityIdValue != CapabilityId) {
// CapabilityNextPtr = CapabilityNextPtr +1;
Pci->Pci.Read (Pci, EfiPciIoWidthUint8, CapabilityNextPtr + 1, 1, &CapabilityNextPtr);
} else {
return CapabilityNextPtr;
}
}
Pci->Pci.Read (Pci, EfiPciIoWidthUint8, CapabilityNextPtr + 1, 1, &CapabilityIdValue);
if (CapabilityIdValue == 0x00) {
Pci->Pci.Read (Pci, EfiPciIoWidthUint8, CapabilityNextPtr, 1, &CapabilityIdValue);
if (CapabilityIdValue == CapabilityId) {
return CapabilityNextPtr;
}
}
return 0;
}
VOID
EnableTimeOut()
{
EFI_STATUS Status;
UINTN HandleCount, Index = 0;
EFI_HANDLE *HandleBuffer;
EFI_PCI_IO_PROTOCOL *PciIo = NULL;
UINT8 ClassCode[3];
UINT8 CapabilityAddr,LinkState;
UINT16 ControlRegister;
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathToText;
CHAR16 *DevicePathString = NULL;
EFI_DEVICE_PATH_PROTOCOL *PciIoDevicePath;
// CHAR16 OnboardLanDevicePath[] = L"PciRoot(0x0)/Pci(0x0,0x0)/Pci(0x0,0x0)/Pci(0x3,0x0)";
// Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **) &DevicePathToText);
// if (EFI_ERROR (Status)) {
// return Status;
// }
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiPciIoProtocolGuid, NULL,&HandleCount,&HandleBuffer);
if (!EFI_ERROR (Status)) {
for (Index = 0; Index < HandleCount; Index ++) {
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
if (!EFI_ERROR (Status)) {
// Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&PciIoDevicePath);
// if (!EFI_ERROR (Status)) {
// DevicePathString = DevicePathToText->ConvertDevicePathToText(PciIoDevicePath, TRUE, TRUE);
// if(!StrnCmp(OnboardLanDevicePath,DevicePathString,StrLen(OnboardLanDevicePath)) &&
// (StrLen(OnboardLanDevicePath) == StrLen(DevicePathString))){
CapabilityAddr = LocatePciCapability(PciIo, 0x10);
if(CapabilityAddr != 0){
CapabilityAddr += 0x28;
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint16,
CapabilityAddr,
1,
&ControlRegister
);
DEBUG((EFI_D_ERROR, "James: ControlRegister is %0x\n", ControlRegister));
if (!EFI_ERROR (Status)) {
// Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
ControlRegister = ControlRegister | 0x10;
//DEBUG((EFI_D_ERROR, "James: LinkState is %0x\n", LinkState));
PciIo->Pci.Write (
PciIo,
EfiPciIoWidthUint16,
CapabilityAddr,
1,
&ControlRegister
);
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint8,
CapabilityAddr,
1,
&LinkState
);
DEBUG((EFI_D_ERROR, "James: ControlRegister is %0x\n", ControlRegister));
}
}
}
}
// }
// }
}
}