如何修改PCIE 设备控制寄存器DevCtl2参数?
参考书籍: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));}}}}// }// }}
}