Offset = PciParseBar (PciIoDevice, Offset, BarIndex);\r
}\r
\r
+ //\r
+ // Parse the SR-IOV VF bars\r
+ //\r
+ if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {\r
+ for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;\r
+ Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;\r
+ BarIndex++) {\r
+ Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);\r
+ }\r
+ }\r
return PciIoDevice;\r
}\r
\r
return PciIoDevice->DevicePath;\r
}\r
\r
+/**\r
+ Check whether the PCI IOV VF bar is existed or not.\r
+\r
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
+ @param Offset The offset.\r
+ @param BarLengthValue The bar length value returned.\r
+ @param OriginalBarValue The original bar value returned.\r
+\r
+ @retval EFI_NOT_FOUND The bar doesn't exist.\r
+ @retval EFI_SUCCESS The bar exist.\r
+\r
+**/\r
+EFI_STATUS\r
+VfBarExisted (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN UINTN Offset,\r
+ OUT UINT32 *BarLengthValue,\r
+ OUT UINT32 *OriginalBarValue\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 OriginalValue;\r
+ UINT32 Value;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Ensure it is called properly\r
+ //\r
+ ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
+ if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PciIo = &PciIoDevice->PciIo;\r
+\r
+ //\r
+ // Preserve the original value\r
+ //\r
+\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
+\r
+ //\r
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);\r
+\r
+ //\r
+ // Write back the original value\r
+ //\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
+\r
+ //\r
+ // Restore TPL to its original level\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (BarLengthValue != NULL) {\r
+ *BarLengthValue = Value;\r
+ }\r
+\r
+ if (OriginalBarValue != NULL) {\r
+ *OriginalBarValue = OriginalValue;\r
+ }\r
+\r
+ if (Value == 0) {\r
+ return EFI_NOT_FOUND;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
+\r
/**\r
Check whether the bar is existed or not.\r
\r
return ;\r
}\r
\r
+/**\r
+ Parse PCI IOV VF bar information and fill them into PCI device instance.\r
+\r
+ @param PciIoDevice Pci device instance.\r
+ @param Offset Bar offset.\r
+ @param BarIndex Bar index.\r
+\r
+ @return Next bar offset.\r
+\r
+**/\r
+UINTN\r
+PciIovParseVfBar (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN UINTN Offset,\r
+ IN UINTN BarIndex\r
+ )\r
+{\r
+ UINT32 Value;\r
+ UINT64 BarValue64;\r
+ UINT32 OriginalValue;\r
+ UINT32 Mask;\r
+ UINT32 Data;\r
+ UINT8 Index;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Ensure it is called properly\r
+ //\r
+ ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
+ if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
+ return 0;\r
+ }\r
+\r
+ OriginalValue = 0;\r
+ Value = 0;\r
+ BarValue64 = 0;\r
+\r
+ Status = VfBarExisted (\r
+ PciIoDevice,\r
+ Offset,\r
+ &Value,\r
+ &OriginalValue\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
+ PciIoDevice->VfPciBar[BarIndex].Length = 0;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
+\r
+ //\r
+ // Scan all the BARs anyway\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset;\r
+ return Offset + 4;\r
+ }\r
+\r
+ PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset;\r
+ if (Value & 0x01) {\r
+ //\r
+ // Device I/Os. Impossible\r
+ //\r
+ ASSERT (FALSE);\r
+ return Offset + 4;\r
+\r
+ } else {\r
+\r
+ Mask = 0xfffffff0;\r
+\r
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
+\r
+ switch (Value & 0x07) {\r
+\r
+ //\r
+ //memory space; anywhere in 32 bit address space\r
+ //\r
+ case 0x00:\r
+ if (Value & 0x08) {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;\r
+ } else {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;\r
+ }\r
+\r
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
+\r
+ //\r
+ // Adjust Length\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
+ //\r
+ // Adjust Alignment\r
+ //\r
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // memory space; anywhere in 64 bit address space\r
+ //\r
+ case 0x04:\r
+ if (Value & 0x08) {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;\r
+ } else {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;\r
+ }\r
+\r
+ //\r
+ // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
+ // is regarded as an extension for the first bar. As a result\r
+ // the sizing will be conducted on combined 64 bit value\r
+ // Here just store the masked first 32bit value for future size\r
+ // calculation\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
+\r
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
+ }\r
+\r
+ //\r
+ // Increment the offset to point to next DWORD\r
+ //\r
+ Offset += 4;\r
+\r
+ Status = VfBarExisted (\r
+ PciIoDevice,\r
+ Offset,\r
+ &Value,\r
+ &OriginalValue\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Offset + 4;\r
+ }\r
+\r
+ //\r
+ // Fix the length to support some spefic 64 bit BAR\r
+ //\r
+ Data = Value;\r
+ Index = 0;\r
+ for (Data = Value; Data != 0; Data >>= 1) {\r
+ Index ++;\r
+ }\r
+ Value |= ((UINT32)(-1) << Index); \r
+\r
+ //\r
+ // Calculate the size of 64bit bar\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
+\r
+ PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
+\r
+ //\r
+ // Adjust Length\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
+ //\r
+ // Adjust Alignment\r
+ //\r
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // reserved\r
+ //\r
+ default:\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
+\r
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Check the length again so as to keep compatible with some special bars\r
+ //\r
+ if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
+ }\r
+ \r
+ //\r
+ // Increment number of bar\r
+ //\r
+ return Offset + 4;\r
+}\r
+\r
/**\r
Parse PCI bar information and fill them into PCI device instance.\r
\r
}\r
\r
PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
- PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
-\r
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
+ //\r
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
+ } else {\r
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+ }\r
break;\r
\r
//\r
);\r
\r
if (EFI_ERROR (Status)) {\r
+ //\r
+ // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again\r
+ //\r
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
+ //\r
+ // some device implement MMIO bar with 0 length, need to treat it as no-bar\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
+ }\r
return Offset + 4;\r
}\r
\r
\r
PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
- PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
+ //\r
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
+ } else {\r
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+ }\r
\r
break;\r
\r
default:\r
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
- PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
-\r
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
+ //\r
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
+ } else {\r
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+ }\r
break;\r
}\r
}\r
)\r
{\r
PCI_IO_DEVICE *PciIoDevice;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
\r
PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
if (PciIoDevice == NULL) {\r
InitializePciIoInstance (PciIoDevice);\r
InitializePciDriverOverrideInstance (PciIoDevice);\r
InitializePciLoadFile2 (PciIoDevice);\r
+ PciIo = &PciIoDevice->PciIo;\r
+\r
+ //\r
+ // Detect if PCI Express Device\r
+ //\r
+ PciIoDevice->PciExpressCapabilityOffset = 0;\r
+ Status = LocateCapabilityRegBlock (\r
+ PciIoDevice,\r
+ EFI_PCI_CAPABILITY_ID_PCIEXP,\r
+ &PciIoDevice->PciExpressCapabilityOffset,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ PciIoDevice->IsPciExp = TRUE;\r
+ }\r
+\r
+ //\r
+ // Initialize for PCI IOV\r
+ //\r
+\r
+ //\r
+ // Check ARI for function 0 only\r
+ //\r
+ Status = LocatePciExpressCapabilityRegBlock (\r
+ PciIoDevice,\r
+ EFI_PCIE_CAPABILITY_ID_ARI,\r
+ &PciIoDevice->AriCapabilityOffset,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "PCI-IOV B%x.D%x.F%x - ARI Cap offset - 0x%x\n",\r
+ (UINTN)Bus,\r
+ (UINTN)Device,\r
+ (UINTN)Func,\r
+ (UINTN)PciIoDevice->AriCapabilityOffset\r
+ ));\r
+ }\r
+\r
+ Status = LocatePciExpressCapabilityRegBlock (\r
+ PciIoDevice,\r
+ EFI_PCIE_CAPABILITY_ID_SRIOV,\r
+ &PciIoDevice->SrIovCapabilityOffset,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "PCI-IOV B%x.D%x.F%x - SRIOV Cap offset - 0x%x\n",\r
+ (UINTN)Bus,\r
+ (UINTN)Device,\r
+ (UINTN)Func,\r
+ (UINTN)PciIoDevice->SrIovCapabilityOffset\r
+ ));\r
+ }\r
+\r
+ Status = LocatePciExpressCapabilityRegBlock (\r
+ PciIoDevice,\r
+ EFI_PCIE_CAPABILITY_ID_MRIOV,\r
+ &PciIoDevice->MrIovCapabilityOffset,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "PCI-IOV B%x.D%x.F%x - MRIOV Cap offset - 0x%x\n",\r
+ (UINTN)Bus,\r
+ (UINTN)Device,\r
+ (UINTN)Func,\r
+ (UINTN)PciIoDevice->MrIovCapabilityOffset\r
+ ));\r
+ }\r
+\r
+ //\r
+ // Calculate SystemPageSize\r
+ //\r
+ if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {\r
+\r
+ PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
+ 1,\r
+ &PciIoDevice->SystemPageSize\r
+ );\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SupportedPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize));\r
+\r
+ PciIoDevice->SystemPageSize = (PcdGet32(PcdSrIovSystemPageSize) & PciIoDevice->SystemPageSize);\r
+ ASSERT (PciIoDevice->SystemPageSize != 0);\r
+\r
+ PciIo->Pci.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
+ 1,\r
+ &PciIoDevice->SystemPageSize\r
+ );\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SystemPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize));\r
+ //\r
+ // Adjust SystemPageSize for Alignment usage later\r
+ //\r
+ PciIoDevice->SystemPageSize <<= 12;\r
+ }\r
+\r
+ // Calculate BusReservation for PCI IOV\r
+ //\r
+ if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {\r
+ UINT16 VFStride;\r
+ UINT16 FirstVFOffset;\r
+ UINT32 PFRID;\r
+ UINT32 LastVF;\r
+\r
+ //\r
+ // Read First FirstVFOffset, InitialVFs, and VFStride\r
+ //\r
+ PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
+ 1,\r
+ &FirstVFOffset\r
+ );\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - FirstVFOffset - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)FirstVFOffset));\r
+\r
+ PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
+ 1,\r
+ &PciIoDevice->InitialVFs\r
+ );\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - InitialVFs - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)PciIoDevice->InitialVFs));\r
+\r
+ PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
+ 1,\r
+ &VFStride\r
+ );\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - VFStride - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)VFStride));\r
+\r
+ //\r
+ // Calculate LastVF\r
+ //\r
+ PFRID = EFI_PCI_RID(Bus, Device, Func);\r
+ LastVF = PFRID + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
+\r
+ //\r
+ // Calculate ReservedBusNum for this PF\r
+ //\r
+ PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - reserved bus number - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)PciIoDevice->ReservedBusNum));\r
+ }\r
+\r
\r
//\r
// Initialize the reserved resource list\r