/** @file\r
Internal library implementation for PCI Bus module.\r
\r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
L"PMem32",\r
L" Mem64",\r
L"PMem64",\r
+ L" OpRom",\r
L" Io",\r
L" Mem",\r
L"Unknow"\r
}\r
}\r
\r
+/**\r
+ Adjust the Devices' BAR size to minimum value if it support Resizeable BAR capability.\r
+\r
+ @param RootBridgeDev Pointer to instance of PCI_IO_DEVICE..\r
+\r
+ @return TRUE if BAR size is adjusted.\r
+\r
+**/\r
+BOOLEAN\r
+AdjustPciDeviceBarSize (\r
+ IN PCI_IO_DEVICE *RootBridgeDev\r
+ )\r
+{\r
+ PCI_IO_DEVICE *PciIoDevice;\r
+ LIST_ENTRY *CurrentLink;\r
+ BOOLEAN Adjusted;\r
+ UINTN Offset;\r
+ UINTN BarIndex;\r
+\r
+ Adjusted = FALSE;\r
+ CurrentLink = RootBridgeDev->ChildList.ForwardLink;\r
+\r
+ while (CurrentLink != NULL && CurrentLink != &RootBridgeDev->ChildList) {\r
+ PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+\r
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
+ if (AdjustPciDeviceBarSize (PciIoDevice)) {\r
+ Adjusted = TRUE;\r
+ }\r
+ } else {\r
+ if (PciIoDevice->ResizableBarOffset != 0) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "PciBus: [%02x|%02x|%02x] Adjust Pci Device Bar Size\n",\r
+ PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber\r
+ ));\r
+ PciProgramResizableBar (PciIoDevice, PciResizableBarMin);\r
+ //\r
+ // Start to parse the bars\r
+ //\r
+ for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {\r
+ Offset = PciParseBar (PciIoDevice, Offset, BarIndex);\r
+ }\r
+ Adjusted = TRUE;\r
+ DEBUG_CODE (DumpPciBars (PciIoDevice););\r
+ }\r
+ }\r
+\r
+ CurrentLink = CurrentLink->ForwardLink;\r
+ }\r
+\r
+ return Adjusted;\r
+}\r
+\r
/**\r
Submits the I/O and memory resource requirements for the specified PCI Host Bridge.\r
\r
UINT64 PMem32ResStatus;\r
UINT64 Mem64ResStatus;\r
UINT64 PMem64ResStatus;\r
- UINT64 MaxOptionRomSize;\r
+ UINT32 MaxOptionRomSize;\r
PCI_RESOURCE_NODE *IoBridge;\r
PCI_RESOURCE_NODE *Mem32Bridge;\r
PCI_RESOURCE_NODE *PMem32Bridge;\r
PCI_RESOURCE_NODE PMem32Pool;\r
PCI_RESOURCE_NODE Mem64Pool;\r
PCI_RESOURCE_NODE PMem64Pool;\r
- BOOLEAN ReAllocate;\r
EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;\r
EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;\r
+ BOOLEAN ResizableBarNeedAdjust;\r
+ BOOLEAN ResizableBarAdjusted;\r
\r
- //\r
- // Reallocate flag\r
- //\r
- ReAllocate = FALSE;\r
+ ResizableBarNeedAdjust = PcdGetBool (PcdPcieResizableBarSupport);\r
\r
//\r
// It may try several times if the resource allocation fails\r
PciResUsageTypical\r
);\r
\r
+ //\r
+ // Get the max ROM size that the root bridge can process\r
+ // Insert to resource map so that there will be dedicate MEM32 resource range for Option ROM.\r
+ // All devices' Option ROM share the same MEM32 resource.\r
+ //\r
+ MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);\r
+ if (MaxOptionRomSize != 0) {\r
+ RootBridgeDev->PciBar[0].BarType = PciBarTypeOpRom;\r
+ RootBridgeDev->PciBar[0].Length = MaxOptionRomSize;\r
+ RootBridgeDev->PciBar[0].Alignment = MaxOptionRomSize - 1;\r
+ GetResourceFromDevice (RootBridgeDev, IoBridge, Mem32Bridge, PMem32Bridge, Mem64Bridge, PMem64Bridge);\r
+ }\r
+\r
//\r
// Create resourcemap by going through all the devices subject to this root bridge\r
//\r
PMem64Bridge\r
);\r
\r
- //\r
- // Get the max ROM size that the root bridge can process\r
- //\r
- RootBridgeDev->RomSize = Mem32Bridge->Length;\r
-\r
- //\r
- // Skip to enlarge the resource request during realloction\r
- //\r
- if (!ReAllocate) {\r
- //\r
- // Get Max Option Rom size for current root bridge\r
- //\r
- MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);\r
-\r
- //\r
- // Enlarger the mem32 resource to accomdate the option rom\r
- // if the mem32 resource is not enough to hold the rom\r
- //\r
- if (MaxOptionRomSize > Mem32Bridge->Length) {\r
-\r
- Mem32Bridge->Length = MaxOptionRomSize;\r
- RootBridgeDev->RomSize = MaxOptionRomSize;\r
-\r
- //\r
- // Alignment should be adjusted as well\r
- //\r
- if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {\r
- Mem32Bridge->Alignment = MaxOptionRomSize - 1;\r
- }\r
- }\r
- }\r
-\r
//\r
// Based on the all the resource tree, construct ACPI resource node to\r
// submit the resource aperture to pci host bridge protocol\r
sizeof (AllocFailExtendedData)\r
);\r
\r
- Status = PciHostBridgeAdjustAllocation (\r
- &IoPool,\r
- &Mem32Pool,\r
- &PMem32Pool,\r
- &Mem64Pool,\r
- &PMem64Pool,\r
- IoResStatus,\r
- Mem32ResStatus,\r
- PMem32ResStatus,\r
- Mem64ResStatus,\r
- PMem64ResStatus\r
- );\r
-\r
+ //\r
+ // When resource conflict happens, adjust the BAR size first.\r
+ // Only when adjusting BAR size doesn't help or BAR size cannot be adjusted,\r
+ // reject the device who requests largest resource that causes conflict.\r
+ //\r
+ ResizableBarAdjusted = FALSE;\r
+ if (ResizableBarNeedAdjust) {\r
+ ResizableBarAdjusted = AdjustPciDeviceBarSize (RootBridgeDev);\r
+ ResizableBarNeedAdjust = FALSE;\r
+ }\r
+ if (!ResizableBarAdjusted) {\r
+ Status = PciHostBridgeAdjustAllocation (\r
+ &IoPool,\r
+ &Mem32Pool,\r
+ &PMem32Pool,\r
+ &Mem64Pool,\r
+ &PMem64Pool,\r
+ IoResStatus,\r
+ Mem32ResStatus,\r
+ PMem32ResStatus,\r
+ Mem64ResStatus,\r
+ PMem64ResStatus\r
+ );\r
+ }\r
//\r
// Destroy all the resource tree\r
//\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
-\r
- ReAllocate = TRUE;\r
}\r
}\r
//\r
&PMem64Base\r
);\r
\r
- //\r
- // Process option rom for this root bridge\r
- //\r
- ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);\r
-\r
//\r
// Create the entire system resource map from the information collected by\r
// enumerator. Several resource tree was created\r
PMem64Bridge\r
);\r
\r
+ //\r
+ // Process Option ROM for this root bridge after all BARs are programmed.\r
+ // The PPB's MEM32 RANGE BAR is re-programmed to the Option ROM BAR Base in order to\r
+ // shadow the Option ROM of the devices under the PPB.\r
+ // After the shadow, Option ROM BAR decoding is turned off and the PPB's MEM32 RANGE\r
+ // BAR is restored back to the original value.\r
+ // The original value is programmed by ProgramResource() above.\r
+ //\r
+ DEBUG ((\r
+ DEBUG_INFO, "Process Option ROM: BAR Base/Length = %lx/%lx\n",\r
+ RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length\r
+ ));\r
+ ProcessOptionRom (RootBridgeDev, RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length);\r
+\r
IoBridge ->PciDev->PciBar[IoBridge ->Bar].BaseAddress = IoBase;\r
Mem32Bridge ->PciDev->PciBar[Mem32Bridge ->Bar].BaseAddress = Mem32Base;\r
PMem32Bridge->PciDev->PciBar[PMem32Bridge->Bar].BaseAddress = PMem32Base;\r
&PciDevice\r
);\r
\r
- ASSERT (!EFI_ERROR (Status));\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
\r
PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);\r
\r
//\r
// For PPB\r
//\r
- if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
- //\r
- // If Hot Plug is not supported,\r
- // get the bridge information\r
- //\r
- Status = PciSearchDevice (\r
- Bridge,\r
- &Pci,\r
- StartBusNumber,\r
- Device,\r
- Func,\r
- &PciDevice\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- } else {\r
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
//\r
// If Hot Plug is supported,\r
// Get the bridge information\r
\r
return EFI_SUCCESS;\r
}\r
+\r
+/**\r
+ This function is used to program the Resizable BAR Register.\r
+\r
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
+ @param ResizableBarOp PciResizableBarMax: Set BAR to max size\r
+ PciResizableBarMin: set BAR to min size.\r
+\r
+ @retval EFI_SUCCESS Successfully enumerated the host bridge.\r
+ @retval other Some error occurred when enumerating the host bridge.\r
+\r
+**/\r
+EFI_STATUS\r
+PciProgramResizableBar (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN PCI_RESIZABLE_BAR_OPERATION ResizableBarOp\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT64 Capabilities;\r
+ UINT32 Index;\r
+ UINT32 Offset;\r
+ INTN Bit;\r
+ UINTN ResizableBarNumber;\r
+ EFI_STATUS Status;\r
+ PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY Entries[PCI_MAX_BAR];\r
+\r
+ ASSERT (PciIoDevice->ResizableBarOffset != 0);\r
+\r
+ DEBUG ((DEBUG_INFO, " Programs Resizable BAR register, offset: 0x%08x, number: %d\n",\r
+ PciIoDevice->ResizableBarOffset, PciIoDevice->ResizableBarNumber));\r
+\r
+ ResizableBarNumber = MIN (PciIoDevice->ResizableBarNumber, PCI_MAX_BAR);\r
+ PciIo = &PciIoDevice->PciIo;\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER),\r
+ sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY) * ResizableBarNumber,\r
+ (VOID *)(&Entries)\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ for (Index = 0; Index < ResizableBarNumber; Index++) {\r
+\r
+ //\r
+ // When the bit of Capabilities Set, indicates that the Function supports\r
+ // operating with the BAR sized to (2^Bit) MB.\r
+ // Example:\r
+ // Bit 0 is set: supports operating with the BAR sized to 1 MB\r
+ // Bit 1 is set: supports operating with the BAR sized to 2 MB\r
+ // Bit n is set: supports operating with the BAR sized to (2^n) MB\r
+ //\r
+ Capabilities = LShiftU64(Entries[Index].ResizableBarControl.Bits.BarSizeCapability, 28)\r
+ | Entries[Index].ResizableBarCapability.Bits.BarSizeCapability;\r
+\r
+ if (ResizableBarOp == PciResizableBarMax) {\r
+ Bit = HighBitSet64(Capabilities);\r
+ } else if (ResizableBarOp == PciResizableBarMin) {\r
+ Bit = LowBitSet64(Capabilities);\r
+ } else {\r
+ ASSERT ((ResizableBarOp == PciResizableBarMax) || (ResizableBarOp == PciResizableBarMin));\r
+ }\r
+\r
+ ASSERT (Bit >= 0);\r
+\r
+ Offset = PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)\r
+ + Index * sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY)\r
+ + OFFSET_OF (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY, ResizableBarControl);\r
+\r
+ Entries[Index].ResizableBarControl.Bits.BarSize = (UINT32) Bit;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " Resizable Bar: Offset = 0x%x, Bar Size Capability = 0x%016lx, New Bar Size = 0x%lx\n",\r
+ OFFSET_OF (PCI_TYPE00, Device.Bar[Entries[Index].ResizableBarControl.Bits.BarIndex]),\r
+ Capabilities, LShiftU64 (SIZE_1MB, Bit)\r
+ ));\r
+ PciIo->Pci.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ Offset,\r
+ 1,\r
+ &Entries[Index].ResizableBarControl.Uint32\r
+ );\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r