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