193 lines
5.9 KiB
C
193 lines
5.9 KiB
C
|
/** @file
|
||
|
Temporarily enable IO and MMIO decoding for all PCI devices while QEMU
|
||
|
regenerates the ACPI tables.
|
||
|
|
||
|
Copyright (C) 2016, Red Hat, Inc.
|
||
|
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
**/
|
||
|
|
||
|
#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);
|
||
|
}
|