From 72c835a180dfa1b8c9920254ff671ece9e1d7c15 Mon Sep 17 00:00:00 2001 From: "hengyan,tao" Date: Wed, 16 Sep 2009 09:32:06 +0000 Subject: [PATCH] add SR-IOV support in EDK II. --- IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBus.h | 19 +- .../Bus/Pci/PciBusDxe/PciBusDxe.inf | 5 + .../Bus/Pci/PciBusDxe/PciCommand.c | 67 +++ .../Bus/Pci/PciBusDxe/PciCommand.h | 21 + .../Bus/Pci/PciBusDxe/PciDeviceSupport.c | 32 ++ .../Bus/Pci/PciBusDxe/PciEnumeratorSupport.c | 481 ++++++++++++++++++++- .../Bus/Pci/PciBusDxe/PciEnumeratorSupport.h | 37 ++ IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciLib.c | 32 +- .../Bus/Pci/PciBusDxe/PciResourceSupport.c | 252 +++++++++++ .../Bus/Pci/PciBusDxe/PciResourceSupport.h | 36 ++ .../IntelFrameworkModulePkg.dec | 16 + 11 files changed, 988 insertions(+), 10 deletions(-) diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBus.h index df224d12c..0c1c864bc 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBus.h +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBus.h @@ -50,6 +50,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. typedef struct _PCI_IO_DEVICE PCI_IO_DEVICE; typedef struct _PCI_BAR PCI_BAR; +#define EFI_PCI_RID(Bus, Device, Function) (((UINT32)Bus << 8) + ((UINT32)Device << 3) + (UINT32)Function) +#define EFI_PCI_BUS_OF_RID(RID) ((UINT32)RID >> 8) + +#define EFI_PCI_IOV_POLICY_ARI 0x0001 +#define EFI_PCI_IOV_POLICY_SRIOV 0x0002 +#define EFI_PCI_IOV_POLICY_MRIOV 0x0004 + typedef enum { PciBarTypeUnknown = 0, PciBarTypeIo16, @@ -248,7 +255,17 @@ struct _PCI_IO_DEVICE { EFI_HPC_PADDING_ATTRIBUTES PaddingAttributes; BOOLEAN IsPciExp; - + // + // For SR-IOV + // + UINT8 PciExpressCapabilityOffset; + UINT32 AriCapabilityOffset; + UINT32 SrIovCapabilityOffset; + UINT32 MrIovCapabilityOffset; + PCI_BAR VfPciBar[PCI_MAX_BAR]; + UINT32 SystemPageSize; + UINT16 InitialVFs; + UINT16 ReservedBusNum; }; #define PCI_IO_DEVICE_FROM_PCI_IO_THIS(a) \ diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf index a3a13d55a..a0f1e44e2 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf @@ -101,7 +101,12 @@ [FeaturePcd.common] gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSrIovSupport + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdAriSupport + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdMrIovSupport +[FixedPcd.common] + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize # [Event] # ## # # Notify event set by CreateEventForHpc () for PCI Hot Plug controller. diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.c b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.c index 39f5271e9..601af309b 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.c +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.c @@ -179,3 +179,70 @@ LocateCapabilityRegBlock ( return EFI_NOT_FOUND; } +/** + Locate PciExpress capability register block per capability ID. + + @param PciIoDevice A pointer to the PCI_IO_DEVICE. + @param CapId The capability ID. + @param Offset A pointer to the offset returned. + @param NextRegBlock A pointer to the next block returned. + + @retval EFI_SUCCESS Successfuly located capability register block. + @retval EFI_UNSUPPORTED Pci device does not support capability. + @retval EFI_NOT_FOUND Pci device support but can not find register block. + +**/ +EFI_STATUS +LocatePciExpressCapabilityRegBlock ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 CapId, + IN OUT UINT32 *Offset, + OUT UINT32 *NextRegBlock OPTIONAL + ) +{ + UINT32 CapabilityPtr; + UINT32 CapabilityEntry; + UINT16 CapabilityID; + + // + // To check the capability of this device supports + // + if (!PciIoDevice->IsPciExp) { + return EFI_UNSUPPORTED; + } + + if (*Offset != 0) { + CapabilityPtr = *Offset; + } else { + CapabilityPtr = EFI_PCIE_CAPABILITY_BASE_OFFSET; + } + + while (CapabilityPtr != 0) { + // + // Mask it to DWORD alignment per PCI spec + // + CapabilityPtr &= 0xFFC; + PciIoDevice->PciIo.Pci.Read ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint32, + CapabilityPtr, + 1, + &CapabilityEntry + ); + + CapabilityID = (UINT16) CapabilityEntry; + + if (CapabilityID == CapId) { + *Offset = CapabilityPtr; + if (NextRegBlock != NULL) { + *NextRegBlock = (CapabilityEntry >> 20) & 0xFFF; + } + + return EFI_SUCCESS; + } + + CapabilityPtr = (CapabilityEntry >> 20) & 0xFFF; + } + + return EFI_NOT_FOUND; +} diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.h b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.h index 7019b5ea1..942bea941 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.h +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.h @@ -119,6 +119,27 @@ LocateCapabilityRegBlock ( ); /** + Locate PciExpress capability register block per capability ID. + + @param PciIoDevice A pointer to the PCI_IO_DEVICE. + @param CapId The capability ID. + @param Offset A pointer to the offset returned. + @param NextRegBlock A pointer to the next block returned. + + @retval EFI_SUCCESS Successfuly located capability register block. + @retval EFI_UNSUPPORTED Pci device does not support capability. + @retval EFI_NOT_FOUND Pci device support but can not find register block. + +**/ +EFI_STATUS +LocatePciExpressCapabilityRegBlock ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 CapId, + IN OUT UINT32 *Offset, + OUT UINT32 *NextRegBlock OPTIONAL + ); + +/** Macro that reads command register. @param a[in] Pointer to instance of PCI_IO_DEVICE. diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c index baad1ccd7..0eb9f9a9d 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c @@ -215,6 +215,10 @@ RegisterPciDevice ( EFI_PCI_IO_PROTOCOL *PciIo; UINT8 Data8; BOOLEAN HasEfiImage; + PCI_IO_DEVICE *ParrentPciIoDevice; + EFI_PCI_IO_PROTOCOL *ParrentPciIo; + UINT16 Data16; + UINT32 Data32; // // Install the pciio protocol, device path protocol @@ -251,7 +255,35 @@ RegisterPciDevice ( PciIo = &(PciIoDevice->PciIo); Data8 = PCI_INT_LINE_UNKNOWN; PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8); + + // + // PCI-IOV programming + // + if (((FeaturePcdGet(PcdAriSupport) & EFI_PCI_IOV_POLICY_ARI) != 0) && (PciIoDevice->AriCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport) & EFI_PCI_IOV_POLICY_SRIOV) != 0) && + (PciIoDevice->SrIovCapabilityOffset != 0)) { + // + // Check its parrent ARI forwarding capability + // + ParrentPciIoDevice = PciIoDevice->Parent; + ParrentPciIo = &(ParrentPciIoDevice->PciIo); + ParrentPciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ParrentPciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET, 1, &Data32); + if (Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) { + // + // ARI forward support in bridge, so enable it. + // + ParrentPciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ParrentPciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, 1, &Data32); + Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING; + ParrentPciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ParrentPciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, 1, &Data32); + // + // Set ARI Capable Hierarchy for device + // + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, 1, &Data16); + Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY; + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, 1, &Data16); + } + } + // // Process OpRom // diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c index 2d5408abe..66183960f 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c @@ -367,6 +367,16 @@ GatherDeviceInfo ( Offset = PciParseBar (PciIoDevice, Offset, BarIndex); } + // + // Parse the SR-IOV VF bars + // + if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) { + for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0; + Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5; + BarIndex++) { + Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex); + } + } return PciIoDevice; } @@ -598,6 +608,80 @@ CreatePciDevicePath ( } /** + Check whether the PCI IOV VF bar is existed or not. + + @param PciIoDevice A pointer to the PCI_IO_DEVICE. + @param Offset The offset. + @param BarLengthValue The bar length value returned. + @param OriginalBarValue The original bar value returned. + + @retval EFI_NOT_FOUND The bar doesn't exist. + @retval EFI_SUCCESS The bar exist. + +**/ +EFI_STATUS +VfBarExisted ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + OUT UINT32 *BarLengthValue, + OUT UINT32 *OriginalBarValue + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 OriginalValue; + UINT32 Value; + EFI_TPL OldTpl; + + // + // Ensure it is called properly + // + ASSERT (PciIoDevice->SrIovCapabilityOffset != 0); + if (PciIoDevice->SrIovCapabilityOffset == 0) { + return EFI_NOT_FOUND; + } + + PciIo = &PciIoDevice->PciIo; + + // + // Preserve the original value + // + + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue); + + // + // Raise TPL to high level to disable timer interrupt while the BAR is probed + // + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne); + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value); + + // + // Write back the original value + // + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue); + + // + // Restore TPL to its original level + // + gBS->RestoreTPL (OldTpl); + + if (BarLengthValue != NULL) { + *BarLengthValue = Value; + } + + if (OriginalBarValue != NULL) { + *OriginalBarValue = OriginalValue; + } + + if (Value == 0) { + return EFI_NOT_FOUND; + } else { + return EFI_SUCCESS; + } +} + +/** Check whether the bar is existed or not. @param PciIoDevice A pointer to the PCI_IO_DEVICE. @@ -1250,6 +1334,207 @@ SetNewAlign ( } /** + Parse PCI IOV VF bar information and fill them into PCI device instance. + + @param PciIoDevice Pci device instance. + @param Offset Bar offset. + @param BarIndex Bar index. + + @return Next bar offset. + +**/ +UINTN +PciIovParseVfBar ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + IN UINTN BarIndex + ) +{ + UINT32 Value; + UINT64 BarValue64; + UINT32 OriginalValue; + UINT32 Mask; + UINT32 Data; + UINT8 Index; + EFI_STATUS Status; + + // + // Ensure it is called properly + // + ASSERT (PciIoDevice->SrIovCapabilityOffset != 0); + if (PciIoDevice->SrIovCapabilityOffset == 0) { + return 0; + } + + OriginalValue = 0; + Value = 0; + BarValue64 = 0; + + Status = VfBarExisted ( + PciIoDevice, + Offset, + &Value, + &OriginalValue + ); + + if (EFI_ERROR (Status)) { + PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0; + PciIoDevice->VfPciBar[BarIndex].Length = 0; + PciIoDevice->VfPciBar[BarIndex].Alignment = 0; + + // + // Scan all the BARs anyway + // + PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset; + return Offset + 4; + } + + PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset; + if (Value & 0x01) { + // + // Device I/Os. Impossible + // + ASSERT (FALSE); + return Offset + 4; + + } else { + + Mask = 0xfffffff0; + + PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask; + + switch (Value & 0x07) { + + // + //memory space; anywhere in 32 bit address space + // + case 0x00: + if (Value & 0x08) { + PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32; + } else { + PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32; + } + + PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1; + PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; + + // + // Adjust Length + // + PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs); + // + // Adjust Alignment + // + if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { + PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; + } + + break; + + // + // memory space; anywhere in 64 bit address space + // + case 0x04: + if (Value & 0x08) { + PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64; + } else { + PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64; + } + + // + // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar + // is regarded as an extension for the first bar. As a result + // the sizing will be conducted on combined 64 bit value + // Here just store the masked first 32bit value for future size + // calculation + // + PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask; + PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; + + if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { + PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; + } + + // + // Increment the offset to point to next DWORD + // + Offset += 4; + + Status = VfBarExisted ( + PciIoDevice, + Offset, + &Value, + &OriginalValue + ); + + if (EFI_ERROR (Status)) { + return Offset + 4; + } + + // + // Fix the length to support some spefic 64 bit BAR + // + Data = Value; + Index = 0; + for (Data = Value; Data != 0; Data >>= 1) { + Index ++; + } + Value |= ((UINT32)(-1) << Index); + + // + // Calculate the size of 64bit bar + // + PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32); + + PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32); + PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1; + PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; + + // + // Adjust Length + // + PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs); + // + // Adjust Alignment + // + if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { + PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; + } + + break; + + // + // reserved + // + default: + PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown; + PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1; + PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; + + if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { + PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; + } + + break; + } + } + + // + // Check the length again so as to keep compatible with some special bars + // + if (PciIoDevice->VfPciBar[BarIndex].Length == 0) { + PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown; + PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0; + PciIoDevice->VfPciBar[BarIndex].Alignment = 0; + } + + // + // Increment number of bar + // + return Offset + 4; +} + +/** Parse PCI bar information and fill them into PCI device instance. @param PciIoDevice Pci device instance. @@ -1349,8 +1634,14 @@ PciParseBar ( } PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; - PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; - + if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) { + // + // Force minimum 4KByte alignment for Virtualization technology for Directed I/O + // + PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1); + } else { + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + } break; // @@ -1386,6 +1677,15 @@ PciParseBar ( ); if (EFI_ERROR (Status)) { + // + // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again + // + if (PciIoDevice->PciBar[BarIndex].Length == 0) { + // + // some device implement MMIO bar with 0 length, need to treat it as no-bar + // + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; + } return Offset + 4; } @@ -1406,7 +1706,14 @@ PciParseBar ( PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32); PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1; - PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) { + // + // Force minimum 4KByte alignment for Virtualization technology for Directed I/O + // + PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1); + } else { + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + } break; @@ -1416,8 +1723,14 @@ PciParseBar ( default: PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; - PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; - + if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) { + // + // Force minimum 4KByte alignment for Virtualization technology for Directed I/O + // + PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1); + } else { + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + } break; } } @@ -1570,6 +1883,8 @@ CreatePciIoDevice ( ) { PCI_IO_DEVICE *PciIoDevice; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_STATUS Status; PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE)); if (PciIoDevice == NULL) { @@ -1607,6 +1922,162 @@ CreatePciIoDevice ( InitializePciIoInstance (PciIoDevice); InitializePciDriverOverrideInstance (PciIoDevice); InitializePciLoadFile2 (PciIoDevice); + PciIo = &PciIoDevice->PciIo; + + // + // Detect if PCI Express Device + // + PciIoDevice->PciExpressCapabilityOffset = 0; + Status = LocateCapabilityRegBlock ( + PciIoDevice, + EFI_PCI_CAPABILITY_ID_PCIEXP, + &PciIoDevice->PciExpressCapabilityOffset, + NULL + ); + if (!EFI_ERROR (Status)) { + PciIoDevice->IsPciExp = TRUE; + } + + // + // Initialize for PCI IOV + // + + // + // Check ARI for function 0 only + // + Status = LocatePciExpressCapabilityRegBlock ( + PciIoDevice, + EFI_PCIE_CAPABILITY_ID_ARI, + &PciIoDevice->AriCapabilityOffset, + NULL + ); + if (!EFI_ERROR (Status)) { + DEBUG (( + EFI_D_INFO, + "PCI-IOV B%x.D%x.F%x - ARI Cap offset - 0x%x\n", + (UINTN)Bus, + (UINTN)Device, + (UINTN)Func, + (UINTN)PciIoDevice->AriCapabilityOffset + )); + } + + Status = LocatePciExpressCapabilityRegBlock ( + PciIoDevice, + EFI_PCIE_CAPABILITY_ID_SRIOV, + &PciIoDevice->SrIovCapabilityOffset, + NULL + ); + if (!EFI_ERROR (Status)) { + DEBUG (( + EFI_D_INFO, + "PCI-IOV B%x.D%x.F%x - SRIOV Cap offset - 0x%x\n", + (UINTN)Bus, + (UINTN)Device, + (UINTN)Func, + (UINTN)PciIoDevice->SrIovCapabilityOffset + )); + } + + Status = LocatePciExpressCapabilityRegBlock ( + PciIoDevice, + EFI_PCIE_CAPABILITY_ID_MRIOV, + &PciIoDevice->MrIovCapabilityOffset, + NULL + ); + if (!EFI_ERROR (Status)) { + DEBUG (( + EFI_D_INFO, + "PCI-IOV B%x.D%x.F%x - MRIOV Cap offset - 0x%x\n", + (UINTN)Bus, + (UINTN)Device, + (UINTN)Func, + (UINTN)PciIoDevice->MrIovCapabilityOffset + )); + } + + // + // Calculate SystemPageSize + // + if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) { + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE, + 1, + &PciIoDevice->SystemPageSize + ); + DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SupportedPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize)); + + PciIoDevice->SystemPageSize = (PcdGet32(PcdSrIovSystemPageSize) & PciIoDevice->SystemPageSize); + ASSERT (PciIoDevice->SystemPageSize != 0); + + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint32, + PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE, + 1, + &PciIoDevice->SystemPageSize + ); + DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SystemPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize)); + // + // Adjust SystemPageSize for Alignment usage later + // + PciIoDevice->SystemPageSize <<= 12; + } + + // Calculate BusReservation for PCI IOV + // + if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) { + UINT16 VFStride; + UINT16 FirstVFOffset; + UINT32 PFRID; + UINT32 LastVF; + + // + // Read First FirstVFOffset, InitialVFs, and VFStride + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF, + 1, + &FirstVFOffset + ); + DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - FirstVFOffset - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)FirstVFOffset)); + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS, + 1, + &PciIoDevice->InitialVFs + ); + 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)); + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE, + 1, + &VFStride + ); + DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - VFStride - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)VFStride)); + + // + // Calculate LastVF + // + PFRID = EFI_PCI_RID(Bus, Device, Func); + LastVF = PFRID + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride; + + // + // Calculate ReservedBusNum for this PF + // + PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1); + 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)); + } + // // Initialize the reserved resource list diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h index 6f2f1e6ea..31238b45c 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h @@ -159,6 +159,26 @@ CreatePciDevicePath ( ); /** + Check whether the PCI IOV VF bar is existed or not. + + @param PciIoDevice A pointer to the PCI_IO_DEVICE. + @param Offset The offset. + @param BarLengthValue The bar length value returned. + @param OriginalBarValue The original bar value returned. + + @retval EFI_NOT_FOUND The bar doesn't exist. + @retval EFI_SUCCESS The bar exist. + +**/ +EFI_STATUS +VfBarExisted ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + OUT UINT32 *BarLengthValue, + OUT UINT32 *OriginalBarValue + ); + +/** Check whether the bar is existed or not. @param PciIoDevice A pointer to the PCI_IO_DEVICE. @@ -289,6 +309,23 @@ PciParseBar ( ); /** + Parse PCI IOV VF bar information and fill them into PCI device instance. + + @param PciIoDevice Pci device instance. + @param Offset Bar offset. + @param BarIndex Bar index. + + @return Next bar offset. + +**/ +UINTN +PciIovParseVfBar ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + IN UINTN BarIndex + ); + +/** This routine is used to initialize the bar of a PCI device. @param PciIoDevice Pci device instance. diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciLib.c b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciLib.c index 16c0cce99..70b28df0b 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciLib.c +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciLib.c @@ -706,6 +706,7 @@ PciScanBus ( UINT16 BusRange; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; BOOLEAN BusPadding; + UINT32 TempReservedBusNum; PciRootBridgeIo = Bridge->PciRootBridgeIo; SecondBus = 0; @@ -718,6 +719,7 @@ PciScanBus ( PciAddress = 0; for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { + TempReservedBusNum = 0; for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { // @@ -742,7 +744,7 @@ PciScanBus ( continue; } - DEBUG((EFI_D_ERROR, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func )); + DEBUG((EFI_D_INFO, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func )); if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { // @@ -930,7 +932,7 @@ PciScanBus ( EfiPciBeforeChildBusEnumeration ); - DEBUG((EFI_D_ERROR, "Scan PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber)); + DEBUG((EFI_D_INFO, "Scan PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber)); Status = PciScanBus ( PciDevice, (UINT8) (SecondBus), @@ -967,6 +969,28 @@ PciScanBus ( 1, SubBusNumber ); + } else { + // + // It is device. Check PCI IOV for Bus reservation + // + + // + // Go through each function, just reserve the MAX ReservedBusNum for one device + // + if ((PciDevice->AriCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) { + + if (TempReservedBusNum < PciDevice->ReservedBusNum) { + + (*SubBusNumber) = (UINT8)((*SubBusNumber) + PciDevice->ReservedBusNum - TempReservedBusNum); + TempReservedBusNum = PciDevice->ReservedBusNum; + + if (Func == 0) { + DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x\n", *SubBusNumber)); + } else { + DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x (Update)\n", *SubBusNumber)); + } + } + } } if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { @@ -1139,7 +1163,7 @@ PciHostBridgeEnumerator ( // NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation); - DEBUG((EFI_D_ERROR, "PCI Bus First Scanning\n")); + DEBUG((EFI_D_INFO, "PCI Bus First Scanning\n")); RootBridgeHandle = NULL; while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { @@ -1226,7 +1250,7 @@ PciHostBridgeEnumerator ( // NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation); - DEBUG((EFI_D_ERROR, "PCI Bus Second Scanning\n")); + DEBUG((EFI_D_INFO, "PCI Bus Second Scanning\n")); RootBridgeHandle = NULL; while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c index 40d02354e..17c864029 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c @@ -544,6 +544,94 @@ GetResourceFromDevice ( } // + // Add VF resource + // + for (Index = 0; Index < PCI_MAX_BAR; Index++) { + + switch ((PciDev->VfPciBar)[Index].BarType) { + + case PciBarTypeMem32: + + Node = CreateVfResourceNode ( + PciDev, + (PciDev->VfPciBar)[Index].Length, + (PciDev->VfPciBar)[Index].Alignment, + Index, + PciBarTypeMem32, + PciResUsageTypical + ); + + InsertResourceNode ( + Mem32Node, + Node + ); + + break; + + case PciBarTypeMem64: + + Node = CreateVfResourceNode ( + PciDev, + (PciDev->VfPciBar)[Index].Length, + (PciDev->VfPciBar)[Index].Alignment, + Index, + PciBarTypeMem64, + PciResUsageTypical + ); + + InsertResourceNode ( + Mem64Node, + Node + ); + + break; + + case PciBarTypePMem64: + + Node = CreateVfResourceNode ( + PciDev, + (PciDev->VfPciBar)[Index].Length, + (PciDev->VfPciBar)[Index].Alignment, + Index, + PciBarTypePMem64, + PciResUsageTypical + ); + + InsertResourceNode ( + PMem64Node, + Node + ); + + break; + + case PciBarTypePMem32: + + Node = CreateVfResourceNode ( + PciDev, + (PciDev->VfPciBar)[Index].Length, + (PciDev->VfPciBar)[Index].Alignment, + Index, + PciBarTypePMem32, + PciResUsageTypical + ); + + InsertResourceNode ( + PMem32Node, + Node + ); + break; + + case PciBarTypeIo16: + case PciBarTypeIo32: + break; + + case PciBarTypeUnknown: + break; + + default: + break; + } + } // If there is no resource requested from this device, // then we indicate this device has been allocated naturally. // @@ -600,6 +688,53 @@ CreateResourceNode ( } /** + This function is used to create a IOV VF resource node. + + @param PciDev Pci device instance. + @param Length Length of Io/Memory resource. + @param Alignment Alignment of resource. + @param Bar Bar index. + @param ResType Type of resource: IO/Memory. + @param ResUsage Resource usage. + + @return PCI resource node created for given VF PCI device. + NULL means PCI resource node is not created. + +**/ +PCI_RESOURCE_NODE * +CreateVfResourceNode ( + IN PCI_IO_DEVICE *PciDev, + IN UINT64 Length, + IN UINT64 Alignment, + IN UINT8 Bar, + IN PCI_BAR_TYPE ResType, + IN PCI_RESOURCE_USAGE ResUsage + ) +{ + PCI_RESOURCE_NODE *Node; + + DEBUG (( + EFI_D_INFO, + "PCI-IOV B%x.D%x.F%x - VfResource (Bar - 0x%x) (Type - 0x%x) (Length - 0x%x)\n", + (UINTN)PciDev->BusNumber, + (UINTN)PciDev->DeviceNumber, + (UINTN)PciDev->FunctionNumber, + (UINTN)Bar, + (UINTN)ResType, + (UINTN)Length + )); + + Node = CreateResourceNode (PciDev, Length, Alignment, Bar, ResType, ResUsage); + if (Node == NULL) { + return Node; + } + + Node->Virtual = TRUE; + + return Node; +} + +/** This function is used to extract resource request from device node list. @@ -1094,6 +1229,13 @@ ProgramBar ( UINT64 Address; UINT32 Address32; + // + // Check VF BAR + // + if (Node->Virtual) { + ProgramVfBar (Base, Node); + } + Address = 0; PciIo = &(Node->PciDev->PciIo); @@ -1160,6 +1302,116 @@ ProgramBar ( } /** + Program IOV VF Bar register for PCI device. + + @param Base Base address for PCI device resource to be progammed. + @param Node Point to resoure node structure. + +**/ +EFI_STATUS +ProgramVfBar ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Node + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 Address; + UINT32 Address32; + + ASSERT (Node->Virtual); + if (!Node->Virtual) { + return EFI_UNSUPPORTED; + } + + Address = 0; + PciIo = &(Node->PciDev->PciIo); + + Address = Base + Node->Offset; + + // + // Indicate pci bus driver has allocated + // resource for this device + // It might be a temporary solution here since + // pci device could have multiple bar + // + Node->PciDev->Allocated = TRUE; + + switch ((Node->PciDev->VfPciBar[Node->Bar]).BarType) { + + case PciBarTypeMem32: + case PciBarTypePMem32: + + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint32, + (Node->PciDev->VfPciBar[Node->Bar]).Offset, + 1, + &Address + ); + + Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address; + + DEBUG (( + EFI_D_INFO, + "PCI-IOV B%x.D%x.F%x - VF Bar (Offset - 0x%x) 32Mem (Address - 0x%x)\n", + (UINTN)Node->PciDev->BusNumber, + (UINTN)Node->PciDev->DeviceNumber, + (UINTN)Node->PciDev->FunctionNumber, + (UINTN)(Node->PciDev->VfPciBar[Node->Bar]).Offset, + (UINTN)Address + )); + + break; + + case PciBarTypeMem64: + case PciBarTypePMem64: + + Address32 = (UINT32) (Address & 0x00000000FFFFFFFF); + + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint32, + (Node->PciDev->VfPciBar[Node->Bar]).Offset, + 1, + &Address32 + ); + + Address32 = (UINT32) RShiftU64 (Address, 32); + + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint32, + ((Node->PciDev->VfPciBar[Node->Bar]).Offset + 4), + 1, + &Address32 + ); + + Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address; + + DEBUG (( + EFI_D_INFO, + "PCI-IOV B%x.D%x.F%x - VF Bar (Offset - 0x%x) 64Mem (Address - 0x%lx)\n", + (UINTN)Node->PciDev->BusNumber, + (UINTN)Node->PciDev->DeviceNumber, + (UINTN)Node->PciDev->FunctionNumber, + (UINTN)(Node->PciDev->VfPciBar[Node->Bar]).Offset, + (UINT64)Address + )); + + break; + + case PciBarTypeIo16: + case PciBarTypeIo32: + break; + + default: + break; + } + + return EFI_SUCCESS; +} + +/** Program PCI-PCI bridge apperture. @param Base Base address for resource. diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h index 96396fe86..faa6c0d60 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h @@ -35,6 +35,7 @@ typedef struct { UINT64 Length; BOOLEAN Reserved; PCI_RESOURCE_USAGE ResourceUsage; + BOOLEAN Virtual; } PCI_RESOURCE_NODE; #define RESOURCE_NODE_FROM_LINK(a) \ @@ -176,6 +177,28 @@ CreateResourceNode ( /** This function is used to extract resource request from + IOV VF device node list. + + @param Bridge Pci device instance. + @param IoNode Resource info node for IO. + @param Mem32Node Resource info node for 32-bit memory. + @param PMem32Node Resource info node for 32-bit Prefetchable Memory. + @param Mem64Node Resource info node for 64-bit memory. + @param PMem64Node Resource info node for 64-bit Prefetchable Memory. + +**/ +PCI_RESOURCE_NODE * +CreateVfResourceNode ( + IN PCI_IO_DEVICE *PciDev, + IN UINT64 Length, + IN UINT64 Alignment, + IN UINT8 Bar, + IN PCI_BAR_TYPE ResType, + IN PCI_RESOURCE_USAGE ResUsage + ); + +/** + This function is used to extract resource request from device node list. @param Bridge Pci device instance. @@ -288,6 +311,19 @@ ProgramBar ( ); /** + Program IOV VF Bar register for PCI device. + + @param Base Base address for PCI device resource to be progammed. + @param Node Point to resoure node structure. + +**/ +EFI_STATUS +ProgramVfBar ( + IN UINT64 Base, + IN PCI_RESOURCE_NODE *Node + ); + +/** Program PCI-PCI bridge apperture. @param Base Base address for resource. diff --git a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec index e7f496bbe..62225a6be 100644 --- a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec +++ b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec @@ -102,6 +102,16 @@ ## This PCD specifies whether Serial device use half hand shake. gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSerialUseHalfHandshake|FALSE|BOOLEAN|0x00010043 + ## This PCD specifies whether the Single Root I/O virtualization support. + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSrIovSupport|TRUE|BOOLEAN|0x10000044 + + ## This PCD specifies whether the Alternative Routing-ID support. + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdAriSupport|TRUE|BOOLEAN|0x10000045 + + ## This PCD specifies whether the Multi Root I/O virtualization support. + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdMrIovSupport|FALSE|BOOLEAN|0x10000046 + + [PcdsFixedAtBuild] ## FFS filename to find the default BMP Logo file. gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLogoFile |{ 0x99, 0x8b, 0xB2, 0x7B, 0xBB, 0x61, 0xD5, 0x11, 0x9A, 0x5D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }|VOID*|16 @@ -115,6 +125,12 @@ # BIT2 indicates if ISA memory is supported gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSupportedFeatures|0x05|UINT8|0x00010040 + ## Single root I/O virtualization virtual function memory BAR alignment + # BITN set indicates 2 of n+12 power + # BIT0 set indicates 4KB alignment + # BIT1 set indicates 8KB alignment + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize|0x1|UINT32|0x10000047 + [PcdsFixedAtBuild,PcdsPatchableInModule,PcdsDynamic] ## PcdStatusCodeMemorySize is used when PcdStatusCodeUseMemory is set to true # (PcdStatusCodeMemorySize * KBytes) is the total taken memory size. -- 2.11.4.GIT