修改PCIE 设备控制寄存器DevCtl2参数

发布时间:2023年12月25日

如何修改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));
              }
            }
          }
        }
      // }
    // }
  }
}
文章来源:https://blog.csdn.net/weixin_41172506/article/details/135204112
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。