1 | /** @file
|
---|
2 | This driver implements EFI_PCI_HOT_PLUG_INIT_PROTOCOL, providing the PCI bus
|
---|
3 | driver with resource padding information, for PCIe hotplug purposes.
|
---|
4 |
|
---|
5 | Copyright (C) 2016, Red Hat, Inc.
|
---|
6 |
|
---|
7 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
8 | **/
|
---|
9 |
|
---|
10 | #include <IndustryStandard/Acpi10.h>
|
---|
11 | #include <IndustryStandard/Q35MchIch9.h>
|
---|
12 | #include <IndustryStandard/QemuPciBridgeCapabilities.h>
|
---|
13 |
|
---|
14 | #include <Library/BaseLib.h>
|
---|
15 | #include <Library/BaseMemoryLib.h>
|
---|
16 | #include <Library/DebugLib.h>
|
---|
17 | #include <Library/DevicePathLib.h>
|
---|
18 | #include <Library/MemoryAllocationLib.h>
|
---|
19 | #include <Library/PciCapLib.h>
|
---|
20 | #include <Library/PciCapPciSegmentLib.h>
|
---|
21 | #include <Library/PciLib.h>
|
---|
22 | #include <Library/UefiBootServicesTableLib.h>
|
---|
23 |
|
---|
24 | #include <Protocol/PciHotPlugInit.h>
|
---|
25 | #include <Protocol/PciRootBridgeIo.h>
|
---|
26 |
|
---|
27 | //
|
---|
28 | // TRUE if the PCI platform supports extended config space, FALSE otherwise.
|
---|
29 | //
|
---|
30 | STATIC BOOLEAN mPciExtConfSpaceSupported;
|
---|
31 |
|
---|
32 |
|
---|
33 | //
|
---|
34 | // The protocol interface this driver produces.
|
---|
35 | //
|
---|
36 | // Refer to 12.6 "PCI Hot Plug PCI Initialization Protocol" in the Platform
|
---|
37 | // Init 1.4a Spec, Volume 5.
|
---|
38 | //
|
---|
39 | STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit;
|
---|
40 |
|
---|
41 |
|
---|
42 | //
|
---|
43 | // Resource padding template for the GetResourcePadding() protocol member
|
---|
44 | // function.
|
---|
45 | //
|
---|
46 | // Refer to Table 8 "ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage" in
|
---|
47 | // the Platform Init 1.4a Spec, Volume 5.
|
---|
48 | //
|
---|
49 | // This structure is interpreted by the ApplyResourcePadding() function in the
|
---|
50 | // edk2 PCI Bus UEFI_DRIVER.
|
---|
51 | //
|
---|
52 | // We can request padding for at most four resource types, each of which is
|
---|
53 | // optional, independently of the others:
|
---|
54 | // (a) bus numbers,
|
---|
55 | // (b) IO space,
|
---|
56 | // (c) non-prefetchable MMIO space (32-bit only),
|
---|
57 | // (d) prefetchable MMIO space (either 32-bit or 64-bit, never both).
|
---|
58 | //
|
---|
59 | #pragma pack (1)
|
---|
60 | typedef struct {
|
---|
61 | EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Padding[4];
|
---|
62 | EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
|
---|
63 | } RESOURCE_PADDING;
|
---|
64 | #pragma pack ()
|
---|
65 |
|
---|
66 |
|
---|
67 | /**
|
---|
68 | Initialize a RESOURCE_PADDING object.
|
---|
69 |
|
---|
70 | @param[out] ResourcePadding The caller-allocated RESOURCE_PADDING object to
|
---|
71 | initialize.
|
---|
72 | **/
|
---|
73 | STATIC
|
---|
74 | VOID
|
---|
75 | InitializeResourcePadding (
|
---|
76 | OUT RESOURCE_PADDING *ResourcePadding
|
---|
77 | )
|
---|
78 | {
|
---|
79 | UINTN Index;
|
---|
80 |
|
---|
81 | ZeroMem (ResourcePadding, sizeof *ResourcePadding);
|
---|
82 |
|
---|
83 | //
|
---|
84 | // Fill in the Padding fields that don't vary across resource types.
|
---|
85 | //
|
---|
86 | for (Index = 0; Index < ARRAY_SIZE (ResourcePadding->Padding); ++Index) {
|
---|
87 | EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
|
---|
88 |
|
---|
89 | Descriptor = ResourcePadding->Padding + Index;
|
---|
90 | Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
|
---|
91 | Descriptor->Len = (UINT16)(
|
---|
92 | sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -
|
---|
93 | OFFSET_OF (
|
---|
94 | EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,
|
---|
95 | ResType
|
---|
96 | )
|
---|
97 | );
|
---|
98 | }
|
---|
99 |
|
---|
100 | //
|
---|
101 | // Fill in the End Tag.
|
---|
102 | //
|
---|
103 | ResourcePadding->EndDesc.Desc = ACPI_END_TAG_DESCRIPTOR;
|
---|
104 | }
|
---|
105 |
|
---|
106 |
|
---|
107 | /**
|
---|
108 | Set up a descriptor entry for reserving IO space.
|
---|
109 |
|
---|
110 | @param[in,out] Descriptor The descriptor to configure. The caller shall have
|
---|
111 | initialized Descriptor earlier, with
|
---|
112 | InitializeResourcePadding().
|
---|
113 |
|
---|
114 | @param[in] SizeExponent The size and natural alignment of the reservation
|
---|
115 | are determined by raising two to this power.
|
---|
116 | **/
|
---|
117 | STATIC
|
---|
118 | VOID
|
---|
119 | SetIoPadding (
|
---|
120 | IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor,
|
---|
121 | IN UINTN SizeExponent
|
---|
122 | )
|
---|
123 | {
|
---|
124 | Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
|
---|
125 | Descriptor->AddrLen = LShiftU64 (1, SizeExponent);
|
---|
126 | Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;
|
---|
127 | }
|
---|
128 |
|
---|
129 |
|
---|
130 | /**
|
---|
131 | Set up a descriptor entry for reserving MMIO space.
|
---|
132 |
|
---|
133 | @param[in,out] Descriptor The descriptor to configure. The caller shall
|
---|
134 | have initialized Descriptor earlier, with
|
---|
135 | InitializeResourcePadding().
|
---|
136 |
|
---|
137 | @param[in] Prefetchable TRUE if the descriptor should reserve
|
---|
138 | prefetchable MMIO space. Pass FALSE for
|
---|
139 | reserving non-prefetchable MMIO space.
|
---|
140 |
|
---|
141 | @param[in] ThirtyTwoBitOnly TRUE if the reservation should be limited to
|
---|
142 | 32-bit address space. FALSE if the reservation
|
---|
143 | can be satisfied from 64-bit address space.
|
---|
144 | ThirtyTwoBitOnly is ignored if Prefetchable is
|
---|
145 | FALSE; in that case ThirtyTwoBitOnly is always
|
---|
146 | considered TRUE.
|
---|
147 |
|
---|
148 | @param[in] SizeExponent The size and natural alignment of the
|
---|
149 | reservation are determined by raising two to
|
---|
150 | this power.
|
---|
151 | **/
|
---|
152 | STATIC
|
---|
153 | VOID
|
---|
154 | SetMmioPadding (
|
---|
155 | IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor,
|
---|
156 | IN BOOLEAN Prefetchable,
|
---|
157 | IN BOOLEAN ThirtyTwoBitOnly,
|
---|
158 | IN UINTN SizeExponent
|
---|
159 | )
|
---|
160 | {
|
---|
161 | Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
|
---|
162 | if (Prefetchable) {
|
---|
163 | Descriptor->SpecificFlag =
|
---|
164 | EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
|
---|
165 | Descriptor->AddrSpaceGranularity = ThirtyTwoBitOnly ? 32 : 64;
|
---|
166 | } else {
|
---|
167 | Descriptor->SpecificFlag =
|
---|
168 | EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_NON_CACHEABLE;
|
---|
169 | Descriptor->AddrSpaceGranularity = 32;
|
---|
170 | }
|
---|
171 | Descriptor->AddrLen = LShiftU64 (1, SizeExponent);
|
---|
172 | Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;
|
---|
173 | }
|
---|
174 |
|
---|
175 |
|
---|
176 | /**
|
---|
177 | Round up a positive 32-bit value to the next whole power of two, and return
|
---|
178 | the bit position of the highest bit set in the result. Equivalent to
|
---|
179 | ceil(log2(x)).
|
---|
180 |
|
---|
181 | @param[in] Operand The 32-bit operand to evaluate.
|
---|
182 |
|
---|
183 | @retval -1 Operand is zero.
|
---|
184 |
|
---|
185 | @retval -1 Operand is positive, not a whole power of two, and rounding it
|
---|
186 | up to the next power of two does not fit into 32 bits.
|
---|
187 |
|
---|
188 | @retval 0..31 Otherwise, return ceil(log2(Value)).
|
---|
189 | **/
|
---|
190 | STATIC
|
---|
191 | INTN
|
---|
192 | HighBitSetRoundUp32 (
|
---|
193 | IN UINT32 Operand
|
---|
194 | )
|
---|
195 | {
|
---|
196 | INTN HighBit;
|
---|
197 |
|
---|
198 | HighBit = HighBitSet32 (Operand);
|
---|
199 | if (HighBit == -1) {
|
---|
200 | //
|
---|
201 | // Operand is zero.
|
---|
202 | //
|
---|
203 | return HighBit;
|
---|
204 | }
|
---|
205 | if ((Operand & (Operand - 1)) != 0) {
|
---|
206 | //
|
---|
207 | // Operand is not a whole power of two.
|
---|
208 | //
|
---|
209 | ++HighBit;
|
---|
210 | }
|
---|
211 | return (HighBit < 32) ? HighBit : -1;
|
---|
212 | }
|
---|
213 |
|
---|
214 |
|
---|
215 | /**
|
---|
216 | Round up a positive 64-bit value to the next whole power of two, and return
|
---|
217 | the bit position of the highest bit set in the result. Equivalent to
|
---|
218 | ceil(log2(x)).
|
---|
219 |
|
---|
220 | @param[in] Operand The 64-bit operand to evaluate.
|
---|
221 |
|
---|
222 | @retval -1 Operand is zero.
|
---|
223 |
|
---|
224 | @retval -1 Operand is positive, not a whole power of two, and rounding it
|
---|
225 | up to the next power of two does not fit into 64 bits.
|
---|
226 |
|
---|
227 | @retval 0..63 Otherwise, return ceil(log2(Value)).
|
---|
228 | **/
|
---|
229 | STATIC
|
---|
230 | INTN
|
---|
231 | HighBitSetRoundUp64 (
|
---|
232 | IN UINT64 Operand
|
---|
233 | )
|
---|
234 | {
|
---|
235 | INTN HighBit;
|
---|
236 |
|
---|
237 | HighBit = HighBitSet64 (Operand);
|
---|
238 | if (HighBit == -1) {
|
---|
239 | //
|
---|
240 | // Operand is zero.
|
---|
241 | //
|
---|
242 | return HighBit;
|
---|
243 | }
|
---|
244 | if ((Operand & (Operand - 1)) != 0) {
|
---|
245 | //
|
---|
246 | // Operand is not a whole power of two.
|
---|
247 | //
|
---|
248 | ++HighBit;
|
---|
249 | }
|
---|
250 | return (HighBit < 64) ? HighBit : -1;
|
---|
251 | }
|
---|
252 |
|
---|
253 |
|
---|
254 | /**
|
---|
255 | Look up the QEMU-specific Resource Reservation capability in the conventional
|
---|
256 | config space of a Hotplug Controller (that is, PCI Bridge).
|
---|
257 |
|
---|
258 | On error, the contents of ReservationHint are indeterminate.
|
---|
259 |
|
---|
260 | @param[in] HpcPciAddress The address of the PCI Bridge -- Bus, Device,
|
---|
261 | Function -- in UEFI (not PciLib) encoding.
|
---|
262 |
|
---|
263 | @param[out] ReservationHint The caller-allocated capability structure to
|
---|
264 | populate from the PCI Bridge's config space.
|
---|
265 |
|
---|
266 | @retval EFI_SUCCESS The capability has been found, ReservationHint has
|
---|
267 | been populated.
|
---|
268 |
|
---|
269 | @retval EFI_NOT_FOUND The capability is missing.
|
---|
270 |
|
---|
271 | @return Error codes from PciCapPciSegmentLib and PciCapLib.
|
---|
272 | **/
|
---|
273 | STATIC
|
---|
274 | EFI_STATUS
|
---|
275 | QueryReservationHint (
|
---|
276 | IN CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *HpcPciAddress,
|
---|
277 | OUT QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION *ReservationHint
|
---|
278 | )
|
---|
279 | {
|
---|
280 | UINT16 PciVendorId;
|
---|
281 | EFI_STATUS Status;
|
---|
282 | PCI_CAP_DEV *PciDevice;
|
---|
283 | PCI_CAP_LIST *CapList;
|
---|
284 | UINT16 VendorInstance;
|
---|
285 | PCI_CAP *VendorCap;
|
---|
286 |
|
---|
287 | //
|
---|
288 | // Check the vendor identifier.
|
---|
289 | //
|
---|
290 | PciVendorId = PciRead16 (
|
---|
291 | PCI_LIB_ADDRESS (
|
---|
292 | HpcPciAddress->Bus,
|
---|
293 | HpcPciAddress->Device,
|
---|
294 | HpcPciAddress->Function,
|
---|
295 | PCI_VENDOR_ID_OFFSET
|
---|
296 | )
|
---|
297 | );
|
---|
298 | if (PciVendorId != QEMU_PCI_BRIDGE_VENDOR_ID_REDHAT) {
|
---|
299 | return EFI_NOT_FOUND;
|
---|
300 | }
|
---|
301 |
|
---|
302 | //
|
---|
303 | // Parse the capabilities lists.
|
---|
304 | //
|
---|
305 | Status = PciCapPciSegmentDeviceInit (
|
---|
306 | mPciExtConfSpaceSupported ? PciCapExtended : PciCapNormal,
|
---|
307 | 0, // Segment
|
---|
308 | HpcPciAddress->Bus,
|
---|
309 | HpcPciAddress->Device,
|
---|
310 | HpcPciAddress->Function,
|
---|
311 | &PciDevice
|
---|
312 | );
|
---|
313 | if (EFI_ERROR (Status)) {
|
---|
314 | return Status;
|
---|
315 | }
|
---|
316 | Status = PciCapListInit (PciDevice, &CapList);
|
---|
317 | if (EFI_ERROR (Status)) {
|
---|
318 | goto UninitPciDevice;
|
---|
319 | }
|
---|
320 |
|
---|
321 | //
|
---|
322 | // Scan the vendor capability instances for the Resource Reservation
|
---|
323 | // capability.
|
---|
324 | //
|
---|
325 | VendorInstance = 0;
|
---|
326 | for (;;) {
|
---|
327 | UINT8 VendorLength;
|
---|
328 | UINT8 BridgeCapType;
|
---|
329 |
|
---|
330 | Status = PciCapListFindCap (
|
---|
331 | CapList,
|
---|
332 | PciCapNormal,
|
---|
333 | EFI_PCI_CAPABILITY_ID_VENDOR,
|
---|
334 | VendorInstance++,
|
---|
335 | &VendorCap
|
---|
336 | );
|
---|
337 | if (EFI_ERROR (Status)) {
|
---|
338 | goto UninitCapList;
|
---|
339 | }
|
---|
340 |
|
---|
341 | //
|
---|
342 | // Check the vendor capability length.
|
---|
343 | //
|
---|
344 | Status = PciCapRead (
|
---|
345 | PciDevice,
|
---|
346 | VendorCap,
|
---|
347 | OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length),
|
---|
348 | &VendorLength,
|
---|
349 | sizeof VendorLength
|
---|
350 | );
|
---|
351 | if (EFI_ERROR (Status)) {
|
---|
352 | goto UninitCapList;
|
---|
353 | }
|
---|
354 | if (VendorLength != sizeof *ReservationHint) {
|
---|
355 | continue;
|
---|
356 | }
|
---|
357 |
|
---|
358 | //
|
---|
359 | // Check the vendor bridge capability type.
|
---|
360 | //
|
---|
361 | Status = PciCapRead (
|
---|
362 | PciDevice,
|
---|
363 | VendorCap,
|
---|
364 | OFFSET_OF (QEMU_PCI_BRIDGE_CAPABILITY_HDR, Type),
|
---|
365 | &BridgeCapType,
|
---|
366 | sizeof BridgeCapType
|
---|
367 | );
|
---|
368 | if (EFI_ERROR (Status)) {
|
---|
369 | goto UninitCapList;
|
---|
370 | }
|
---|
371 | if (BridgeCapType ==
|
---|
372 | QEMU_PCI_BRIDGE_CAPABILITY_TYPE_RESOURCE_RESERVATION) {
|
---|
373 | //
|
---|
374 | // We have a match.
|
---|
375 | //
|
---|
376 | break;
|
---|
377 | }
|
---|
378 | }
|
---|
379 |
|
---|
380 | //
|
---|
381 | // Populate ReservationHint.
|
---|
382 | //
|
---|
383 | Status = PciCapRead (
|
---|
384 | PciDevice,
|
---|
385 | VendorCap,
|
---|
386 | 0, // SourceOffsetInCap
|
---|
387 | ReservationHint,
|
---|
388 | sizeof *ReservationHint
|
---|
389 | );
|
---|
390 |
|
---|
391 | UninitCapList:
|
---|
392 | PciCapListUninit (CapList);
|
---|
393 |
|
---|
394 | UninitPciDevice:
|
---|
395 | PciCapPciSegmentDeviceUninit (PciDevice);
|
---|
396 |
|
---|
397 | return Status;
|
---|
398 | }
|
---|
399 |
|
---|
400 |
|
---|
401 | /**
|
---|
402 | Returns a list of root Hot Plug Controllers (HPCs) that require
|
---|
403 | initialization during the boot process.
|
---|
404 |
|
---|
405 | This procedure returns a list of root HPCs. The PCI bus driver must
|
---|
406 | initialize these controllers during the boot process. The PCI bus driver may
|
---|
407 | or may not be able to detect these HPCs. If the platform includes a
|
---|
408 | PCI-to-CardBus bridge, it can be included in this list if it requires
|
---|
409 | initialization. The HpcList must be self consistent. An HPC cannot control
|
---|
410 | any of its parent buses. Only one HPC can control a PCI bus. Because this
|
---|
411 | list includes only root HPCs, no HPC in the list can be a child of another
|
---|
412 | HPC. This policy must be enforced by the EFI_PCI_HOT_PLUG_INIT_PROTOCOL.
|
---|
413 | The PCI bus driver may not check for such invalid conditions. The callee
|
---|
414 | allocates the buffer HpcList
|
---|
415 |
|
---|
416 | @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
|
---|
417 | instance.
|
---|
418 | @param[out] HpcCount The number of root HPCs that were returned.
|
---|
419 | @param[out] HpcList The list of root HPCs. HpcCount defines the number of
|
---|
420 | elements in this list.
|
---|
421 |
|
---|
422 | @retval EFI_SUCCESS HpcList was returned.
|
---|
423 | @retval EFI_OUT_OF_RESOURCES HpcList was not returned due to insufficient
|
---|
424 | resources.
|
---|
425 | @retval EFI_INVALID_PARAMETER HpcCount is NULL or HpcList is NULL.
|
---|
426 | **/
|
---|
427 | STATIC
|
---|
428 | EFI_STATUS
|
---|
429 | EFIAPI
|
---|
430 | GetRootHpcList (
|
---|
431 | IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
|
---|
432 | OUT UINTN *HpcCount,
|
---|
433 | OUT EFI_HPC_LOCATION **HpcList
|
---|
434 | )
|
---|
435 | {
|
---|
436 | if (HpcCount == NULL || HpcList == NULL) {
|
---|
437 | return EFI_INVALID_PARAMETER;
|
---|
438 | }
|
---|
439 |
|
---|
440 | //
|
---|
441 | // There are no top-level (i.e., un-enumerable) hot-plug controllers in QEMU
|
---|
442 | // that would require special initialization.
|
---|
443 | //
|
---|
444 | *HpcCount = 0;
|
---|
445 | *HpcList = NULL;
|
---|
446 | return EFI_SUCCESS;
|
---|
447 | }
|
---|
448 |
|
---|
449 |
|
---|
450 | /**
|
---|
451 | Initializes one root Hot Plug Controller (HPC). This process may causes
|
---|
452 | initialization of its subordinate buses.
|
---|
453 |
|
---|
454 | This function initializes the specified HPC. At the end of initialization,
|
---|
455 | the hot-plug slots or sockets (controlled by this HPC) are powered and are
|
---|
456 | connected to the bus. All the necessary registers in the HPC are set up. For
|
---|
457 | a Standard (PCI) Hot Plug Controller (SHPC), the registers that must be set
|
---|
458 | up are defined in the PCI Standard Hot Plug Controller and Subsystem
|
---|
459 | Specification.
|
---|
460 |
|
---|
461 | @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
|
---|
462 | instance.
|
---|
463 | @param[in] HpcDevicePath The device path to the HPC that is being
|
---|
464 | initialized.
|
---|
465 | @param[in] HpcPciAddress The address of the HPC function on the PCI bus.
|
---|
466 | @param[in] Event The event that should be signaled when the HPC
|
---|
467 | initialization is complete. Set to NULL if the
|
---|
468 | caller wants to wait until the entire
|
---|
469 | initialization process is complete.
|
---|
470 | @param[out] HpcState The state of the HPC hardware. The state is
|
---|
471 | EFI_HPC_STATE_INITIALIZED or
|
---|
472 | EFI_HPC_STATE_ENABLED.
|
---|
473 |
|
---|
474 | @retval EFI_SUCCESS If Event is NULL, the specific HPC was
|
---|
475 | successfully initialized. If Event is not
|
---|
476 | NULL, Event will be signaled at a later time
|
---|
477 | when initialization is complete.
|
---|
478 | @retval EFI_UNSUPPORTED This instance of
|
---|
479 | EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
|
---|
480 | support the specified HPC.
|
---|
481 | @retval EFI_OUT_OF_RESOURCES Initialization failed due to insufficient
|
---|
482 | resources.
|
---|
483 | @retval EFI_INVALID_PARAMETER HpcState is NULL.
|
---|
484 | **/
|
---|
485 | STATIC
|
---|
486 | EFI_STATUS
|
---|
487 | EFIAPI
|
---|
488 | InitializeRootHpc (
|
---|
489 | IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
|
---|
490 | IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
|
---|
491 | IN UINT64 HpcPciAddress,
|
---|
492 | IN EFI_EVENT Event, OPTIONAL
|
---|
493 | OUT EFI_HPC_STATE *HpcState
|
---|
494 | )
|
---|
495 | {
|
---|
496 | //
|
---|
497 | // This function should never be called, due to the information returned by
|
---|
498 | // GetRootHpcList().
|
---|
499 | //
|
---|
500 | ASSERT (FALSE);
|
---|
501 |
|
---|
502 | if (HpcState == NULL) {
|
---|
503 | return EFI_INVALID_PARAMETER;
|
---|
504 | }
|
---|
505 | return EFI_UNSUPPORTED;
|
---|
506 | }
|
---|
507 |
|
---|
508 |
|
---|
509 | /**
|
---|
510 | Returns the resource padding that is required by the PCI bus that is
|
---|
511 | controlled by the specified Hot Plug Controller (HPC).
|
---|
512 |
|
---|
513 | This function returns the resource padding that is required by the PCI bus
|
---|
514 | that is controlled by the specified HPC. This member function is called for
|
---|
515 | all the root HPCs and nonroot HPCs that are detected by the PCI bus
|
---|
516 | enumerator. This function will be called before PCI resource allocation is
|
---|
517 | completed. This function must be called after all the root HPCs, with the
|
---|
518 | possible exception of a PCI-to-CardBus bridge, have completed
|
---|
519 | initialization.
|
---|
520 |
|
---|
521 | @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
|
---|
522 | instance.
|
---|
523 | @param[in] HpcDevicePath The device path to the HPC.
|
---|
524 | @param[in] HpcPciAddress The address of the HPC function on the PCI bus.
|
---|
525 | @param[in] HpcState The state of the HPC hardware.
|
---|
526 | @param[out] Padding The amount of resource padding that is required
|
---|
527 | by the PCI bus under the control of the specified
|
---|
528 | HPC.
|
---|
529 | @param[out] Attributes Describes how padding is accounted for. The
|
---|
530 | padding is returned in the form of ACPI 2.0
|
---|
531 | resource descriptors.
|
---|
532 |
|
---|
533 | @retval EFI_SUCCESS The resource padding was successfully
|
---|
534 | returned.
|
---|
535 | @retval EFI_UNSUPPORTED This instance of the
|
---|
536 | EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
|
---|
537 | support the specified HPC.
|
---|
538 | @retval EFI_NOT_READY This function was called before HPC
|
---|
539 | initialization is complete.
|
---|
540 | @retval EFI_INVALID_PARAMETER HpcState or Padding or Attributes is NULL.
|
---|
541 | @retval EFI_OUT_OF_RESOURCES ACPI 2.0 resource descriptors for Padding
|
---|
542 | cannot be allocated due to insufficient
|
---|
543 | resources.
|
---|
544 | **/
|
---|
545 | STATIC
|
---|
546 | EFI_STATUS
|
---|
547 | EFIAPI
|
---|
548 | GetResourcePadding (
|
---|
549 | IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
|
---|
550 | IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
|
---|
551 | IN UINT64 HpcPciAddress,
|
---|
552 | OUT EFI_HPC_STATE *HpcState,
|
---|
553 | OUT VOID **Padding,
|
---|
554 | OUT EFI_HPC_PADDING_ATTRIBUTES *Attributes
|
---|
555 | )
|
---|
556 | {
|
---|
557 | EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *Address;
|
---|
558 | BOOLEAN DefaultIo;
|
---|
559 | BOOLEAN DefaultMmio;
|
---|
560 | RESOURCE_PADDING ReservationRequest;
|
---|
561 | EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FirstResource;
|
---|
562 | EFI_STATUS ReservationHintStatus;
|
---|
563 | QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION ReservationHint;
|
---|
564 |
|
---|
565 | Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;
|
---|
566 |
|
---|
567 | DEBUG_CODE (
|
---|
568 | CHAR16 *DevicePathString;
|
---|
569 |
|
---|
570 | DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);
|
---|
571 |
|
---|
572 | DEBUG ((EFI_D_VERBOSE, "%a: Address=%02x:%02x.%x DevicePath=%s\n",
|
---|
573 | __FUNCTION__, Address->Bus, Address->Device, Address->Function,
|
---|
574 | (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString));
|
---|
575 |
|
---|
576 | if (DevicePathString != NULL) {
|
---|
577 | FreePool (DevicePathString);
|
---|
578 | }
|
---|
579 | );
|
---|
580 |
|
---|
581 | if (HpcState == NULL || Padding == NULL || Attributes == NULL) {
|
---|
582 | return EFI_INVALID_PARAMETER;
|
---|
583 | }
|
---|
584 |
|
---|
585 | DefaultIo = TRUE;
|
---|
586 | DefaultMmio = TRUE;
|
---|
587 |
|
---|
588 | //
|
---|
589 | // Init ReservationRequest, and point FirstResource one past the last
|
---|
590 | // descriptor entry. We're going to build the entries backwards from
|
---|
591 | // ReservationRequest.EndDesc.
|
---|
592 | //
|
---|
593 | InitializeResourcePadding (&ReservationRequest);
|
---|
594 | FirstResource = ReservationRequest.Padding +
|
---|
595 | ARRAY_SIZE (ReservationRequest.Padding);
|
---|
596 |
|
---|
597 | //
|
---|
598 | // Try to get the QEMU-specific Resource Reservation capability.
|
---|
599 | //
|
---|
600 | ReservationHintStatus = QueryReservationHint (Address, &ReservationHint);
|
---|
601 | if (!EFI_ERROR (ReservationHintStatus)) {
|
---|
602 | INTN HighBit;
|
---|
603 |
|
---|
604 | DEBUG ((
|
---|
605 | DEBUG_VERBOSE,
|
---|
606 | "%a: BusNumbers=0x%x Io=0x%Lx NonPrefetchable32BitMmio=0x%x\n"
|
---|
607 | "%a: Prefetchable32BitMmio=0x%x Prefetchable64BitMmio=0x%Lx\n",
|
---|
608 | __FUNCTION__,
|
---|
609 | ReservationHint.BusNumbers,
|
---|
610 | ReservationHint.Io,
|
---|
611 | ReservationHint.NonPrefetchable32BitMmio,
|
---|
612 | __FUNCTION__,
|
---|
613 | ReservationHint.Prefetchable32BitMmio,
|
---|
614 | ReservationHint.Prefetchable64BitMmio
|
---|
615 | ));
|
---|
616 |
|
---|
617 | //
|
---|
618 | // (a) Reserve bus numbers.
|
---|
619 | //
|
---|
620 | switch (ReservationHint.BusNumbers) {
|
---|
621 | case 0:
|
---|
622 | //
|
---|
623 | // No reservation needed.
|
---|
624 | //
|
---|
625 | break;
|
---|
626 | case MAX_UINT32:
|
---|
627 | //
|
---|
628 | // Firmware default (unspecified). Treat it as "no reservation needed".
|
---|
629 | //
|
---|
630 | break;
|
---|
631 | default:
|
---|
632 | //
|
---|
633 | // Request the specified amount.
|
---|
634 | //
|
---|
635 | --FirstResource;
|
---|
636 | FirstResource->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
|
---|
637 | FirstResource->AddrLen = ReservationHint.BusNumbers;
|
---|
638 | break;
|
---|
639 | }
|
---|
640 |
|
---|
641 | //
|
---|
642 | // (b) Reserve IO space.
|
---|
643 | //
|
---|
644 | switch (ReservationHint.Io) {
|
---|
645 | case 0:
|
---|
646 | //
|
---|
647 | // No reservation needed, disable our built-in.
|
---|
648 | //
|
---|
649 | DefaultIo = FALSE;
|
---|
650 | break;
|
---|
651 | case MAX_UINT64:
|
---|
652 | //
|
---|
653 | // Firmware default (unspecified). Stick with our built-in.
|
---|
654 | //
|
---|
655 | break;
|
---|
656 | default:
|
---|
657 | //
|
---|
658 | // Round the specified amount up to the next power of two. If rounding is
|
---|
659 | // successful, reserve the rounded value. Fall back to the default
|
---|
660 | // otherwise.
|
---|
661 | //
|
---|
662 | HighBit = HighBitSetRoundUp64 (ReservationHint.Io);
|
---|
663 | if (HighBit != -1) {
|
---|
664 | SetIoPadding (--FirstResource, (UINTN)HighBit);
|
---|
665 | DefaultIo = FALSE;
|
---|
666 | }
|
---|
667 | break;
|
---|
668 | }
|
---|
669 |
|
---|
670 | //
|
---|
671 | // (c) Reserve non-prefetchable MMIO space (32-bit only).
|
---|
672 | //
|
---|
673 | switch (ReservationHint.NonPrefetchable32BitMmio) {
|
---|
674 | case 0:
|
---|
675 | //
|
---|
676 | // No reservation needed, disable our built-in.
|
---|
677 | //
|
---|
678 | DefaultMmio = FALSE;
|
---|
679 | break;
|
---|
680 | case MAX_UINT32:
|
---|
681 | //
|
---|
682 | // Firmware default (unspecified). Stick with our built-in.
|
---|
683 | //
|
---|
684 | break;
|
---|
685 | default:
|
---|
686 | //
|
---|
687 | // Round the specified amount up to the next power of two. If rounding is
|
---|
688 | // successful, reserve the rounded value. Fall back to the default
|
---|
689 | // otherwise.
|
---|
690 | //
|
---|
691 | HighBit = HighBitSetRoundUp32 (ReservationHint.NonPrefetchable32BitMmio);
|
---|
692 | if (HighBit != -1) {
|
---|
693 | SetMmioPadding (--FirstResource, FALSE, TRUE, (UINTN)HighBit);
|
---|
694 | DefaultMmio = FALSE;
|
---|
695 | }
|
---|
696 | break;
|
---|
697 | }
|
---|
698 |
|
---|
699 | //
|
---|
700 | // (d) Reserve prefetchable MMIO space (either 32-bit or 64-bit, never
|
---|
701 | // both).
|
---|
702 | //
|
---|
703 | // For either space, we treat 0 as "no reservation needed", and the maximum
|
---|
704 | // value as "firmware default". The latter is unspecified, and we interpret
|
---|
705 | // it as the former.
|
---|
706 | //
|
---|
707 | // Otherwise, round the specified amount up to the next power of two. If
|
---|
708 | // rounding is successful, reserve the rounded value. Do not reserve
|
---|
709 | // prefetchable MMIO space otherwise.
|
---|
710 | //
|
---|
711 | if (ReservationHint.Prefetchable32BitMmio > 0 &&
|
---|
712 | ReservationHint.Prefetchable32BitMmio < MAX_UINT32) {
|
---|
713 | HighBit = HighBitSetRoundUp32 (ReservationHint.Prefetchable32BitMmio);
|
---|
714 | if (HighBit != -1) {
|
---|
715 | SetMmioPadding (--FirstResource, TRUE, TRUE, (UINTN)HighBit);
|
---|
716 | }
|
---|
717 | } else if (ReservationHint.Prefetchable64BitMmio > 0 &&
|
---|
718 | ReservationHint.Prefetchable64BitMmio < MAX_UINT64) {
|
---|
719 | HighBit = HighBitSetRoundUp64 (ReservationHint.Prefetchable64BitMmio);
|
---|
720 | if (HighBit != -1) {
|
---|
721 | SetMmioPadding (--FirstResource, TRUE, FALSE, (UINTN)HighBit);
|
---|
722 | }
|
---|
723 | }
|
---|
724 | }
|
---|
725 |
|
---|
726 | if (DefaultIo) {
|
---|
727 | //
|
---|
728 | // Request defaults.
|
---|
729 | //
|
---|
730 | SetIoPadding (--FirstResource, (UINTN)HighBitSetRoundUp64 (512));
|
---|
731 | }
|
---|
732 |
|
---|
733 | if (DefaultMmio) {
|
---|
734 | //
|
---|
735 | // Request defaults.
|
---|
736 | //
|
---|
737 | SetMmioPadding (
|
---|
738 | --FirstResource,
|
---|
739 | FALSE,
|
---|
740 | TRUE,
|
---|
741 | (UINTN)HighBitSetRoundUp32 (SIZE_2MB)
|
---|
742 | );
|
---|
743 | }
|
---|
744 |
|
---|
745 | //
|
---|
746 | // Output a copy of ReservationRequest from the lowest-address populated
|
---|
747 | // entry until the end of the structure (including
|
---|
748 | // ReservationRequest.EndDesc). If no reservations are necessary, we'll only
|
---|
749 | // output the End Tag.
|
---|
750 | //
|
---|
751 | *Padding = AllocateCopyPool (
|
---|
752 | (UINT8 *)(&ReservationRequest + 1) - (UINT8 *)FirstResource,
|
---|
753 | FirstResource
|
---|
754 | );
|
---|
755 | if (*Padding == NULL) {
|
---|
756 | return EFI_OUT_OF_RESOURCES;
|
---|
757 | }
|
---|
758 |
|
---|
759 | //
|
---|
760 | // Resource padding is required.
|
---|
761 | //
|
---|
762 | *HpcState = EFI_HPC_STATE_INITIALIZED | EFI_HPC_STATE_ENABLED;
|
---|
763 |
|
---|
764 | //
|
---|
765 | // The padding should be applied at PCI bus level, and considered by upstream
|
---|
766 | // bridges, recursively.
|
---|
767 | //
|
---|
768 | *Attributes = EfiPaddingPciBus;
|
---|
769 | return EFI_SUCCESS;
|
---|
770 | }
|
---|
771 |
|
---|
772 |
|
---|
773 | /**
|
---|
774 | Entry point for this driver.
|
---|
775 |
|
---|
776 | @param[in] ImageHandle Image handle of this driver.
|
---|
777 | @param[in] SystemTable Pointer to SystemTable.
|
---|
778 |
|
---|
779 | @retval EFI_SUCESS Driver has loaded successfully.
|
---|
780 | @return Error codes from lower level functions.
|
---|
781 |
|
---|
782 | **/
|
---|
783 | EFI_STATUS
|
---|
784 | EFIAPI
|
---|
785 | DriverInitialize (
|
---|
786 | IN EFI_HANDLE ImageHandle,
|
---|
787 | IN EFI_SYSTEM_TABLE *SystemTable
|
---|
788 | )
|
---|
789 | {
|
---|
790 | EFI_STATUS Status;
|
---|
791 |
|
---|
792 | mPciExtConfSpaceSupported = (PcdGet16 (PcdOvmfHostBridgePciDevId) ==
|
---|
793 | INTEL_Q35_MCH_DEVICE_ID);
|
---|
794 | mPciHotPlugInit.GetRootHpcList = GetRootHpcList;
|
---|
795 | mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;
|
---|
796 | mPciHotPlugInit.GetResourcePadding = GetResourcePadding;
|
---|
797 | Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
|
---|
798 | &gEfiPciHotPlugInitProtocolGuid, &mPciHotPlugInit, NULL);
|
---|
799 | return Status;
|
---|
800 | }
|
---|