\r
**/\r
\r
+#include <Library/QemuFwCfgLib.h>\r
+\r
#include "PciHostBridge.h"\r
\r
STATIC\r
}\r
};\r
\r
-//\r
-// Hard code: Root Bridge's resource aperture\r
-//\r
-\r
-PCI_ROOT_BRIDGE_RESOURCE_APERTURE mResAperture[1] = {\r
- {0, 0xff, 0x80000000, 0xffffffff, 0, 0xffff}\r
-};\r
-\r
EFI_HANDLE mDriverImageHandle;\r
\r
PCI_HOST_BRIDGE_INSTANCE mPciHostBridgeInstanceTemplate = {\r
PCI_HOST_BRIDGE_SIGNATURE, // Signature\r
NULL, // HostBridgeHandle\r
- 0, // RootBridgeNumber\r
{NULL, NULL}, // Head\r
FALSE, // ResourceSubiteed\r
TRUE, // CanRestarted\r
\r
param[in] RootBusNumber The bus number of the root bus (root bridge) to\r
create.\r
- RootBusNumber is expected to fall into the valid\r
- offset range of mResAperture.\r
+\r
+ param[in] MaxSubBusNumber The inclusive maximum bus number that can be\r
+ assigned to any subordinate bus found behind any\r
+ PCI bridge hanging off this root bus.\r
+\r
+ The caller is repsonsible for ensuring that\r
+ RootBusNumber <= MaxSubBusNumber. If\r
+ RootBusNumber equals MaxSubBusNumber, then the\r
+ root bus has no room for subordinate buses.\r
\r
param[in] HostBridgeHandle The EFI_HANDLE corresponding to the host bridge\r
that is the parent of the root bridge to create.\r
EFI_STATUS\r
InitRootBridge (\r
IN UINT8 RootBusNumber,\r
+ IN UINT8 MaxSubBusNumber,\r
IN EFI_HANDLE HostBridgeHandle,\r
OUT PCI_ROOT_BRIDGE_INSTANCE **RootBus\r
)\r
{\r
- PCI_ROOT_BRIDGE_INSTANCE *PrivateData;\r
- EFI_STATUS Status;\r
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;\r
+ PCI_ROOT_BRIDGE_RESOURCE_APERTURE ResAperture;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (RootBusNumber <= MaxSubBusNumber);\r
\r
PrivateData = AllocateZeroPool (sizeof *PrivateData);\r
if (PrivateData == NULL) {\r
sizeof mRootBridgeDevicePathTemplate);\r
PrivateData->DevicePath.AcpiDevicePath.UID = RootBusNumber;\r
\r
+ ResAperture.BusBase = RootBusNumber;\r
+ ResAperture.BusLimit = MaxSubBusNumber;\r
+ ResAperture.MemBase = BASE_2GB;\r
+ ResAperture.MemLimit = BASE_4GB - 1;\r
+ ResAperture.IoBase = 0;\r
+ ResAperture.IoLimit = MAX_UINT16;\r
//\r
// The function call below allocates no resources and performs no actions\r
// that have to be rolled back on later failure. It always succeeds.\r
//\r
Status = RootBridgeConstructor (&PrivateData->Io, HostBridgeHandle,\r
- EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM,\r
- &mResAperture[RootBusNumber]);\r
+ EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM, &ResAperture);\r
ASSERT_EFI_ERROR (Status);\r
\r
Status = gBS->InstallMultipleProtocolInterfaces (&PrivateData->Handle,\r
goto FreePrivateData;\r
}\r
\r
+ DEBUG ((EFI_D_INFO,\r
+ "%a: installed root bus %d, with room for %d subordinate bus(es)\n",\r
+ __FUNCTION__, RootBusNumber, MaxSubBusNumber - RootBusNumber));\r
*RootBus = PrivateData;\r
return EFI_SUCCESS;\r
\r
}\r
\r
\r
+/**\r
+ Uninitialize and free a root bridge set up with InitRootBridge().\r
+\r
+ On return, the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance and the device path\r
+ will have been released, freeing RootBus->Handle as well.\r
+\r
+ param[in] RootBus The private PCI_ROOT_BRIDGE_INSTANCE that has been created\r
+ with InitRootBridge(), and should be released.\r
+**/\r
+STATIC\r
+VOID\r
+UninitRootBridge (\r
+ IN PCI_ROOT_BRIDGE_INSTANCE *RootBus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (RootBus->Handle,\r
+ &gEfiDevicePathProtocolGuid, &RootBus->DevicePath,\r
+ &gEfiPciRootBridgeIoProtocolGuid, &RootBus->Io,\r
+ NULL);\r
+ ASSERT_EFI_ERROR (Status);\r
+ FreePool (RootBus);\r
+}\r
+\r
+\r
/**\r
Entry point of this driver\r
\r
)\r
{\r
EFI_STATUS Status;\r
+ FIRMWARE_CONFIG_ITEM FwCfgItem;\r
+ UINTN FwCfgSize;\r
+ UINT64 ExtraRootBridgesLeft;\r
+ UINTN LastRootBridgeNumber;\r
UINTN RootBridgeNumber;\r
PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
PCI_ROOT_BRIDGE_INSTANCE *RootBus;\r
+ EFI_STATUS UninstallStatus;\r
\r
mDriverImageHandle = ImageHandle;\r
\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- HostBridge->RootBridgeNumber = 1;\r
InitializeListHead (&HostBridge->Head);\r
\r
Status = gBS->InstallMultipleProtocolInterfaces (\r
NULL\r
);\r
if (EFI_ERROR (Status)) {\r
- FreePool (HostBridge);\r
- return EFI_DEVICE_ERROR;\r
+ goto FreeHostBridge;\r
}\r
\r
- for (RootBridgeNumber = 0;\r
- RootBridgeNumber < HostBridge->RootBridgeNumber;\r
+ //\r
+ // QEMU provides the number of extra root buses, shortening the exhaustive\r
+ // search below. If there is no hint, the feature is missing.\r
+ //\r
+ Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);\r
+ if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridgesLeft) {\r
+ ExtraRootBridgesLeft = 0;\r
+ } else {\r
+ QemuFwCfgSelectItem (FwCfgItem);\r
+ QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridgesLeft);\r
+ DEBUG ((EFI_D_INFO, "%a: %Lu extra root buses reported by QEMU\n",\r
+ __FUNCTION__, ExtraRootBridgesLeft));\r
+ }\r
+\r
+ //\r
+ // The "main" root bus is always there.\r
+ //\r
+ LastRootBridgeNumber = 0;\r
+\r
+ //\r
+ // Scan all other root buses. If function 0 of any device on a bus returns a\r
+ // VendorId register value different from all-bits-one, then that bus is\r
+ // alive.\r
+ //\r
+ for (RootBridgeNumber = 1;\r
+ RootBridgeNumber < 256 && ExtraRootBridgesLeft > 0;\r
++RootBridgeNumber) {\r
- Status = InitRootBridge (\r
- (UINT8)RootBridgeNumber,\r
- HostBridge->HostBridgeHandle,\r
- &RootBus\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
+ UINTN Device;\r
+\r
+ for (Device = 0; Device <= MAX_PCI_DEVICE_NUMBER; ++Device) {\r
+ if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0,\r
+ PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) {\r
+ break;\r
+ }\r
+ }\r
+ if (Device <= MAX_PCI_DEVICE_NUMBER) {\r
+ //\r
+ // Found the next root bus. We can now install the *previous* one,\r
+ // because now we know how big a bus number range *that* one has, for any\r
+ // subordinate buses that might exist behind PCI bridges hanging off it.\r
+ //\r
+ Status = InitRootBridge ((UINT8)LastRootBridgeNumber,\r
+ (UINT8)(RootBridgeNumber - 1), HostBridge->HostBridgeHandle,\r
+ &RootBus);\r
+ if (EFI_ERROR (Status)) {\r
+ goto RollbackProtocols;\r
+ }\r
+ InsertTailList (&HostBridge->Head, &RootBus->Link);\r
+ LastRootBridgeNumber = RootBridgeNumber;\r
+ --ExtraRootBridgesLeft;\r
}\r
- InsertTailList (&HostBridge->Head, &RootBus->Link);\r
}\r
\r
+ //\r
+ // Install the last root bus (which might be the only, ie. main, root bus, if\r
+ // we've found no extra root buses).\r
+ //\r
+ Status = InitRootBridge ((UINT8)LastRootBridgeNumber, 255,\r
+ HostBridge->HostBridgeHandle, &RootBus);\r
+ if (EFI_ERROR (Status)) {\r
+ goto RollbackProtocols;\r
+ }\r
+ InsertTailList (&HostBridge->Head, &RootBus->Link);\r
+\r
return EFI_SUCCESS;\r
+\r
+RollbackProtocols:\r
+ while (!IsListEmpty (&HostBridge->Head)) {\r
+ LIST_ENTRY *Entry;\r
+\r
+ Entry = GetFirstNode (&HostBridge->Head);\r
+ RemoveEntryList (Entry);\r
+ RootBus = DRIVER_INSTANCE_FROM_LIST_ENTRY (Entry);\r
+ UninitRootBridge (RootBus);\r
+ }\r
+ UninstallStatus = gBS->UninstallMultipleProtocolInterfaces (\r
+ HostBridge->HostBridgeHandle,\r
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,\r
+ &HostBridge->ResAlloc,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (UninstallStatus);\r
+\r
+FreeHostBridge:\r
+ FreePool (HostBridge);\r
+\r
+ return Status;\r
}\r
\r
\r