/** @file\r
Internal library implementation for PCI Bus module.\r
\r
-Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2019, 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
+ Retrieve the max bus number that is assigned to the Root Bridge hierarchy.\r
+ It can support the case that there are multiple bus ranges.\r
+\r
+ @param Bridge Bridge device instance.\r
+\r
+ @retval The max bus number that is assigned to this Root Bridge hierarchy.\r
+\r
+**/\r
+UINT16\r
+PciGetMaxBusNumber (\r
+ IN PCI_IO_DEVICE *Bridge\r
+ )\r
+{\r
+ PCI_IO_DEVICE *RootBridge;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;\r
+ UINT64 MaxNumberInRange;\r
+\r
+ //\r
+ // Get PCI Root Bridge device\r
+ //\r
+ RootBridge = Bridge;\r
+ while (RootBridge->Parent != NULL) {\r
+ RootBridge = RootBridge->Parent;\r
+ }\r
+ MaxNumberInRange = 0;\r
+ //\r
+ // Iterate the bus number ranges to get max PCI bus number\r
+ //\r
+ BusNumberRanges = RootBridge->BusNumberRanges;\r
+ while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
+ MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;\r
+ BusNumberRanges++;\r
+ }\r
+ return (UINT16) MaxNumberInRange;\r
+}\r
+\r
/**\r
Retrieve the PCI Card device BAR information via PciIo interface.\r
\r
\r
/**\r
Find the corresponding resource node for the Device in child list of BridgeResource.\r
- \r
+\r
@param[in] Device Pointer to PCI_IO_DEVICE.\r
@param[in] BridgeResource Pointer to PCI_RESOURCE_NODE.\r
@param[out] DeviceResources Pointer to a buffer to receive resources for the Device.\r
- \r
+\r
@return Count of the resource descriptors returned.\r
**/\r
UINTN\r
\r
/**\r
Dump the resource map of all the devices under Bridge.\r
- \r
+\r
@param[in] Bridge Bridge device instance.\r
@param[in] Resources Resource descriptors for the bridge device.\r
@param[in] ResourceCount Count of resource descriptors.\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
\r
- //\r
- // Reallocate flag\r
- //\r
- ReAllocate = FALSE;\r
-\r
//\r
// It may try several times if the resource allocation fails\r
//\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
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
Resources[2] = PMem32Bridge;\r
Resources[3] = Mem64Bridge;\r
Resources[4] = PMem64Bridge;\r
- DumpResourceMap (RootBridgeDev, Resources, sizeof (Resources) / sizeof (Resources[0]));\r
+ DumpResourceMap (RootBridgeDev, Resources, ARRAY_SIZE (Resources));\r
);\r
\r
FreePool (AcpiConfig);\r
UINT64 PciAddress;\r
EFI_HPC_PADDING_ATTRIBUTES Attributes;\r
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *NextDescriptors;\r
UINT16 BusRange;\r
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
BOOLEAN BusPadding;\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
BusPadding = FALSE;\r
if (gPciHotPlugInit != NULL) {\r
\r
- if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {\r
+ if (IsPciHotPlugBus (PciDevice)) {\r
\r
//\r
// If it is initialized, get the padded bus range\r
//\r
Status = gPciHotPlugInit->GetResourcePadding (\r
gPciHotPlugInit,\r
- gPciRootHpcPool[HpIndex].HpbDevicePath,\r
+ PciDevice->DevicePath,\r
PciAddress,\r
&State,\r
(VOID **) &Descriptors,\r
}\r
\r
BusRange = 0;\r
+ NextDescriptors = Descriptors;\r
Status = PciGetBusRange (\r
- &Descriptors,\r
+ &NextDescriptors,\r
NULL,\r
NULL,\r
&BusRange\r
\r
FreePool (Descriptors);\r
\r
- if (EFI_ERROR (Status)) {\r
+ if (!EFI_ERROR (Status)) {\r
+ BusPadding = TRUE;\r
+ } else if (Status != EFI_NOT_FOUND) {\r
+ //\r
+ // EFI_NOT_FOUND is not a real error. It indicates no bus number padding requested.\r
+ //\r
return Status;\r
}\r
-\r
- BusPadding = TRUE;\r
}\r
}\r
}\r
// Temporarily initialize SubBusNumber to maximum bus number to ensure the\r
// PCI configuration transaction to go through any PPB\r
//\r
- Register = 0xFF;\r
+ Register = PciGetMaxBusNumber (Bridge);\r
Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);\r
Status = PciRootBridgeIo->Pci.Write (\r
PciRootBridgeIo,\r