From 7fc72ecb0d6db6699d9b3e2d3c7b059eb1b53a14 Mon Sep 17 00:00:00 2001 From: htao Date: Wed, 16 Sep 2009 09:32:06 +0000 Subject: add SR-IOV support in EDK II. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9269 6f19259b-4bc3-4df7-8a09-765794883524 --- 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 ++ 10 files changed, 972 insertions(+), 10 deletions(-) (limited to 'IntelFrameworkModulePkg/Bus') diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciBus.h index df224d12c4..0c1c864bc8 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 a3a13d55a0..a0f1e44e28 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 39f5271e9b..601af309b7 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 7019b5ea19..942bea941e 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.h +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciCommand.h @@ -118,6 +118,27 @@ LocateCapabilityRegBlock ( OUT UINT8 *NextRegBlock OPTIONAL ); +/** + 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. diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c index baad1ccd72..0eb9f9a9d1 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 2d5408abe0..66183960f1 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; } @@ -597,6 +607,80 @@ CreatePciDevicePath ( return PciIoDevice->DevicePath; } +/** + 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. @@ -1249,6 +1333,207 @@ SetNewAlign ( return ; } +/** + 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. @@ -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 6f2f1e6ea5..31238b45cf 100644 --- a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h @@ -158,6 +158,26 @@ CreatePciDevicePath ( IN PCI_IO_DEVICE *PciIoDevice ); +/** + 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. @@ -288,6 +308,23 @@ PciParseBar ( IN UINTN BarIndex ); +/** + 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. diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciLib.c b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciLib.c index 16c0cce99a..70b28df0b1 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 40d02354eb..17c864029b 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. // @@ -599,6 +687,53 @@ CreateResourceNode ( return Node; } +/** + 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); @@ -1159,6 +1301,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. diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h b/IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h index 96396fe869..faa6c0d60c 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) \ @@ -174,6 +175,28 @@ CreateResourceNode ( IN PCI_RESOURCE_USAGE ResUsage ); +/** + 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. @@ -287,6 +310,19 @@ ProgramBar ( IN PCI_RESOURCE_NODE *Node ); +/** + 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. -- cgit v1.2.3