--- /dev/null
+/** @file\r
+ Temporarily enable IO and MMIO decoding for all PCI devices while QEMU\r
+ regenerates the ACPI tables.\r
+\r
+ Copyright (C) 2016, Red Hat, Inc.\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ 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, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include "AcpiPlatform.h"\r
+\r
+\r
+/**\r
+ Collect all PciIo protocol instances in the system. Save their original\r
+ attributes, and enable IO and MMIO decoding for each.\r
+\r
+ This is a best effort function; it doesn't return status codes. Its\r
+ caller is supposed to proceed even if this function fails.\r
+\r
+ @param[out] OriginalAttributes On output, a dynamically allocated array of\r
+ ORIGINAL_ATTRIBUTES elements. The array lists\r
+ the PciIo protocol instances found in the\r
+ system at the time of the call, plus the\r
+ original PCI attributes for each.\r
+\r
+ Before returning, the function enables IO and\r
+ MMIO decoding for each PciIo instance it\r
+ finds.\r
+\r
+ On error, or when no such instances are\r
+ found, OriginalAttributes is set to NULL.\r
+\r
+ @param[out] Count On output, the number of elements in\r
+ OriginalAttributes. On error it is set to\r
+ zero.\r
+**/\r
+VOID\r
+EnablePciDecoding (\r
+ OUT ORIGINAL_ATTRIBUTES **OriginalAttributes,\r
+ OUT UINTN *Count\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN NoHandles;\r
+ EFI_HANDLE *Handles;\r
+ ORIGINAL_ATTRIBUTES *OrigAttrs;\r
+ UINTN Idx;\r
+\r
+ *OriginalAttributes = NULL;\r
+ *Count = 0;\r
+\r
+ if (PcdGetBool (PcdPciDisableBusEnumeration)) {\r
+ //\r
+ // The platform downloads ACPI tables from QEMU in general, but there are\r
+ // no root bridges in this execution. We're done.\r
+ //\r
+ return;\r
+ }\r
+\r
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid,\r
+ NULL /* SearchKey */, &NoHandles, &Handles);\r
+ if (Status == EFI_NOT_FOUND) {\r
+ //\r
+ // No PCI devices were found on either of the root bridges. We're done.\r
+ //\r
+ return;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_WARN, "%a: LocateHandleBuffer(): %r\n", __FUNCTION__,\r
+ Status));\r
+ return;\r
+ }\r
+\r
+ OrigAttrs = AllocatePool (NoHandles * sizeof *OrigAttrs);\r
+ if (OrigAttrs == NULL) {\r
+ DEBUG ((EFI_D_WARN, "%a: AllocatePool(): out of resources\n",\r
+ __FUNCTION__));\r
+ goto FreeHandles;\r
+ }\r
+\r
+ for (Idx = 0; Idx < NoHandles; ++Idx) {\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ //\r
+ // Look up PciIo on the handle and stash it\r
+ //\r
+ Status = gBS->HandleProtocol (Handles[Idx], &gEfiPciIoProtocolGuid,\r
+ (VOID**)&PciIo);\r
+ ASSERT_EFI_ERROR (Status);\r
+ OrigAttrs[Idx].PciIo = PciIo;\r
+\r
+ //\r
+ // Stash the current attributes\r
+ //\r
+ Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationGet, 0,\r
+ &OrigAttrs[Idx].PciAttributes);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_WARN, "%a: EfiPciIoAttributeOperationGet: %r\n",\r
+ __FUNCTION__, Status));\r
+ goto RestoreAttributes;\r
+ }\r
+\r
+ //\r
+ // Enable IO and MMIO decoding\r
+ //\r
+ Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationEnable,\r
+ EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY,\r
+ NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_WARN, "%a: EfiPciIoAttributeOperationEnable: %r\n",\r
+ __FUNCTION__, Status));\r
+ goto RestoreAttributes;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Success\r
+ //\r
+ FreePool (Handles);\r
+ *OriginalAttributes = OrigAttrs;\r
+ *Count = NoHandles;\r
+ return;\r
+\r
+RestoreAttributes:\r
+ while (Idx > 0) {\r
+ --Idx;\r
+ OrigAttrs[Idx].PciIo->Attributes (OrigAttrs[Idx].PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ OrigAttrs[Idx].PciAttributes,\r
+ NULL\r
+ );\r
+ }\r
+ FreePool (OrigAttrs);\r
+\r
+FreeHandles:\r
+ FreePool (Handles);\r
+}\r
+\r
+\r
+/**\r
+ Restore the original PCI attributes saved with EnablePciDecoding().\r
+\r
+ @param[in] OriginalAttributes The array allocated and populated by\r
+ EnablePciDecoding(). This parameter may be\r
+ NULL. If OriginalAttributes is NULL, then the\r
+ function is a no-op; otherwise the PciIo\r
+ attributes will be restored, and the\r
+ OriginalAttributes array will be freed.\r
+\r
+ @param[in] Count The Count value stored by EnablePciDecoding(),\r
+ the number of elements in OriginalAttributes.\r
+ Count may be zero if and only if\r
+ OriginalAttributes is NULL.\r
+**/\r
+VOID\r
+RestorePciDecoding (\r
+ IN ORIGINAL_ATTRIBUTES *OriginalAttributes,\r
+ IN UINTN Count\r
+ )\r
+{\r
+ UINTN Idx;\r
+\r
+ ASSERT ((OriginalAttributes == NULL) == (Count == 0));\r
+ if (OriginalAttributes == NULL) {\r
+ return;\r
+ }\r
+\r
+ for (Idx = 0; Idx < Count; ++Idx) {\r
+ OriginalAttributes[Idx].PciIo->Attributes (\r
+ OriginalAttributes[Idx].PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ OriginalAttributes[Idx].PciAttributes,\r
+ NULL\r
+ );\r
+ }\r
+ FreePool (OriginalAttributes);\r
+}\r