summaryrefslogtreecommitdiff
path: root/OvmfPkg
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg')
-rw-r--r--OvmfPkg/PciHostBridgeDxe/PciHostBridge.c54
1 files changed, 51 insertions, 3 deletions
diff --git a/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c b/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
index 7ca0b6e19b..a5dbe57eb2 100644
--- a/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
+++ b/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
@@ -154,6 +154,32 @@ FreePrivateData:
/**
+ Uninitialize and free a root bridge set up with InitRootBridge().
+
+ On return, the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance and the device path
+ will have been released, freeing RootBus->Handle as well.
+
+ param[in] RootBus The private PCI_ROOT_BRIDGE_INSTANCE that has been created
+ with InitRootBridge(), and should be released.
+**/
+STATIC
+VOID
+UninitRootBridge (
+ IN PCI_ROOT_BRIDGE_INSTANCE *RootBus
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (RootBus->Handle,
+ &gEfiDevicePathProtocolGuid, &RootBus->DevicePath,
+ &gEfiPciRootBridgeIoProtocolGuid, &RootBus->Io,
+ NULL);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (RootBus);
+}
+
+
+/**
Entry point of this driver
@param ImageHandle Handle of driver image
@@ -174,6 +200,7 @@ InitializePciHostBridge (
UINTN RootBridgeNumber;
PCI_HOST_BRIDGE_INSTANCE *HostBridge;
PCI_ROOT_BRIDGE_INSTANCE *RootBus;
+ EFI_STATUS UninstallStatus;
mDriverImageHandle = ImageHandle;
@@ -196,8 +223,7 @@ InitializePciHostBridge (
NULL
);
if (EFI_ERROR (Status)) {
- FreePool (HostBridge);
- return EFI_DEVICE_ERROR;
+ goto FreeHostBridge;
}
for (RootBridgeNumber = 0;
@@ -209,12 +235,34 @@ InitializePciHostBridge (
&RootBus
);
if (EFI_ERROR (Status)) {
- return Status;
+ goto RollbackProtocols;
}
InsertTailList (&HostBridge->Head, &RootBus->Link);
}
return EFI_SUCCESS;
+
+RollbackProtocols:
+ while (!IsListEmpty (&HostBridge->Head)) {
+ LIST_ENTRY *Entry;
+
+ Entry = GetFirstNode (&HostBridge->Head);
+ RemoveEntryList (Entry);
+ RootBus = DRIVER_INSTANCE_FROM_LIST_ENTRY (Entry);
+ UninitRootBridge (RootBus);
+ }
+ UninstallStatus = gBS->UninstallMultipleProtocolInterfaces (
+ HostBridge->HostBridgeHandle,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+ &HostBridge->ResAlloc,
+ NULL
+ );
+ ASSERT_EFI_ERROR (UninstallStatus);
+
+FreeHostBridge:
+ FreePool (HostBridge);
+
+ return Status;
}