1 /** @file
2   Temporarily enable IO and MMIO decoding for all PCI devices while QEMU
3   regenerates the ACPI tables.
4 
5   Copyright (C) 2016, Red Hat, Inc.
6 
7   SPDX-License-Identifier: BSD-2-Clause-Patent
8 **/
9 
10 #include <Library/MemoryAllocationLib.h>
11 
12 #include "AcpiPlatform.h"
13 
14 
15 /**
16   Collect all PciIo protocol instances in the system. Save their original
17   attributes, and enable IO and MMIO decoding for each.
18 
19   This is a best effort function; it doesn't return status codes. Its
20   caller is supposed to proceed even if this function fails.
21 
22   @param[out] OriginalAttributes  On output, a dynamically allocated array of
23                                   ORIGINAL_ATTRIBUTES elements. The array lists
24                                   the PciIo protocol instances found in the
25                                   system at the time of the call, plus the
26                                   original PCI attributes for each.
27 
28                                   Before returning, the function enables IO and
29                                   MMIO decoding for each PciIo instance it
30                                   finds.
31 
32                                   On error, or when no such instances are
33                                   found, OriginalAttributes is set to NULL.
34 
35   @param[out] Count               On output, the number of elements in
36                                   OriginalAttributes. On error it is set to
37                                   zero.
38 **/
39 VOID
EnablePciDecoding(OUT ORIGINAL_ATTRIBUTES ** OriginalAttributes,OUT UINTN * Count)40 EnablePciDecoding (
41   OUT ORIGINAL_ATTRIBUTES **OriginalAttributes,
42   OUT UINTN               *Count
43   )
44 {
45   EFI_STATUS          Status;
46   UINTN               NoHandles;
47   EFI_HANDLE          *Handles;
48   ORIGINAL_ATTRIBUTES *OrigAttrs;
49   UINTN               Idx;
50 
51   *OriginalAttributes = NULL;
52   *Count              = 0;
53 
54   if (PcdGetBool (PcdPciDisableBusEnumeration)) {
55     //
56     // The platform downloads ACPI tables from QEMU in general, but there are
57     // no root bridges in this execution. We're done.
58     //
59     return;
60   }
61 
62   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid,
63                   NULL /* SearchKey */, &NoHandles, &Handles);
64   if (Status == EFI_NOT_FOUND) {
65     //
66     // No PCI devices were found on either of the root bridges. We're done.
67     //
68     return;
69   }
70 
71   if (EFI_ERROR (Status)) {
72     DEBUG ((DEBUG_WARN, "%a: LocateHandleBuffer(): %r\n", __FUNCTION__,
73       Status));
74     return;
75   }
76 
77   OrigAttrs = AllocatePool (NoHandles * sizeof *OrigAttrs);
78   if (OrigAttrs == NULL) {
79     DEBUG ((DEBUG_WARN, "%a: AllocatePool(): out of resources\n",
80       __FUNCTION__));
81     goto FreeHandles;
82   }
83 
84   for (Idx = 0; Idx < NoHandles; ++Idx) {
85     EFI_PCI_IO_PROTOCOL *PciIo;
86     UINT64              Attributes;
87 
88     //
89     // Look up PciIo on the handle and stash it
90     //
91     Status = gBS->HandleProtocol (Handles[Idx], &gEfiPciIoProtocolGuid,
92                     (VOID**)&PciIo);
93     ASSERT_EFI_ERROR (Status);
94     OrigAttrs[Idx].PciIo = PciIo;
95 
96     //
97     // Stash the current attributes
98     //
99     Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationGet, 0,
100                       &OrigAttrs[Idx].PciAttributes);
101     if (EFI_ERROR (Status)) {
102       DEBUG ((DEBUG_WARN, "%a: EfiPciIoAttributeOperationGet: %r\n",
103         __FUNCTION__, Status));
104       goto RestoreAttributes;
105     }
106 
107     //
108     // Retrieve supported attributes
109     //
110     Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSupported, 0,
111                       &Attributes);
112     if (EFI_ERROR (Status)) {
113       DEBUG ((DEBUG_WARN, "%a: EfiPciIoAttributeOperationSupported: %r\n",
114         __FUNCTION__, Status));
115       goto RestoreAttributes;
116     }
117 
118     //
119     // Enable IO and MMIO decoding
120     //
121     Attributes &= EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY;
122     Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationEnable,
123                       Attributes, NULL);
124     if (EFI_ERROR (Status)) {
125       DEBUG ((DEBUG_WARN, "%a: EfiPciIoAttributeOperationEnable: %r\n",
126         __FUNCTION__, Status));
127       goto RestoreAttributes;
128     }
129   }
130 
131   //
132   // Success
133   //
134   FreePool (Handles);
135   *OriginalAttributes = OrigAttrs;
136   *Count              = NoHandles;
137   return;
138 
139 RestoreAttributes:
140   while (Idx > 0) {
141     --Idx;
142     OrigAttrs[Idx].PciIo->Attributes (OrigAttrs[Idx].PciIo,
143                             EfiPciIoAttributeOperationSet,
144                             OrigAttrs[Idx].PciAttributes,
145                             NULL
146                             );
147   }
148   FreePool (OrigAttrs);
149 
150 FreeHandles:
151   FreePool (Handles);
152 }
153 
154 
155 /**
156   Restore the original PCI attributes saved with EnablePciDecoding().
157 
158   @param[in] OriginalAttributes  The array allocated and populated by
159                                  EnablePciDecoding(). This parameter may be
160                                  NULL. If OriginalAttributes is NULL, then the
161                                  function is a no-op; otherwise the PciIo
162                                  attributes will be restored, and the
163                                  OriginalAttributes array will be freed.
164 
165   @param[in] Count               The Count value stored by EnablePciDecoding(),
166                                  the number of elements in OriginalAttributes.
167                                  Count may be zero if and only if
168                                  OriginalAttributes is NULL.
169 **/
170 VOID
RestorePciDecoding(IN ORIGINAL_ATTRIBUTES * OriginalAttributes,IN UINTN Count)171 RestorePciDecoding (
172   IN ORIGINAL_ATTRIBUTES *OriginalAttributes,
173   IN UINTN               Count
174   )
175 {
176   UINTN Idx;
177 
178   ASSERT ((OriginalAttributes == NULL) == (Count == 0));
179   if (OriginalAttributes == NULL) {
180     return;
181   }
182 
183   for (Idx = 0; Idx < Count; ++Idx) {
184     OriginalAttributes[Idx].PciIo->Attributes (
185                                      OriginalAttributes[Idx].PciIo,
186                                      EfiPciIoAttributeOperationSet,
187                                      OriginalAttributes[Idx].PciAttributes,
188                                      NULL
189                                      );
190   }
191   FreePool (OriginalAttributes);
192 }
193