TianoCore EDK2 master
Loading...
Searching...
No Matches
PciHotPlugInit.c
Go to the documentation of this file.
1
13
14#include <Library/BaseLib.h>
16#include <Library/DebugLib.h>
19#include <Library/PciCapLib.h>
21#include <Library/PciLib.h>
23
26
27//
28// TRUE if the PCI platform supports extended config space, FALSE otherwise.
29//
30STATIC BOOLEAN mPciExtConfSpaceSupported;
31
32//
33// The protocol interface this driver produces.
34//
35// Refer to 12.6 "PCI Hot Plug PCI Initialization Protocol" in the Platform
36// Init 1.4a Spec, Volume 5.
37//
39
40//
41// Resource padding template for the GetResourcePadding() protocol member
42// function.
43//
44// Refer to Table 8 "ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage" in
45// the Platform Init 1.4a Spec, Volume 5.
46//
47// This structure is interpreted by the ApplyResourcePadding() function in the
48// edk2 PCI Bus UEFI_DRIVER.
49//
50// We can request padding for at most four resource types, each of which is
51// optional, independently of the others:
52// (a) bus numbers,
53// (b) IO space,
54// (c) non-prefetchable MMIO space (32-bit only),
55// (d) prefetchable MMIO space (either 32-bit or 64-bit, never both).
56//
57#pragma pack (1)
58typedef struct {
62#pragma pack ()
63
71VOID
73 OUT RESOURCE_PADDING *ResourcePadding
74 )
75{
76 UINTN Index;
77
78 ZeroMem (ResourcePadding, sizeof *ResourcePadding);
79
80 //
81 // Fill in the Padding fields that don't vary across resource types.
82 //
83 for (Index = 0; Index < ARRAY_SIZE (ResourcePadding->Padding); ++Index) {
85
86 Descriptor = ResourcePadding->Padding + Index;
87 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
88 Descriptor->Len = (UINT16)(
90 OFFSET_OF (
92 ResType
93 )
94 );
95 }
96
97 //
98 // Fill in the End Tag.
99 //
100 ResourcePadding->EndDesc.Desc = ACPI_END_TAG_DESCRIPTOR;
101}
102
113STATIC
114VOID
117 IN UINTN SizeExponent
118 )
119{
120 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
121 Descriptor->AddrLen = LShiftU64 (1, SizeExponent);
122 Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;
123}
124
147STATIC
148VOID
151 IN BOOLEAN Prefetchable,
152 IN BOOLEAN ThirtyTwoBitOnly,
153 IN UINTN SizeExponent
154 )
155{
156 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
157 if (Prefetchable) {
158 Descriptor->SpecificFlag =
159 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
160 Descriptor->AddrSpaceGranularity = ThirtyTwoBitOnly ? 32 : 64;
161 } else {
162 Descriptor->SpecificFlag =
163 EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_NON_CACHEABLE;
164 Descriptor->AddrSpaceGranularity = 32;
165 }
166
167 Descriptor->AddrLen = LShiftU64 (1, SizeExponent);
168 Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;
169}
170
185STATIC
186INTN
188 IN UINT32 Operand
189 )
190{
191 INTN HighBit;
192
193 HighBit = HighBitSet32 (Operand);
194 if (HighBit == -1) {
195 //
196 // Operand is zero.
197 //
198 return HighBit;
199 }
200
201 if ((Operand & (Operand - 1)) != 0) {
202 //
203 // Operand is not a whole power of two.
204 //
205 ++HighBit;
206 }
207
208 return (HighBit < 32) ? HighBit : -1;
209}
210
225STATIC
226INTN
228 IN UINT64 Operand
229 )
230{
231 INTN HighBit;
232
233 HighBit = HighBitSet64 (Operand);
234 if (HighBit == -1) {
235 //
236 // Operand is zero.
237 //
238 return HighBit;
239 }
240
241 if ((Operand & (Operand - 1)) != 0) {
242 //
243 // Operand is not a whole power of two.
244 //
245 ++HighBit;
246 }
247
248 return (HighBit < 64) ? HighBit : -1;
249}
250
270STATIC
275 )
276{
277 UINT16 PciVendorId;
278 EFI_STATUS Status;
279 PCI_CAP_DEV *PciDevice;
280 PCI_CAP_LIST *CapList;
281 UINT16 VendorInstance;
282 PCI_CAP *VendorCap;
283
284 //
285 // Check the vendor identifier.
286 //
287 PciVendorId = PciRead16 (
289 HpcPciAddress->Bus,
290 HpcPciAddress->Device,
291 HpcPciAddress->Function,
292 PCI_VENDOR_ID_OFFSET
293 )
294 );
295 if (PciVendorId != QEMU_PCI_BRIDGE_VENDOR_ID_REDHAT) {
296 return EFI_NOT_FOUND;
297 }
298
299 //
300 // Parse the capabilities lists.
301 //
303 mPciExtConfSpaceSupported ? PciCapExtended : PciCapNormal,
304 0, // Segment
305 HpcPciAddress->Bus,
306 HpcPciAddress->Device,
307 HpcPciAddress->Function,
308 &PciDevice
309 );
310 if (EFI_ERROR (Status)) {
311 return Status;
312 }
313
314 Status = PciCapListInit (PciDevice, &CapList);
315 if (EFI_ERROR (Status)) {
316 goto UninitPciDevice;
317 }
318
319 //
320 // Scan the vendor capability instances for the Resource Reservation
321 // capability.
322 //
323 VendorInstance = 0;
324 for ( ; ;) {
325 UINT8 VendorLength;
326 UINT8 BridgeCapType;
327
328 Status = PciCapListFindCap (
329 CapList,
330 PciCapNormal,
331 EFI_PCI_CAPABILITY_ID_VENDOR,
332 VendorInstance++,
333 &VendorCap
334 );
335 if (EFI_ERROR (Status)) {
336 goto UninitCapList;
337 }
338
339 //
340 // Check the vendor capability length.
341 //
342 Status = PciCapRead (
343 PciDevice,
344 VendorCap,
346 &VendorLength,
347 sizeof VendorLength
348 );
349 if (EFI_ERROR (Status)) {
350 goto UninitCapList;
351 }
352
353 if (VendorLength != sizeof *ReservationHint) {
354 continue;
355 }
356
357 //
358 // Check the vendor bridge capability type.
359 //
360 Status = PciCapRead (
361 PciDevice,
362 VendorCap,
364 &BridgeCapType,
365 sizeof BridgeCapType
366 );
367 if (EFI_ERROR (Status)) {
368 goto UninitCapList;
369 }
370
371 if (BridgeCapType ==
372 QEMU_PCI_BRIDGE_CAPABILITY_TYPE_RESOURCE_RESERVATION)
373 {
374 //
375 // We have a match.
376 //
377 break;
378 }
379 }
380
381 //
382 // Populate ReservationHint.
383 //
384 Status = PciCapRead (
385 PciDevice,
386 VendorCap,
387 0, // SourceOffsetInCap
388 ReservationHint,
389 sizeof *ReservationHint
390 );
391
392UninitCapList:
393 PciCapListUninit (CapList);
394
395UninitPciDevice:
397
398 return Status;
399}
400
427STATIC
429EFIAPI
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
484STATIC
486EFIAPI
489 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
490 IN UINT64 HpcPciAddress,
491 IN EFI_EVENT Event OPTIONAL,
492 OUT EFI_HPC_STATE *HpcState
493 )
494{
495 //
496 // This function should never be called, due to the information returned by
497 // GetRootHpcList().
498 //
499 ASSERT (FALSE);
500
501 if (HpcState == NULL) {
502 return EFI_INVALID_PARAMETER;
503 }
504
505 return EFI_UNSUPPORTED;
506}
507
544STATIC
546EFIAPI
549 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
550 IN UINT64 HpcPciAddress,
551 OUT EFI_HPC_STATE *HpcState,
552 OUT VOID **Padding,
554 )
555{
557 BOOLEAN DefaultIo;
558 BOOLEAN DefaultMmio;
559 BOOLEAN DefaultPrefMmio;
560 RESOURCE_PADDING ReservationRequest;
562 EFI_STATUS ReservationHintStatus;
564
565 Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;
566
568 CHAR16 *DevicePathString;
569
570 DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);
571
572 DEBUG ((
573 DEBUG_VERBOSE,
574 "%a: Address=%02x:%02x.%x DevicePath=%s\n",
575 __func__,
576 Address->Bus,
577 Address->Device,
578 Address->Function,
579 (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString
580 ));
581
582 if (DevicePathString != NULL) {
583 FreePool (DevicePathString);
584 }
585
587
588 if ((HpcState == NULL) || (Padding == NULL) || (Attributes == NULL)) {
589 return EFI_INVALID_PARAMETER;
590 }
591
592 DefaultIo = FALSE;
593 DefaultMmio = TRUE;
594 DefaultPrefMmio = TRUE;
595
596 //
597 // Init ReservationRequest, and point FirstResource one past the last
598 // descriptor entry. We're going to build the entries backwards from
599 // ReservationRequest.EndDesc.
600 //
601 InitializeResourcePadding (&ReservationRequest);
602 FirstResource = ReservationRequest.Padding +
603 ARRAY_SIZE (ReservationRequest.Padding);
604
605 //
606 // Try to get the QEMU-specific Resource Reservation capability.
607 //
608 ReservationHintStatus = QueryReservationHint (Address, &ReservationHint);
609 if (!EFI_ERROR (ReservationHintStatus)) {
610 INTN HighBit;
611
612 DEBUG ((
613 DEBUG_VERBOSE,
614 "%a: BusNumbers=0x%x Io=0x%Lx NonPrefetchable32BitMmio=0x%x\n"
615 "%a: Prefetchable32BitMmio=0x%x Prefetchable64BitMmio=0x%Lx\n",
616 __func__,
617 ReservationHint.BusNumbers,
618 ReservationHint.Io,
619 ReservationHint.NonPrefetchable32BitMmio,
620 __func__,
621 ReservationHint.Prefetchable32BitMmio,
622 ReservationHint.Prefetchable64BitMmio
623 ));
624
625 //
626 // (a) Reserve bus numbers.
627 //
628 switch (ReservationHint.BusNumbers) {
629 case 0:
630 //
631 // No reservation needed.
632 //
633 break;
634 case MAX_UINT32:
635 //
636 // Firmware default (unspecified). Treat it as "no reservation needed".
637 //
638 break;
639 default:
640 //
641 // Request the specified amount.
642 //
643 --FirstResource;
644 FirstResource->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
645 FirstResource->AddrLen = ReservationHint.BusNumbers;
646 break;
647 }
648
649 //
650 // (b) Reserve IO space.
651 //
652 switch (ReservationHint.Io) {
653 case 0:
654 //
655 // No reservation needed, disable our built-in.
656 //
657 DefaultIo = FALSE;
658 break;
659 case MAX_UINT64:
660 //
661 // Firmware default (unspecified). Stick with our built-in.
662 //
663 break;
664 default:
665 //
666 // Round the specified amount up to the next power of two. If rounding is
667 // successful, reserve the rounded value. Fall back to the default
668 // otherwise.
669 //
670 HighBit = HighBitSetRoundUp64 (ReservationHint.Io);
671 if (HighBit != -1) {
672 SetIoPadding (--FirstResource, (UINTN)HighBit);
673 DefaultIo = FALSE;
674 }
675
676 break;
677 }
678
679 //
680 // (c) Reserve non-prefetchable MMIO space (32-bit only).
681 //
682 switch (ReservationHint.NonPrefetchable32BitMmio) {
683 case 0:
684 //
685 // No reservation needed, disable our built-in.
686 //
687 DefaultMmio = FALSE;
688 break;
689 case MAX_UINT32:
690 //
691 // Firmware default (unspecified). Stick with our built-in.
692 //
693 break;
694 default:
695 //
696 // Round the specified amount up to the next power of two. If rounding is
697 // successful, reserve the rounded value. Fall back to the default
698 // otherwise.
699 //
700 HighBit = HighBitSetRoundUp32 (ReservationHint.NonPrefetchable32BitMmio);
701 if (HighBit != -1) {
702 SetMmioPadding (--FirstResource, FALSE, TRUE, (UINTN)HighBit);
703 DefaultMmio = FALSE;
704 }
705
706 break;
707 }
708
709 //
710 // (d) Reserve prefetchable MMIO space (either 32-bit or 64-bit, never
711 // both).
712 //
713 // For either space, we treat 0 as "no reservation needed", and the maximum
714 // value as "firmware default". The latter is unspecified, and we interpret
715 // it as the former.
716 //
717 // Otherwise, round the specified amount up to the next power of two. If
718 // rounding is successful, reserve the rounded value. Do not reserve
719 // prefetchable MMIO space otherwise.
720 //
721 if ((ReservationHint.Prefetchable32BitMmio > 0) &&
722 (ReservationHint.Prefetchable32BitMmio < MAX_UINT32))
723 {
724 HighBit = HighBitSetRoundUp32 (ReservationHint.Prefetchable32BitMmio);
725 if (HighBit != -1) {
726 SetMmioPadding (--FirstResource, TRUE, TRUE, (UINTN)HighBit);
727 DefaultPrefMmio = FALSE;
728 }
729 } else if ((ReservationHint.Prefetchable64BitMmio > 0) &&
730 (ReservationHint.Prefetchable64BitMmio < MAX_UINT64))
731 {
732 HighBit = HighBitSetRoundUp64 (ReservationHint.Prefetchable64BitMmio);
733 if (HighBit != -1) {
734 SetMmioPadding (--FirstResource, TRUE, FALSE, (UINTN)HighBit);
735 DefaultPrefMmio = FALSE;
736 }
737 }
738 }
739
740 if (DefaultIo) {
741 //
742 // Request defaults.
743 //
744 SetIoPadding (--FirstResource, (UINTN)HighBitSetRoundUp64 (0x1000));
745 }
746
747 if (DefaultMmio) {
748 //
749 // Request defaults.
750 //
752 --FirstResource,
753 FALSE,
754 TRUE,
755 (UINTN)HighBitSetRoundUp32 (SIZE_2MB)
756 );
757 }
758
759 if (DefaultPrefMmio) {
760 UINT64 Pci64Size = PcdGet64 (PcdPciMmio64Size);
761
762 if (Pci64Size > SIZE_32GB) {
764 --FirstResource,
765 TRUE,
766 FALSE,
767 (UINTN)HighBitSetRoundUp64 (RShiftU64 (Pci64Size, 8))
768 );
769 }
770 }
771
772 //
773 // Output a copy of ReservationRequest from the lowest-address populated
774 // entry until the end of the structure (including
775 // ReservationRequest.EndDesc). If no reservations are necessary, we'll only
776 // output the End Tag.
777 //
778 *Padding = AllocateCopyPool (
779 (UINT8 *)(&ReservationRequest + 1) - (UINT8 *)FirstResource,
780 FirstResource
781 );
782 if (*Padding == NULL) {
783 return EFI_OUT_OF_RESOURCES;
784 }
785
786 //
787 // Resource padding is required.
788 //
790
791 //
792 // The padding should be applied at PCI bus level, and considered by upstream
793 // bridges, recursively.
794 //
795 *Attributes = EfiPaddingPciBus;
796 return EFI_SUCCESS;
797}
798
810EFIAPI
812 IN EFI_HANDLE ImageHandle,
813 IN EFI_SYSTEM_TABLE *SystemTable
814 )
815{
816 EFI_STATUS Status;
817
818 mPciExtConfSpaceSupported = (PcdGet16 (PcdOvmfHostBridgePciDevId) ==
819 INTEL_Q35_MCH_DEVICE_ID);
820 mPciHotPlugInit.GetRootHpcList = GetRootHpcList;
821 mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;
822 mPciHotPlugInit.GetResourcePadding = GetResourcePadding;
823 Status = gBS->InstallMultipleProtocolInterfaces (
824 &ImageHandle,
825 &gEfiPciHotPlugInitProtocolGuid,
826 &mPciHotPlugInit,
827 NULL
828 );
829 return Status;
830}
UINT64 UINTN
INT64 INTN
PACKED struct @89 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: RShiftU64.c:28
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
INTN EFIAPI HighBitSet64(IN UINT64 Operand)
Definition: HighBitSet64.c:27
INTN EFIAPI HighBitSet32(IN UINT32 Operand)
Definition: HighBitSet32.c:27
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
CHAR16 *EFIAPI ConvertDevicePathToText(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN BOOLEAN DisplayOnly, IN BOOLEAN AllowShortcuts)
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID *EFIAPI AllocateCopyPool(IN UINTN AllocationSize, IN CONST VOID *Buffer)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
#define DEBUG_CODE_BEGIN()
Definition: DebugLib.h:564
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define DEBUG_CODE_END()
Definition: DebugLib.h:578
#define PCI_LIB_ADDRESS(Bus, Device, Function, Register)
Definition: PciLib.h:34
UINT16 EFIAPI PciRead16(IN UINTN Address)
Definition: PciLib.c:396
#define PcdGet16(TokenName)
Definition: PcdLib.h:349
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
VOID EFIAPI PciCapListUninit(IN PCI_CAP_LIST *CapList)
RETURN_STATUS EFIAPI PciCapListInit(IN PCI_CAP_DEV *PciDevice, OUT PCI_CAP_LIST **CapList)
RETURN_STATUS EFIAPI PciCapRead(IN PCI_CAP_DEV *PciDevice, IN PCI_CAP *Cap, IN UINT16 SourceOffsetInCap, OUT VOID *DestinationBuffer, IN UINT16 Size)
RETURN_STATUS EFIAPI PciCapListFindCap(IN PCI_CAP_LIST *CapList, IN PCI_CAP_DOMAIN Domain, IN UINT16 CapId, IN UINT16 Instance, OUT PCI_CAP **Cap OPTIONAL)
VOID EFIAPI PciCapPciSegmentDeviceUninit(IN PCI_CAP_DEV *PciDevice)
RETURN_STATUS EFIAPI PciCapPciSegmentDeviceInit(IN PCI_CAP_DOMAIN MaxDomain, IN UINT16 Segment, IN UINT8 Bus, IN UINT8 Device, IN UINT8 Function, OUT PCI_CAP_DEV **PciDevice)
STATIC INTN HighBitSetRoundUp64(IN UINT64 Operand)
STATIC EFI_STATUS EFIAPI InitializeRootHpc(IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This, IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath, IN UINT64 HpcPciAddress, IN EFI_EVENT Event OPTIONAL, OUT EFI_HPC_STATE *HpcState)
STATIC VOID SetIoPadding(IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor, IN UINTN SizeExponent)
EFI_STATUS EFIAPI DriverInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
STATIC EFI_STATUS QueryReservationHint(IN CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *HpcPciAddress, OUT QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION *ReservationHint)
STATIC INTN HighBitSetRoundUp32(IN UINT32 Operand)
STATIC VOID SetMmioPadding(IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor, IN BOOLEAN Prefetchable, IN BOOLEAN ThirtyTwoBitOnly, IN UINTN SizeExponent)
STATIC VOID InitializeResourcePadding(OUT RESOURCE_PADDING *ResourcePadding)
STATIC EFI_STATUS EFIAPI GetRootHpcList(IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This, OUT UINTN *HpcCount, OUT EFI_HPC_LOCATION **HpcList)
STATIC EFI_STATUS EFIAPI GetResourcePadding(IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This, IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath, IN UINT64 HpcPciAddress, OUT EFI_HPC_STATE *HpcState, OUT VOID **Padding, OUT EFI_HPC_PADDING_ATTRIBUTES *Attributes)
#define EFI_HPC_STATE_ENABLED
EFI_HPC_PADDING_ATTRIBUTES
@ EfiPaddingPciBus
UINT16 EFI_HPC_STATE
#define EFI_HPC_STATE_INITIALIZED
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_INITIALIZE_ROOT_HPC InitializeRootHpc
EFI_GET_ROOT_HPC_LIST GetRootHpcList
EFI_GET_HOT_PLUG_PADDING GetResourcePadding