]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiSsdtPcieLibArm / SsdtPcieGenerator.c
1 /** @file
2 SSDT Pcie Table Generator.
3
4 Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 @par Reference(s):
9 - PCI Firmware Specification - Revision 3.0
10 - ACPI 6.4 specification:
11 - s6.2.13 "_PRT (PCI Routing Table)"
12 - s6.1.1 "_ADR (Address)"
13 - linux kernel code
14 - Arm Base Boot Requirements v1.0
15 - Arm Base System Architecture v1.0
16 **/
17
18 #include <Library/AcpiLib.h>
19 #include <Library/BaseLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Protocol/AcpiTable.h>
24
25 // Module specific include files.
26 #include <AcpiTableGenerator.h>
27 #include <ConfigurationManagerObject.h>
28 #include <ConfigurationManagerHelper.h>
29 #include <Library/AcpiHelperLib.h>
30 #include <Library/TableHelperLib.h>
31 #include <Library/AmlLib/AmlLib.h>
32 #include <Library/SsdtPcieSupportLib.h>
33 #include <Protocol/ConfigurationManagerProtocol.h>
34
35 #include "SsdtPcieGenerator.h"
36
37 #define PCI_MAX_DEVICE_COUNT_PER_BUS 32
38 #define PCI_MAX_FUNCTION_COUNT_PER_DEVICE 8
39
40 /** ARM standard SSDT Pcie Table Generator.
41
42 Requirements:
43 The following Configuration Manager Object(s) are required by
44 this Generator:
45 - EArmObjCmRef
46 - EArmObjPciConfigSpaceInfo
47 - EArmObjPciAddressMapInfo
48 - EArmObjPciInterruptMapInfo
49 */
50
51 /** This macro expands to a function that retrieves the cross-CM-object-
52 reference information from the Configuration Manager.
53 */
54 GET_OBJECT_LIST (
55 EObjNameSpaceArm,
56 EArmObjCmRef,
57 CM_ARM_OBJ_REF
58 );
59
60 /** This macro expands to a function that retrieves the Pci
61 Configuration Space Information from the Configuration Manager.
62 */
63 GET_OBJECT_LIST (
64 EObjNameSpaceArm,
65 EArmObjPciConfigSpaceInfo,
66 CM_ARM_PCI_CONFIG_SPACE_INFO
67 );
68
69 /** This macro expands to a function that retrieves the Pci
70 Address Mapping Information from the Configuration Manager.
71 */
72 GET_OBJECT_LIST (
73 EObjNameSpaceArm,
74 EArmObjPciAddressMapInfo,
75 CM_ARM_PCI_ADDRESS_MAP_INFO
76 );
77
78 /** This macro expands to a function that retrieves the Pci
79 Interrupt Mapping Information from the Configuration Manager.
80 */
81 GET_OBJECT_LIST (
82 EObjNameSpaceArm,
83 EArmObjPciInterruptMapInfo,
84 CM_ARM_PCI_INTERRUPT_MAP_INFO
85 );
86
87 /** Initialize the MappingTable.
88
89 @param [in] MappingTable The mapping table structure.
90 @param [in] Count Number of entries to allocate in the
91 MappingTable.
92
93 @retval EFI_SUCCESS Success.
94 @retval EFI_INVALID_PARAMETER Invalid parameter.
95 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
96 **/
97 STATIC
98 EFI_STATUS
99 EFIAPI
100 MappingTableInitialize (
101 IN MAPPING_TABLE *MappingTable,
102 IN UINT32 Count
103 )
104 {
105 UINT32 *Table;
106
107 if ((MappingTable == NULL) ||
108 (Count == 0))
109 {
110 ASSERT (0);
111 return EFI_INVALID_PARAMETER;
112 }
113
114 Table = AllocateZeroPool (sizeof (*Table) * Count);
115 if (Table == NULL) {
116 ASSERT (0);
117 return EFI_OUT_OF_RESOURCES;
118 }
119
120 MappingTable->Table = Table;
121 MappingTable->LastIndex = 0;
122 MappingTable->MaxIndex = Count;
123
124 return EFI_SUCCESS;
125 }
126
127 /** Free the MappingTable.
128
129 @param [in, out] MappingTable The mapping table structure.
130 **/
131 STATIC
132 VOID
133 EFIAPI
134 MappingTableFree (
135 IN OUT MAPPING_TABLE *MappingTable
136 )
137 {
138 ASSERT (MappingTable != NULL);
139 ASSERT (MappingTable->Table != NULL);
140
141 if (MappingTable->Table != NULL) {
142 FreePool (MappingTable->Table);
143 }
144 }
145
146 /** Add a new entry to the MappingTable and return its index.
147
148 If an entry with [Integer] is already available in the table,
149 return its index without adding a new entry.
150
151 @param [in] MappingTable The mapping table structure.
152 @param [in] Integer New Integer entry to add.
153
154 @retval The index of the Integer entry in the MappingTable.
155 **/
156 STATIC
157 UINT32
158 EFIAPI
159 MappingTableAdd (
160 IN MAPPING_TABLE *MappingTable,
161 IN UINT32 Integer
162 )
163 {
164 UINT32 *Table;
165 UINT32 Index;
166 UINT32 LastIndex;
167
168 ASSERT (MappingTable != NULL);
169 ASSERT (MappingTable->Table != NULL);
170
171 Table = MappingTable->Table;
172 LastIndex = MappingTable->LastIndex;
173
174 // Search if there is already an entry with this Integer.
175 for (Index = 0; Index < LastIndex; Index++) {
176 if (Table[Index] == Integer) {
177 return Index;
178 }
179 }
180
181 ASSERT (LastIndex < MappingTable->MaxIndex);
182
183 // If no, create a new entry.
184 Table[LastIndex] = Integer;
185
186 return MappingTable->LastIndex++;
187 }
188
189 /** Generate required Pci device information.
190
191 ASL code:
192 Name (_UID, <Uid>) // Uid of the Pci device
193 Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge
194 Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge
195 Name (_SEG, <Pci segment group>) // PCI Segment Group number
196 Name (_BBN, <Bus number>) // PCI Base Bus Number
197 Name (_CCA, 1) // Initially mark the PCI coherent
198
199 @param [in] PciInfo Pci device information.
200 @param [in] Uid Unique Id of the Pci device.
201 @param [in, out] PciNode Pci node to amend.
202
203 @retval EFI_SUCCESS Success.
204 @retval EFI_INVALID_PARAMETER Invalid parameter.
205 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
206 **/
207 STATIC
208 EFI_STATUS
209 EFIAPI
210 GeneratePciDeviceInfo (
211 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
212 IN UINT32 Uid,
213 IN OUT AML_OBJECT_NODE_HANDLE PciNode
214 )
215 {
216 EFI_STATUS Status;
217 UINT32 EisaId;
218
219 ASSERT (PciInfo != NULL);
220 ASSERT (PciNode != NULL);
221
222 // ASL: Name (_UID, <Uid>)
223 Status = AmlCodeGenNameInteger ("_UID", Uid, PciNode, NULL);
224 if (EFI_ERROR (Status)) {
225 ASSERT (0);
226 return Status;
227 }
228
229 // ASL: Name (_HID, EISAID ("PNP0A08"))
230 Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId);
231 if (EFI_ERROR (Status)) {
232 ASSERT (0);
233 return Status;
234 }
235
236 Status = AmlCodeGenNameInteger ("_HID", EisaId, PciNode, NULL);
237 if (EFI_ERROR (Status)) {
238 ASSERT (0);
239 return Status;
240 }
241
242 // ASL: Name (_CID, EISAID ("PNP0A03"))
243 Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId);
244 if (EFI_ERROR (Status)) {
245 ASSERT (0);
246 return Status;
247 }
248
249 Status = AmlCodeGenNameInteger ("_CID", EisaId, PciNode, NULL);
250 if (EFI_ERROR (Status)) {
251 ASSERT (0);
252 return Status;
253 }
254
255 // ASL: Name (_SEG, <Pci segment group>)
256 Status = AmlCodeGenNameInteger (
257 "_SEG",
258 PciInfo->PciSegmentGroupNumber,
259 PciNode,
260 NULL
261 );
262 if (EFI_ERROR (Status)) {
263 ASSERT (0);
264 return Status;
265 }
266
267 // ASL: Name (_BBN, <Bus number>)
268 Status = AmlCodeGenNameInteger (
269 "_BBN",
270 PciInfo->StartBusNumber,
271 PciNode,
272 NULL
273 );
274 if (EFI_ERROR (Status)) {
275 ASSERT (0);
276 return Status;
277 }
278
279 // ASL: Name (_CCA, 1)
280 // Must be aligned with the IORT CCA property in
281 // "Table 14 Memory access properties"
282 Status = AmlCodeGenNameInteger ("_CCA", 1, PciNode, NULL);
283 ASSERT_EFI_ERROR (Status);
284 return Status;
285 }
286
287 /** Generate a _PRT object (Pci Routing Table) for the Pci device.
288
289 Cf. ACPI 6.4 specification, s6.2.13 "_PRT (PCI Routing Table)"
290
291 @param [in] Generator The SSDT Pci generator.
292 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
293 Protocol interface.
294 @param [in] PciInfo Pci device information.
295 @param [in] Uid Unique Id of the Pci device.
296 @param [in, out] PciNode Pci node to amend.
297
298 @retval EFI_SUCCESS The function completed successfully.
299 @retval EFI_INVALID_PARAMETER Invalid parameter.
300 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
301 **/
302 STATIC
303 EFI_STATUS
304 EFIAPI
305 GeneratePrt (
306 IN ACPI_PCI_GENERATOR *Generator,
307 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
308 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
309 IN UINT32 Uid,
310 IN OUT AML_OBJECT_NODE_HANDLE PciNode
311 )
312 {
313 EFI_STATUS Status;
314 INT32 Index;
315 AML_OBJECT_NODE_HANDLE PrtNode;
316 CM_ARM_OBJ_REF *RefInfo;
317 UINT32 RefCount;
318 CM_ARM_PCI_INTERRUPT_MAP_INFO *IrqMapInfo;
319
320 ASSERT (Generator != NULL);
321 ASSERT (CfgMgrProtocol != NULL);
322 ASSERT (PciInfo != NULL);
323 ASSERT (PciNode != NULL);
324
325 PrtNode = NULL;
326
327 // Get the array of CM_ARM_OBJ_REF referencing the
328 // CM_ARM_PCI_INTERRUPT_MAP_INFO objects.
329 Status = GetEArmObjCmRef (
330 CfgMgrProtocol,
331 PciInfo->InterruptMapToken,
332 &RefInfo,
333 &RefCount
334 );
335 if (EFI_ERROR (Status)) {
336 ASSERT (0);
337 return Status;
338 }
339
340 // Initialized DeviceTable.
341 Status = MappingTableInitialize (&Generator->DeviceTable, RefCount);
342 if (EFI_ERROR (Status)) {
343 ASSERT (0);
344 goto exit_handler0;
345 }
346
347 // ASL: Name (_PRT, Package () {})
348 Status = AmlCodeGenNamePackage ("_PRT", NULL, &PrtNode);
349 if (EFI_ERROR (Status)) {
350 ASSERT (0);
351 goto exit_handler;
352 }
353
354 for (Index = 0; Index < RefCount; Index++) {
355 // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.
356 Status = GetEArmObjPciInterruptMapInfo (
357 CfgMgrProtocol,
358 RefInfo[Index].ReferenceToken,
359 &IrqMapInfo,
360 NULL
361 );
362 if (EFI_ERROR (Status)) {
363 ASSERT (0);
364 goto exit_handler;
365 }
366
367 // Check that the interrupts flags are SPIs, level high.
368 // Cf. Arm BSA v1.0, sE.6 "Legacy interrupts"
369 if ((Index > 0) &&
370 (IrqMapInfo->IntcInterrupt.Interrupt >= 32) &&
371 (IrqMapInfo->IntcInterrupt.Interrupt < 1020) &&
372 ((IrqMapInfo->IntcInterrupt.Flags & 0xB) != 0))
373 {
374 Status = EFI_INVALID_PARAMETER;
375 ASSERT_EFI_ERROR (Status);
376 goto exit_handler;
377 }
378
379 // Add the device to the DeviceTable.
380 MappingTableAdd (&Generator->DeviceTable, IrqMapInfo->PciDevice);
381
382 /* Add a _PRT entry.
383 ASL
384 Name (_PRT, Package () {
385 <OldPrtEntries>,
386 <NewPrtEntry>
387 })
388
389 Address is set as:
390 ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
391 High word-Device #, Low word-Function #. (for example, device 3,
392 function 2 is 0x00030002). To refer to all the functions on a device #,
393 use a function number of FFFF).
394
395 Use the second model for _PRT object and describe a hardwired interrupt.
396 */
397 Status = AmlAddPrtEntry (
398 (IrqMapInfo->PciDevice << 16) | 0xFFFF,
399 IrqMapInfo->PciInterrupt,
400 NULL,
401 IrqMapInfo->IntcInterrupt.Interrupt,
402 PrtNode
403 );
404 if (EFI_ERROR (Status)) {
405 ASSERT (0);
406 goto exit_handler;
407 }
408 } // for
409
410 // Attach the _PRT entry.
411 Status = AmlAttachNode (PciNode, PrtNode);
412 if (EFI_ERROR (Status)) {
413 ASSERT_EFI_ERROR (Status);
414 goto exit_handler;
415 }
416
417 PrtNode = NULL;
418
419 // Generate the Pci slots once all the device have been added.
420 Status = GeneratePciSlots (PciInfo, &Generator->DeviceTable, Uid, PciNode);
421 if (EFI_ERROR (Status)) {
422 ASSERT (0);
423 goto exit_handler;
424 }
425
426 exit_handler:
427 MappingTableFree (&Generator->DeviceTable);
428 exit_handler0:
429 if (PrtNode != NULL) {
430 AmlDeleteTree (PrtNode);
431 }
432
433 return Status;
434 }
435
436 /** Generate a _CRS method for the Pci device.
437
438 @param [in] Generator The SSDT Pci generator.
439 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
440 Protocol interface.
441 @param [in] PciInfo Pci device information.
442 @param [in, out] PciNode Pci node to amend.
443
444 @retval EFI_SUCCESS The function completed successfully.
445 @retval EFI_INVALID_PARAMETER Invalid parameter.
446 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
447 **/
448 STATIC
449 EFI_STATUS
450 EFIAPI
451 GeneratePciCrs (
452 IN ACPI_PCI_GENERATOR *Generator,
453 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
454 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
455 IN OUT AML_OBJECT_NODE_HANDLE PciNode
456 )
457 {
458 EFI_STATUS Status;
459 BOOLEAN Translation;
460 UINT32 Index;
461 CM_ARM_OBJ_REF *RefInfo;
462 UINT32 RefCount;
463 CM_ARM_PCI_ADDRESS_MAP_INFO *AddrMapInfo;
464 AML_OBJECT_NODE_HANDLE CrsNode;
465 BOOLEAN IsPosDecode;
466
467 ASSERT (Generator != NULL);
468 ASSERT (CfgMgrProtocol != NULL);
469 ASSERT (PciInfo != NULL);
470 ASSERT (PciNode != NULL);
471
472 // ASL: Name (_CRS, ResourceTemplate () {})
473 Status = AmlCodeGenNameResourceTemplate ("_CRS", PciNode, &CrsNode);
474 if (EFI_ERROR (Status)) {
475 ASSERT (0);
476 return Status;
477 }
478
479 // ASL:
480 // WordBusNumber ( // Bus numbers assigned to this root
481 // ResourceProducer, MinFixed, MaxFixed, PosDecode,
482 // 0, // AddressGranularity
483 // <Start>, // AddressMinimum - Minimum Bus Number
484 // <End>, // AddressMaximum - Maximum Bus Number
485 // 0, // AddressTranslation - Set to 0
486 // <End> - <Start> + 1 // RangeLength - Number of Busses
487 // )
488 Status = AmlCodeGenRdWordBusNumber (
489 FALSE,
490 TRUE,
491 TRUE,
492 TRUE,
493 0,
494 PciInfo->StartBusNumber,
495 PciInfo->EndBusNumber,
496 0,
497 PciInfo->EndBusNumber - PciInfo->StartBusNumber + 1,
498 0,
499 NULL,
500 CrsNode,
501 NULL
502 );
503 if (EFI_ERROR (Status)) {
504 ASSERT (0);
505 return Status;
506 }
507
508 // Get the array of CM_ARM_OBJ_REF referencing the
509 // CM_ARM_PCI_ADDRESS_MAP_INFO objects.
510 Status = GetEArmObjCmRef (
511 CfgMgrProtocol,
512 PciInfo->AddressMapToken,
513 &RefInfo,
514 &RefCount
515 );
516 if (EFI_ERROR (Status)) {
517 ASSERT (0);
518 return Status;
519 }
520
521 for (Index = 0; Index < RefCount; Index++) {
522 // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one.
523 Status = GetEArmObjPciAddressMapInfo (
524 CfgMgrProtocol,
525 RefInfo[Index].ReferenceToken,
526 &AddrMapInfo,
527 NULL
528 );
529 if (EFI_ERROR (Status)) {
530 ASSERT (0);
531 return Status;
532 }
533
534 Translation = (AddrMapInfo->CpuAddress != AddrMapInfo->PciAddress);
535 if (AddrMapInfo->CpuAddress >= AddrMapInfo->PciAddress) {
536 IsPosDecode = TRUE;
537 } else {
538 IsPosDecode = FALSE;
539 }
540
541 switch (AddrMapInfo->SpaceCode) {
542 case PCI_SS_IO:
543 Status = AmlCodeGenRdDWordIo (
544 FALSE,
545 TRUE,
546 TRUE,
547 IsPosDecode,
548 3,
549 0,
550 AddrMapInfo->PciAddress,
551 AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
552 Translation ? AddrMapInfo->CpuAddress - AddrMapInfo->PciAddress : 0,
553 AddrMapInfo->AddressSize,
554 0,
555 NULL,
556 TRUE,
557 FALSE,
558 CrsNode,
559 NULL
560 );
561 break;
562
563 case PCI_SS_M32:
564 Status = AmlCodeGenRdDWordMemory (
565 FALSE,
566 IsPosDecode,
567 TRUE,
568 TRUE,
569 TRUE,
570 TRUE,
571 0,
572 AddrMapInfo->PciAddress,
573 AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
574 Translation ? AddrMapInfo->CpuAddress - AddrMapInfo->PciAddress : 0,
575 AddrMapInfo->AddressSize,
576 0,
577 NULL,
578 0,
579 TRUE,
580 CrsNode,
581 NULL
582 );
583 break;
584
585 case PCI_SS_M64:
586 Status = AmlCodeGenRdQWordMemory (
587 FALSE,
588 IsPosDecode,
589 TRUE,
590 TRUE,
591 TRUE,
592 TRUE,
593 0,
594 AddrMapInfo->PciAddress,
595 AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
596 Translation ? AddrMapInfo->CpuAddress - AddrMapInfo->PciAddress : 0,
597 AddrMapInfo->AddressSize,
598 0,
599 NULL,
600 0,
601 TRUE,
602 CrsNode,
603 NULL
604 );
605 break;
606
607 default:
608 Status = EFI_INVALID_PARAMETER;
609 } // switch
610
611 if (EFI_ERROR (Status)) {
612 ASSERT (0);
613 return Status;
614 }
615 } // for
616
617 return Status;
618 }
619
620 /** Generate a RES0 device node to reserve PNP motherboard resources
621 for a given PCI node.
622
623 @param [in] PciNode Parent PCI node handle of the generated
624 resource object.
625 @param [out] CrsNode CRS node of the AML tree to populate.
626
627 @retval EFI_SUCCESS The function completed successfully.
628 @retval EFI_INVALID_PARAMETER Invalid input parameter.
629 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
630 **/
631 STATIC
632 EFI_STATUS
633 EFIAPI
634 GenerateMotherboardDevice (
635 IN AML_OBJECT_NODE_HANDLE PciNode,
636 OUT AML_OBJECT_NODE_HANDLE *CrsNode
637 )
638 {
639 EFI_STATUS Status;
640 UINT32 EisaId;
641 AML_OBJECT_NODE_HANDLE ResNode;
642
643 if (CrsNode == NULL) {
644 ASSERT (0);
645 return EFI_INVALID_PARAMETER;
646 }
647
648 // ASL: Device (RES0) {}
649 Status = AmlCodeGenDevice ("RES0", PciNode, &ResNode);
650 if (EFI_ERROR (Status)) {
651 ASSERT (0);
652 return Status;
653 }
654
655 // ASL: Name (_HID, EISAID ("PNP0C02"))
656 Status = AmlGetEisaIdFromString ("PNP0C02", &EisaId); /* PNP Motherboard Resources */
657 if (EFI_ERROR (Status)) {
658 ASSERT (0);
659 return Status;
660 }
661
662 Status = AmlCodeGenNameInteger ("_HID", EisaId, ResNode, NULL);
663 if (EFI_ERROR (Status)) {
664 ASSERT (0);
665 return Status;
666 }
667
668 // ASL: Name (_CRS, ResourceTemplate () {})
669 Status = AmlCodeGenNameResourceTemplate ("_CRS", ResNode, CrsNode);
670 if (EFI_ERROR (Status)) {
671 ASSERT (0);
672 return Status;
673 }
674
675 return Status;
676 }
677
678 /** Reserves ECAM space for PCI config space
679
680 @param [in] Generator The SSDT Pci generator.
681 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
682 Protocol interface.
683 @param [in] PciInfo Pci device information.
684 @param [in, out] PciNode RootNode of the AML tree to populate.
685
686 @retval EFI_SUCCESS The function completed successfully.
687 @retval EFI_INVALID_PARAMETER Invalid parameter.
688 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
689 **/
690 STATIC
691 EFI_STATUS
692 EFIAPI
693 ReserveEcamSpace (
694 IN ACPI_PCI_GENERATOR *Generator,
695 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
696 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
697 IN OUT AML_OBJECT_NODE_HANDLE PciNode
698 )
699 {
700 EFI_STATUS Status;
701 AML_OBJECT_NODE_HANDLE CrsNode;
702 UINT64 AddressMinimum;
703 UINT64 AddressMaximum;
704
705 Status = GenerateMotherboardDevice (PciNode, &CrsNode);
706 if (EFI_ERROR (Status)) {
707 ASSERT (0);
708 return Status;
709 }
710
711 AddressMinimum = PciInfo->BaseAddress + (PciInfo->StartBusNumber *
712 PCI_MAX_DEVICE_COUNT_PER_BUS * PCI_MAX_FUNCTION_COUNT_PER_DEVICE * SIZE_4KB);
713 AddressMaximum = PciInfo->BaseAddress + ((PciInfo->EndBusNumber + 1) *
714 PCI_MAX_DEVICE_COUNT_PER_BUS * PCI_MAX_FUNCTION_COUNT_PER_DEVICE * SIZE_4KB) - 1;
715
716 Status = AmlCodeGenRdQWordMemory (
717 FALSE,
718 TRUE,
719 TRUE,
720 TRUE,
721 FALSE, // non-cacheable
722 TRUE,
723 0,
724 AddressMinimum,
725 AddressMaximum,
726 0, // no translation
727 AddressMaximum - AddressMinimum + 1,
728 0,
729 NULL,
730 0,
731 TRUE,
732 CrsNode,
733 NULL
734 );
735
736 if (EFI_ERROR (Status)) {
737 ASSERT (0);
738 return Status;
739 }
740
741 return Status;
742 }
743
744 /** Generate a Pci device.
745
746 @param [in] Generator The SSDT Pci generator.
747 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
748 Protocol interface.
749 @param [in] PciInfo Pci device information.
750 @param [in] Uid Unique Id of the Pci device.
751 @param [in, out] RootNode RootNode of the AML tree to populate.
752
753 @retval EFI_SUCCESS The function completed successfully.
754 @retval EFI_INVALID_PARAMETER Invalid parameter.
755 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
756 **/
757 STATIC
758 EFI_STATUS
759 EFIAPI
760 GeneratePciDevice (
761 IN ACPI_PCI_GENERATOR *Generator,
762 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
763 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
764 IN UINT32 Uid,
765 IN OUT AML_ROOT_NODE_HANDLE *RootNode
766 )
767 {
768 EFI_STATUS Status;
769
770 CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
771 AML_OBJECT_NODE_HANDLE ScopeNode;
772 AML_OBJECT_NODE_HANDLE PciNode;
773
774 ASSERT (Generator != NULL);
775 ASSERT (CfgMgrProtocol != NULL);
776 ASSERT (PciInfo != NULL);
777 ASSERT (RootNode != NULL);
778
779 PciNode = NULL;
780
781 // ASL: Scope (\_SB) {}
782 Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
783 if (EFI_ERROR (Status)) {
784 ASSERT (0);
785 return Status;
786 }
787
788 // Write the name of the PCI device.
789 CopyMem (AslName, "PCIx", AML_NAME_SEG_SIZE + 1);
790 AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (Uid & 0xF);
791 if (Uid > 0xF) {
792 AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((Uid >> 4) & 0xF);
793 }
794
795 // ASL: Device (PCIx) {}
796 Status = AmlCodeGenDevice (AslName, ScopeNode, &PciNode);
797 if (EFI_ERROR (Status)) {
798 ASSERT (0);
799 return Status;
800 }
801
802 // Populate the PCIx node with some Id values.
803 Status = GeneratePciDeviceInfo (PciInfo, Uid, PciNode);
804 if (EFI_ERROR (Status)) {
805 ASSERT (0);
806 return Status;
807 }
808
809 // Generate the Pci Routing Table (_PRT).
810 if (PciInfo->InterruptMapToken != CM_NULL_TOKEN) {
811 Status = GeneratePrt (
812 Generator,
813 CfgMgrProtocol,
814 PciInfo,
815 Uid,
816 PciNode
817 );
818 if (EFI_ERROR (Status)) {
819 ASSERT (0);
820 return Status;
821 }
822 }
823
824 // Generate the _CRS method.
825 Status = GeneratePciCrs (Generator, CfgMgrProtocol, PciInfo, PciNode);
826 if (EFI_ERROR (Status)) {
827 ASSERT (0);
828 return Status;
829 }
830
831 // Add the PNP Motherboard Resources Device to reserve ECAM space
832 Status = ReserveEcamSpace (Generator, CfgMgrProtocol, PciInfo, PciNode);
833 if (EFI_ERROR (Status)) {
834 ASSERT (0);
835 return Status;
836 }
837
838 // Add the template _OSC method.
839 Status = AddOscMethod (PciInfo, PciNode);
840 ASSERT_EFI_ERROR (Status);
841
842 return Status;
843 }
844
845 /** Build an Ssdt table describing a Pci device.
846
847 @param [in] Generator The SSDT Pci generator.
848 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
849 Protocol interface.
850 @param [in] AcpiTableInfo Pointer to the ACPI table information.
851 @param [in] PciInfo Pci device information.
852 @param [in] Uid Unique Id of the Pci device.
853 @param [out] Table If success, contains the created SSDT table.
854
855 @retval EFI_SUCCESS The function completed successfully.
856 @retval EFI_INVALID_PARAMETER Invalid parameter.
857 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
858 **/
859 STATIC
860 EFI_STATUS
861 EFIAPI
862 BuildSsdtPciTable (
863 IN ACPI_PCI_GENERATOR *Generator,
864 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
865 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
866 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
867 IN UINT32 Uid,
868 OUT EFI_ACPI_DESCRIPTION_HEADER **Table
869 )
870 {
871 EFI_STATUS Status;
872 EFI_STATUS Status1;
873 AML_ROOT_NODE_HANDLE RootNode;
874
875 ASSERT (Generator != NULL);
876 ASSERT (CfgMgrProtocol != NULL);
877 ASSERT (PciInfo != NULL);
878 ASSERT (Table != NULL);
879
880 // Create a new Ssdt table.
881 Status = AddSsdtAcpiHeader (
882 CfgMgrProtocol,
883 &Generator->Header,
884 AcpiTableInfo,
885 &RootNode
886 );
887 if (EFI_ERROR (Status)) {
888 ASSERT (0);
889 return Status;
890 }
891
892 Status = GeneratePciDevice (
893 Generator,
894 CfgMgrProtocol,
895 PciInfo,
896 Uid,
897 RootNode
898 );
899 if (EFI_ERROR (Status)) {
900 ASSERT (0);
901 goto exit_handler;
902 }
903
904 // Serialize the tree.
905 Status = AmlSerializeDefinitionBlock (
906 RootNode,
907 Table
908 );
909 if (EFI_ERROR (Status)) {
910 DEBUG ((
911 DEBUG_ERROR,
912 "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data."
913 " Status = %r\n",
914 Status
915 ));
916 }
917
918 exit_handler:
919 // Cleanup
920 Status1 = AmlDeleteTree (RootNode);
921 if (EFI_ERROR (Status1)) {
922 DEBUG ((
923 DEBUG_ERROR,
924 "ERROR: SSDT-PCI: Failed to cleanup AML tree."
925 " Status = %r\n",
926 Status1
927 ));
928 // If Status was success but we failed to delete the AML Tree
929 // return Status1 else return the original error code, i.e. Status.
930 if (!EFI_ERROR (Status)) {
931 return Status1;
932 }
933 }
934
935 return Status;
936 }
937
938 /** Construct SSDT tables describing Pci root complexes.
939
940 This function invokes the Configuration Manager protocol interface
941 to get the required hardware information for generating the ACPI
942 table.
943
944 If this function allocates any resources then they must be freed
945 in the FreeXXXXTableResourcesEx function.
946
947 @param [in] This Pointer to the ACPI table generator.
948 @param [in] AcpiTableInfo Pointer to the ACPI table information.
949 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
950 Protocol interface.
951 @param [out] Table Pointer to a list of generated ACPI table(s).
952 @param [out] TableCount Number of generated ACPI table(s).
953
954 @retval EFI_SUCCESS Table generated successfully.
955 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
956 Manager is less than the Object size for
957 the requested object.
958 @retval EFI_INVALID_PARAMETER A parameter is invalid.
959 @retval EFI_NOT_FOUND Could not find information.
960 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
961 @retval EFI_UNSUPPORTED Unsupported configuration.
962 **/
963 STATIC
964 EFI_STATUS
965 EFIAPI
966 BuildSsdtPciTableEx (
967 IN CONST ACPI_TABLE_GENERATOR *This,
968 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
969 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
970 OUT EFI_ACPI_DESCRIPTION_HEADER ***Table,
971 OUT UINTN *CONST TableCount
972 )
973 {
974 EFI_STATUS Status;
975 CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo;
976 UINT32 PciCount;
977 UINTN Index;
978 EFI_ACPI_DESCRIPTION_HEADER **TableList;
979 ACPI_PCI_GENERATOR *Generator;
980 UINT32 Uid;
981
982 ASSERT (This != NULL);
983 ASSERT (AcpiTableInfo != NULL);
984 ASSERT (CfgMgrProtocol != NULL);
985 ASSERT (Table != NULL);
986 ASSERT (TableCount != NULL);
987 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
988 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
989
990 *TableCount = 0;
991 Generator = (ACPI_PCI_GENERATOR *)This;
992
993 Status = GetEArmObjPciConfigSpaceInfo (
994 CfgMgrProtocol,
995 CM_NULL_TOKEN,
996 &PciInfo,
997 &PciCount
998 );
999 if (EFI_ERROR (Status)) {
1000 ASSERT (0);
1001 return Status;
1002 }
1003
1004 if (PciCount > MAX_PCI_ROOT_COMPLEXES_SUPPORTED) {
1005 DEBUG ((
1006 DEBUG_ERROR,
1007 "ERROR: SSDT-PCI: Too many Pci root complexes: %d."
1008 " Maximum Pci root complexes supported = %d.\n",
1009 PciCount,
1010 MAX_PCI_ROOT_COMPLEXES_SUPPORTED
1011 ));
1012 return EFI_INVALID_PARAMETER;
1013 }
1014
1015 // Allocate a table to store pointers to the SSDT tables.
1016 TableList = (EFI_ACPI_DESCRIPTION_HEADER **)
1017 AllocateZeroPool (
1018 (sizeof (EFI_ACPI_DESCRIPTION_HEADER *) * PciCount)
1019 );
1020 if (TableList == NULL) {
1021 Status = EFI_OUT_OF_RESOURCES;
1022 DEBUG ((
1023 DEBUG_ERROR,
1024 "ERROR: SSDT-PCI: Failed to allocate memory for Table List."
1025 " Status = %r\n",
1026 Status
1027 ));
1028 return Status;
1029 }
1030
1031 // Setup the table list early so that appropriate cleanup
1032 // can be done in case of failure.
1033 *Table = TableList;
1034
1035 for (Index = 0; Index < PciCount; Index++) {
1036 if (PcdGetBool (PcdPciUseSegmentAsUid)) {
1037 Uid = PciInfo[Index].PciSegmentGroupNumber;
1038 if (Uid > MAX_PCI_ROOT_COMPLEXES_SUPPORTED) {
1039 DEBUG ((
1040 DEBUG_ERROR,
1041 "ERROR: SSDT-PCI: Pci root complexes segment number: %d."
1042 " Greater than maximum number of Pci root complexes supported = %d.\n",
1043 Uid,
1044 MAX_PCI_ROOT_COMPLEXES_SUPPORTED
1045 ));
1046 return EFI_INVALID_PARAMETER;
1047 }
1048 } else {
1049 Uid = Index;
1050 }
1051
1052 // Build a SSDT table describing the Pci devices.
1053 Status = BuildSsdtPciTable (
1054 Generator,
1055 CfgMgrProtocol,
1056 AcpiTableInfo,
1057 &PciInfo[Index],
1058 Uid,
1059 &TableList[Index]
1060 );
1061 if (EFI_ERROR (Status)) {
1062 DEBUG ((
1063 DEBUG_ERROR,
1064 "ERROR: SSDT-PCI: Failed to build associated SSDT table."
1065 " Status = %r\n",
1066 Status
1067 ));
1068 goto error_handler;
1069 }
1070
1071 *TableCount += 1;
1072 } // for
1073
1074 error_handler:
1075 // Note: Table list and Table count have been setup. The
1076 // error handler does nothing here as the framework will invoke
1077 // FreeSsdtPciTableEx () even on failure.
1078 return Status;
1079 }
1080
1081 /** Free any resources allocated for constructing the tables.
1082
1083 @param [in] This Pointer to the ACPI table generator.
1084 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1085 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1086 Protocol Interface.
1087 @param [in, out] Table Pointer to an array of pointers
1088 to ACPI Table(s).
1089 @param [in] TableCount Number of ACPI table(s).
1090
1091 @retval EFI_SUCCESS The resources were freed successfully.
1092 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1093 **/
1094 STATIC
1095 EFI_STATUS
1096 EFIAPI
1097 FreeSsdtPciTableEx (
1098 IN CONST ACPI_TABLE_GENERATOR *CONST This,
1099 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
1100 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1101 IN OUT EFI_ACPI_DESCRIPTION_HEADER ***CONST Table,
1102 IN CONST UINTN TableCount
1103 )
1104 {
1105 EFI_ACPI_DESCRIPTION_HEADER **TableList;
1106 UINTN Index;
1107
1108 ASSERT (This != NULL);
1109 ASSERT (AcpiTableInfo != NULL);
1110 ASSERT (CfgMgrProtocol != NULL);
1111 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
1112 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
1113
1114 if ((Table == NULL) ||
1115 (*Table == NULL) ||
1116 (TableCount == 0))
1117 {
1118 DEBUG ((DEBUG_ERROR, "ERROR: SSDT-PCI: Invalid Table Pointer\n"));
1119 return EFI_INVALID_PARAMETER;
1120 }
1121
1122 TableList = *Table;
1123 for (Index = 0; Index < TableCount; Index++) {
1124 if ((TableList[Index] != NULL) &&
1125 (TableList[Index]->Signature ==
1126 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE))
1127 {
1128 FreePool (TableList[Index]);
1129 } else {
1130 DEBUG ((
1131 DEBUG_ERROR,
1132 "ERROR: SSDT-PCI: Could not free SSDT table at index %d.",
1133 Index
1134 ));
1135 return EFI_INVALID_PARAMETER;
1136 }
1137 } // for
1138
1139 // Free the table list.
1140 FreePool (*Table);
1141
1142 return EFI_SUCCESS;
1143 }
1144
1145 /** This macro defines the SSDT Pci Table Generator revision.
1146 */
1147 #define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0)
1148
1149 /** The interface for the SSDT Pci Table Generator.
1150 */
1151 STATIC
1152 ACPI_PCI_GENERATOR SsdtPcieGenerator = {
1153 // ACPI table generator header
1154 {
1155 // Generator ID
1156 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress),
1157 // Generator Description
1158 L"ACPI.STD.SSDT.PCI.GENERATOR",
1159 // ACPI Table Signature
1160 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
1161 // ACPI Table Revision - Unused
1162 0,
1163 // Minimum ACPI Table Revision - Unused
1164 0,
1165 // Creator ID
1166 TABLE_GENERATOR_CREATOR_ID_ARM,
1167 // Creator Revision
1168 SSDT_PCI_GENERATOR_REVISION,
1169 // Build table function. Use the extended version instead.
1170 NULL,
1171 // Free table function. Use the extended version instead.
1172 NULL,
1173 // Extended Build table function.
1174 BuildSsdtPciTableEx,
1175 // Extended free function.
1176 FreeSsdtPciTableEx
1177 },
1178
1179 // Private fields are defined from here.
1180
1181 // DeviceTable
1182 {
1183 // Table
1184 NULL,
1185 // LastIndex
1186 0,
1187 // MaxIndex
1188 0
1189 },
1190 };
1191
1192 /** Register the Generator with the ACPI Table Factory.
1193
1194 @param [in] ImageHandle The handle to the image.
1195 @param [in] SystemTable Pointer to the System Table.
1196
1197 @retval EFI_SUCCESS The Generator is registered.
1198 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1199 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1200 is already registered.
1201 **/
1202 EFI_STATUS
1203 EFIAPI
1204 AcpiSsdtPcieLibConstructor (
1205 IN EFI_HANDLE ImageHandle,
1206 IN EFI_SYSTEM_TABLE *SystemTable
1207 )
1208 {
1209 EFI_STATUS Status;
1210
1211 Status = RegisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
1212 DEBUG ((
1213 DEBUG_INFO,
1214 "SSDT-PCI: Register Generator. Status = %r\n",
1215 Status
1216 ));
1217 ASSERT_EFI_ERROR (Status);
1218 return Status;
1219 }
1220
1221 /** Deregister the Generator from the ACPI Table Factory.
1222
1223 @param [in] ImageHandle The handle to the image.
1224 @param [in] SystemTable Pointer to the System Table.
1225
1226 @retval EFI_SUCCESS The Generator is deregistered.
1227 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1228 @retval EFI_NOT_FOUND The Generator is not registered.
1229 **/
1230 EFI_STATUS
1231 EFIAPI
1232 AcpiSsdtPcieLibDestructor (
1233 IN EFI_HANDLE ImageHandle,
1234 IN EFI_SYSTEM_TABLE *SystemTable
1235 )
1236 {
1237 EFI_STATUS Status;
1238
1239 Status = DeregisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
1240 DEBUG ((
1241 DEBUG_INFO,
1242 "SSDT-PCI: Deregister Generator. Status = %r\n",
1243 Status
1244 ));
1245 ASSERT_EFI_ERROR (Status);
1246 return Status;
1247 }