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