]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
DynamicTablesPkg: AcpiSsdtPcieLibArm: Added function to reserve ECAM space
[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 The first model (defining a _CRS object) is used. This is necessary because
292 PCI legacy interrupts are active low and GICv2 SPI interrupts are active
293 high.
294 Even though PCI interrupts cannot be re-routed, only the first model allows
295 to specify the activation state (low/high).
296
297 @param [in] Generator The SSDT Pci generator.
298 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
299 Protocol interface.
300 @param [in] PciInfo Pci device information.
301 @param [in, out] PciNode Pci node to amend.
302
303 @retval EFI_SUCCESS The function completed successfully.
304 @retval EFI_INVALID_PARAMETER Invalid parameter.
305 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
306 **/
307 STATIC
308 EFI_STATUS
309 EFIAPI
310 GeneratePrt (
311 IN ACPI_PCI_GENERATOR *Generator,
312 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
313 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
314 IN OUT AML_OBJECT_NODE_HANDLE PciNode
315 )
316 {
317 EFI_STATUS Status;
318 INT32 Index;
319 AML_OBJECT_NODE_HANDLE PrtNode;
320 CM_ARM_OBJ_REF *RefInfo;
321 UINT32 RefCount;
322 CM_ARM_PCI_INTERRUPT_MAP_INFO *IrqMapInfo;
323
324 ASSERT (Generator != NULL);
325 ASSERT (CfgMgrProtocol != NULL);
326 ASSERT (PciInfo != NULL);
327 ASSERT (PciNode != NULL);
328
329 PrtNode = NULL;
330
331 // Get the array of CM_ARM_OBJ_REF referencing the
332 // CM_ARM_PCI_INTERRUPT_MAP_INFO objects.
333 Status = GetEArmObjCmRef (
334 CfgMgrProtocol,
335 PciInfo->InterruptMapToken,
336 &RefInfo,
337 &RefCount
338 );
339 if (EFI_ERROR (Status)) {
340 ASSERT (0);
341 return Status;
342 }
343
344 // Initialized DeviceTable.
345 Status = MappingTableInitialize (&Generator->DeviceTable, RefCount);
346 if (EFI_ERROR (Status)) {
347 ASSERT (0);
348 goto exit_handler0;
349 }
350
351 // ASL: Name (_PRT, Package () {})
352 Status = AmlCodeGenNamePackage ("_PRT", NULL, &PrtNode);
353 if (EFI_ERROR (Status)) {
354 ASSERT (0);
355 goto exit_handler;
356 }
357
358 for (Index = 0; Index < RefCount; Index++) {
359 // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.
360 Status = GetEArmObjPciInterruptMapInfo (
361 CfgMgrProtocol,
362 RefInfo[Index].ReferenceToken,
363 &IrqMapInfo,
364 NULL
365 );
366 if (EFI_ERROR (Status)) {
367 ASSERT (0);
368 goto exit_handler;
369 }
370
371 // Check that the interrupts flags are SPIs, level high.
372 // Cf. Arm BSA v1.0, sE.6 "Legacy interrupts"
373 if ((Index > 0) &&
374 (IrqMapInfo->IntcInterrupt.Interrupt >= 32) &&
375 (IrqMapInfo->IntcInterrupt.Interrupt < 1020) &&
376 ((IrqMapInfo->IntcInterrupt.Flags & 0xB) != 0))
377 {
378 Status = EFI_INVALID_PARAMETER;
379 ASSERT_EFI_ERROR (Status);
380 goto exit_handler;
381 }
382
383 // Add the device to the DeviceTable.
384 MappingTableAdd (&Generator->DeviceTable, IrqMapInfo->PciDevice);
385
386 /* Add a _PRT entry.
387 ASL
388 Name (_PRT, Package () {
389 <OldPrtEntries>,
390 <NewPrtEntry>
391 })
392
393 Address is set as:
394 ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
395 High word-Device #, Low word-Function #. (for example, device 3,
396 function 2 is 0x00030002). To refer to all the functions on a device #,
397 use a function number of FFFF).
398 */
399 Status = AmlAddPrtEntry (
400 (IrqMapInfo->PciDevice << 16) | 0xFFFF,
401 IrqMapInfo->PciInterrupt,
402 NULL,
403 IrqMapInfo->IntcInterrupt.Interrupt,
404 PrtNode
405 );
406 if (EFI_ERROR (Status)) {
407 ASSERT (0);
408 goto exit_handler;
409 }
410 } // for
411
412 // Attach the _PRT entry.
413 Status = AmlAttachNode (PciNode, PrtNode);
414 if (EFI_ERROR (Status)) {
415 ASSERT_EFI_ERROR (Status);
416 goto exit_handler;
417 }
418
419 PrtNode = NULL;
420
421 // Generate the Pci slots once all the device have been added.
422 Status = GeneratePciSlots (PciInfo, &Generator->DeviceTable, PciNode);
423 if (EFI_ERROR (Status)) {
424 ASSERT (0);
425 goto exit_handler;
426 }
427
428 exit_handler:
429 MappingTableFree (&Generator->DeviceTable);
430 exit_handler0:
431 if (PrtNode != NULL) {
432 AmlDeleteTree (PrtNode);
433 }
434
435 return Status;
436 }
437
438 /** Generate a _CRS method for the Pci device.
439
440 @param [in] Generator The SSDT Pci generator.
441 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
442 Protocol interface.
443 @param [in] PciInfo Pci device information.
444 @param [in, out] PciNode Pci node to amend.
445
446 @retval EFI_SUCCESS The function completed successfully.
447 @retval EFI_INVALID_PARAMETER Invalid parameter.
448 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
449 **/
450 STATIC
451 EFI_STATUS
452 EFIAPI
453 GeneratePciCrs (
454 IN ACPI_PCI_GENERATOR *Generator,
455 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
456 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
457 IN OUT AML_OBJECT_NODE_HANDLE PciNode
458 )
459 {
460 EFI_STATUS Status;
461 BOOLEAN Translation;
462 UINT32 Index;
463 CM_ARM_OBJ_REF *RefInfo;
464 UINT32 RefCount;
465 CM_ARM_PCI_ADDRESS_MAP_INFO *AddrMapInfo;
466 AML_OBJECT_NODE_HANDLE CrsNode;
467 BOOLEAN IsPosDecode;
468
469 ASSERT (Generator != NULL);
470 ASSERT (CfgMgrProtocol != NULL);
471 ASSERT (PciInfo != NULL);
472 ASSERT (PciNode != NULL);
473
474 // ASL: Name (_CRS, ResourceTemplate () {})
475 Status = AmlCodeGenNameResourceTemplate ("_CRS", PciNode, &CrsNode);
476 if (EFI_ERROR (Status)) {
477 ASSERT (0);
478 return Status;
479 }
480
481 // ASL:
482 // WordBusNumber ( // Bus numbers assigned to this root
483 // ResourceProducer, MinFixed, MaxFixed, PosDecode,
484 // 0, // AddressGranularity
485 // <Start>, // AddressMinimum - Minimum Bus Number
486 // <End>, // AddressMaximum - Maximum Bus Number
487 // 0, // AddressTranslation - Set to 0
488 // <End> - <Start> + 1 // RangeLength - Number of Busses
489 // )
490 Status = AmlCodeGenRdWordBusNumber (
491 FALSE,
492 TRUE,
493 TRUE,
494 TRUE,
495 0,
496 PciInfo->StartBusNumber,
497 PciInfo->EndBusNumber,
498 0,
499 PciInfo->EndBusNumber - PciInfo->StartBusNumber + 1,
500 0,
501 NULL,
502 CrsNode,
503 NULL
504 );
505 if (EFI_ERROR (Status)) {
506 ASSERT (0);
507 return Status;
508 }
509
510 // Get the array of CM_ARM_OBJ_REF referencing the
511 // CM_ARM_PCI_ADDRESS_MAP_INFO objects.
512 Status = GetEArmObjCmRef (
513 CfgMgrProtocol,
514 PciInfo->AddressMapToken,
515 &RefInfo,
516 &RefCount
517 );
518 if (EFI_ERROR (Status)) {
519 ASSERT (0);
520 return Status;
521 }
522
523 for (Index = 0; Index < RefCount; Index++) {
524 // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one.
525 Status = GetEArmObjPciAddressMapInfo (
526 CfgMgrProtocol,
527 RefInfo[Index].ReferenceToken,
528 &AddrMapInfo,
529 NULL
530 );
531 if (EFI_ERROR (Status)) {
532 ASSERT (0);
533 return Status;
534 }
535
536 Translation = (AddrMapInfo->CpuAddress != AddrMapInfo->PciAddress);
537 if (AddrMapInfo->CpuAddress >= AddrMapInfo->PciAddress) {
538 IsPosDecode = TRUE;
539 } else {
540 IsPosDecode = FALSE;
541 }
542
543 switch (AddrMapInfo->SpaceCode) {
544 case PCI_SS_IO:
545 Status = AmlCodeGenRdDWordIo (
546 FALSE,
547 TRUE,
548 TRUE,
549 IsPosDecode,
550 3,
551 0,
552 AddrMapInfo->PciAddress,
553 AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
554 Translation ? AddrMapInfo->CpuAddress - AddrMapInfo->PciAddress : 0,
555 AddrMapInfo->AddressSize,
556 0,
557 NULL,
558 TRUE,
559 FALSE,
560 CrsNode,
561 NULL
562 );
563 break;
564
565 case PCI_SS_M32:
566 Status = AmlCodeGenRdDWordMemory (
567 FALSE,
568 IsPosDecode,
569 TRUE,
570 TRUE,
571 TRUE,
572 TRUE,
573 0,
574 AddrMapInfo->PciAddress,
575 AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
576 Translation ? AddrMapInfo->CpuAddress - AddrMapInfo->PciAddress : 0,
577 AddrMapInfo->AddressSize,
578 0,
579 NULL,
580 0,
581 TRUE,
582 CrsNode,
583 NULL
584 );
585 break;
586
587 case PCI_SS_M64:
588 Status = AmlCodeGenRdQWordMemory (
589 FALSE,
590 IsPosDecode,
591 TRUE,
592 TRUE,
593 TRUE,
594 TRUE,
595 0,
596 AddrMapInfo->PciAddress,
597 AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
598 Translation ? AddrMapInfo->CpuAddress - AddrMapInfo->PciAddress : 0,
599 AddrMapInfo->AddressSize,
600 0,
601 NULL,
602 0,
603 TRUE,
604 CrsNode,
605 NULL
606 );
607 break;
608
609 default:
610 Status = EFI_INVALID_PARAMETER;
611 } // switch
612
613 if (EFI_ERROR (Status)) {
614 ASSERT (0);
615 return Status;
616 }
617 } // for
618
619 return Status;
620 }
621
622 /** Generate a RES0 device node to reserve PNP motherboard resources
623 for a given PCI node.
624
625 @param [in] PciNode Parent PCI node handle of the generated
626 resource object.
627 @param [out] CrsNode CRS node of the AML tree to populate.
628
629 @retval EFI_SUCCESS The function completed successfully.
630 @retval EFI_INVALID_PARAMETER Invalid input parameter.
631 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
632 **/
633 STATIC
634 EFI_STATUS
635 EFIAPI
636 GenerateMotherboardDevice (
637 IN AML_OBJECT_NODE_HANDLE PciNode,
638 OUT AML_OBJECT_NODE_HANDLE *CrsNode
639 )
640 {
641 EFI_STATUS Status;
642 UINT32 EisaId;
643 AML_OBJECT_NODE_HANDLE ResNode;
644
645 if (CrsNode == NULL) {
646 ASSERT (0);
647 return EFI_INVALID_PARAMETER;
648 }
649
650 // ASL: Device (RES0) {}
651 Status = AmlCodeGenDevice ("RES0", PciNode, &ResNode);
652 if (EFI_ERROR (Status)) {
653 ASSERT (0);
654 return Status;
655 }
656
657 // ASL: Name (_HID, EISAID ("PNP0C02"))
658 Status = AmlGetEisaIdFromString ("PNP0C02", &EisaId); /* PNP Motherboard Resources */
659 if (EFI_ERROR (Status)) {
660 ASSERT (0);
661 return Status;
662 }
663
664 Status = AmlCodeGenNameInteger ("_HID", EisaId, ResNode, NULL);
665 if (EFI_ERROR (Status)) {
666 ASSERT (0);
667 return Status;
668 }
669
670 // ASL: Name (_CRS, ResourceTemplate () {})
671 Status = AmlCodeGenNameResourceTemplate ("_CRS", ResNode, CrsNode);
672 if (EFI_ERROR (Status)) {
673 ASSERT (0);
674 return Status;
675 }
676
677 return Status;
678 }
679
680 /** Reserves ECAM space for PCI config space
681
682 @param [in] Generator The SSDT Pci generator.
683 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
684 Protocol interface.
685 @param [in] PciInfo Pci device information.
686 @param [in, out] PciNode RootNode of the AML tree to populate.
687
688 @retval EFI_SUCCESS The function completed successfully.
689 @retval EFI_INVALID_PARAMETER Invalid parameter.
690 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
691 **/
692 STATIC
693 EFI_STATUS
694 EFIAPI
695 ReserveEcamSpace (
696 IN ACPI_PCI_GENERATOR *Generator,
697 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
698 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
699 IN OUT AML_OBJECT_NODE_HANDLE PciNode
700 )
701 {
702 EFI_STATUS Status;
703 AML_OBJECT_NODE_HANDLE CrsNode;
704 UINT64 AddressMinimum;
705 UINT64 AddressMaximum;
706
707 Status = GenerateMotherboardDevice (PciNode, &CrsNode);
708 if (EFI_ERROR (Status)) {
709 ASSERT (0);
710 return Status;
711 }
712
713 AddressMinimum = PciInfo->BaseAddress + (PciInfo->StartBusNumber *
714 PCI_MAX_DEVICE_COUNT_PER_BUS * PCI_MAX_FUNCTION_COUNT_PER_DEVICE * SIZE_4KB);
715 AddressMaximum = PciInfo->BaseAddress + ((PciInfo->EndBusNumber + 1) *
716 PCI_MAX_DEVICE_COUNT_PER_BUS * PCI_MAX_FUNCTION_COUNT_PER_DEVICE * SIZE_4KB) - 1;
717
718 Status = AmlCodeGenRdQWordMemory (
719 FALSE,
720 TRUE,
721 TRUE,
722 TRUE,
723 FALSE, // non-cacheable
724 TRUE,
725 0,
726 AddressMinimum,
727 AddressMaximum,
728 0, // no translation
729 AddressMaximum - AddressMinimum + 1,
730 0,
731 NULL,
732 0,
733 TRUE,
734 CrsNode,
735 NULL
736 );
737
738 if (EFI_ERROR (Status)) {
739 ASSERT (0);
740 return Status;
741 }
742
743 return Status;
744 }
745
746 /** Generate a Pci device.
747
748 @param [in] Generator The SSDT Pci generator.
749 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
750 Protocol interface.
751 @param [in] PciInfo Pci device information.
752 @param [in] Uid Unique Id of the Pci device.
753 @param [in, out] RootNode RootNode of the AML tree to populate.
754
755 @retval EFI_SUCCESS The function completed successfully.
756 @retval EFI_INVALID_PARAMETER Invalid parameter.
757 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
758 **/
759 STATIC
760 EFI_STATUS
761 EFIAPI
762 GeneratePciDevice (
763 IN ACPI_PCI_GENERATOR *Generator,
764 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
765 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
766 IN UINT32 Uid,
767 IN OUT AML_ROOT_NODE_HANDLE *RootNode
768 )
769 {
770 EFI_STATUS Status;
771
772 CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
773 AML_OBJECT_NODE_HANDLE ScopeNode;
774 AML_OBJECT_NODE_HANDLE PciNode;
775
776 ASSERT (Generator != NULL);
777 ASSERT (CfgMgrProtocol != NULL);
778 ASSERT (PciInfo != NULL);
779 ASSERT (RootNode != NULL);
780
781 PciNode = NULL;
782
783 // ASL: Scope (\_SB) {}
784 Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
785 if (EFI_ERROR (Status)) {
786 ASSERT (0);
787 return Status;
788 }
789
790 // Write the name of the PCI device.
791 CopyMem (AslName, "PCIx", AML_NAME_SEG_SIZE + 1);
792 AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (Uid & 0xF);
793 if (Uid > 0xF) {
794 AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((Uid >> 4) & 0xF);
795 }
796
797 // ASL: Device (PCIx) {}
798 Status = AmlCodeGenDevice (AslName, ScopeNode, &PciNode);
799 if (EFI_ERROR (Status)) {
800 ASSERT (0);
801 return Status;
802 }
803
804 // Populate the PCIx node with some Id values.
805 Status = GeneratePciDeviceInfo (PciInfo, Uid, PciNode);
806 if (EFI_ERROR (Status)) {
807 ASSERT (0);
808 return Status;
809 }
810
811 // Generate the Pci Routing Table (_PRT).
812 if (PciInfo->InterruptMapToken != CM_NULL_TOKEN) {
813 Status = GeneratePrt (
814 Generator,
815 CfgMgrProtocol,
816 PciInfo,
817 PciNode
818 );
819 if (EFI_ERROR (Status)) {
820 ASSERT (0);
821 return Status;
822 }
823 }
824
825 // Generate the _CRS method.
826 Status = GeneratePciCrs (Generator, CfgMgrProtocol, PciInfo, PciNode);
827 if (EFI_ERROR (Status)) {
828 ASSERT (0);
829 return Status;
830 }
831
832 // Add the PNP Motherboard Resources Device to reserve ECAM space
833 Status = ReserveEcamSpace (Generator, CfgMgrProtocol, PciInfo, PciNode);
834 if (EFI_ERROR (Status)) {
835 ASSERT (0);
836 return Status;
837 }
838
839 // Add the template _OSC method.
840 Status = AddOscMethod (PciInfo, PciNode);
841 ASSERT_EFI_ERROR (Status);
842
843 return Status;
844 }
845
846 /** Build an Ssdt table describing a Pci device.
847
848 @param [in] Generator The SSDT Pci generator.
849 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
850 Protocol interface.
851 @param [in] AcpiTableInfo Pointer to the ACPI table information.
852 @param [in] PciInfo Pci device information.
853 @param [in] Uid Unique Id of the Pci device.
854 @param [out] Table If success, contains the created SSDT table.
855
856 @retval EFI_SUCCESS The function completed successfully.
857 @retval EFI_INVALID_PARAMETER Invalid parameter.
858 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
859 **/
860 STATIC
861 EFI_STATUS
862 EFIAPI
863 BuildSsdtPciTable (
864 IN ACPI_PCI_GENERATOR *Generator,
865 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
866 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
867 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
868 IN UINT32 Uid,
869 OUT EFI_ACPI_DESCRIPTION_HEADER **Table
870 )
871 {
872 EFI_STATUS Status;
873 EFI_STATUS Status1;
874 AML_ROOT_NODE_HANDLE RootNode;
875
876 ASSERT (Generator != NULL);
877 ASSERT (CfgMgrProtocol != NULL);
878 ASSERT (PciInfo != NULL);
879 ASSERT (Table != NULL);
880
881 // Create a new Ssdt table.
882 Status = AddSsdtAcpiHeader (
883 CfgMgrProtocol,
884 &Generator->Header,
885 AcpiTableInfo,
886 &RootNode
887 );
888 if (EFI_ERROR (Status)) {
889 ASSERT (0);
890 return Status;
891 }
892
893 Status = GeneratePciDevice (
894 Generator,
895 CfgMgrProtocol,
896 PciInfo,
897 Uid,
898 RootNode
899 );
900 if (EFI_ERROR (Status)) {
901 ASSERT (0);
902 goto exit_handler;
903 }
904
905 // Serialize the tree.
906 Status = AmlSerializeDefinitionBlock (
907 RootNode,
908 Table
909 );
910 if (EFI_ERROR (Status)) {
911 DEBUG ((
912 DEBUG_ERROR,
913 "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data."
914 " Status = %r\n",
915 Status
916 ));
917 }
918
919 exit_handler:
920 // Cleanup
921 Status1 = AmlDeleteTree (RootNode);
922 if (EFI_ERROR (Status1)) {
923 DEBUG ((
924 DEBUG_ERROR,
925 "ERROR: SSDT-PCI: Failed to cleanup AML tree."
926 " Status = %r\n",
927 Status1
928 ));
929 // If Status was success but we failed to delete the AML Tree
930 // return Status1 else return the original error code, i.e. Status.
931 if (!EFI_ERROR (Status)) {
932 return Status1;
933 }
934 }
935
936 return Status;
937 }
938
939 /** Construct SSDT tables describing Pci root complexes.
940
941 This function invokes the Configuration Manager protocol interface
942 to get the required hardware information for generating the ACPI
943 table.
944
945 If this function allocates any resources then they must be freed
946 in the FreeXXXXTableResourcesEx function.
947
948 @param [in] This Pointer to the ACPI table generator.
949 @param [in] AcpiTableInfo Pointer to the ACPI table information.
950 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
951 Protocol interface.
952 @param [out] Table Pointer to a list of generated ACPI table(s).
953 @param [out] TableCount Number of generated ACPI table(s).
954
955 @retval EFI_SUCCESS Table generated successfully.
956 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
957 Manager is less than the Object size for
958 the requested object.
959 @retval EFI_INVALID_PARAMETER A parameter is invalid.
960 @retval EFI_NOT_FOUND Could not find information.
961 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
962 @retval EFI_UNSUPPORTED Unsupported configuration.
963 **/
964 STATIC
965 EFI_STATUS
966 EFIAPI
967 BuildSsdtPciTableEx (
968 IN CONST ACPI_TABLE_GENERATOR *This,
969 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
970 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
971 OUT EFI_ACPI_DESCRIPTION_HEADER ***Table,
972 OUT UINTN *CONST TableCount
973 )
974 {
975 EFI_STATUS Status;
976 CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo;
977 UINT32 PciCount;
978 UINTN Index;
979 EFI_ACPI_DESCRIPTION_HEADER **TableList;
980 ACPI_PCI_GENERATOR *Generator;
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 // Build a SSDT table describing the Pci devices.
1037 Status = BuildSsdtPciTable (
1038 Generator,
1039 CfgMgrProtocol,
1040 AcpiTableInfo,
1041 &PciInfo[Index],
1042 Index,
1043 &TableList[Index]
1044 );
1045 if (EFI_ERROR (Status)) {
1046 DEBUG ((
1047 DEBUG_ERROR,
1048 "ERROR: SSDT-PCI: Failed to build associated SSDT table."
1049 " Status = %r\n",
1050 Status
1051 ));
1052 goto error_handler;
1053 }
1054
1055 *TableCount += 1;
1056 } // for
1057
1058 error_handler:
1059 // Note: Table list and Table count have been setup. The
1060 // error handler does nothing here as the framework will invoke
1061 // FreeSsdtPciTableEx () even on failure.
1062 return Status;
1063 }
1064
1065 /** Free any resources allocated for constructing the tables.
1066
1067 @param [in] This Pointer to the ACPI table generator.
1068 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1069 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1070 Protocol Interface.
1071 @param [in, out] Table Pointer to an array of pointers
1072 to ACPI Table(s).
1073 @param [in] TableCount Number of ACPI table(s).
1074
1075 @retval EFI_SUCCESS The resources were freed successfully.
1076 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1077 **/
1078 STATIC
1079 EFI_STATUS
1080 EFIAPI
1081 FreeSsdtPciTableEx (
1082 IN CONST ACPI_TABLE_GENERATOR *CONST This,
1083 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
1084 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1085 IN OUT EFI_ACPI_DESCRIPTION_HEADER ***CONST Table,
1086 IN CONST UINTN TableCount
1087 )
1088 {
1089 EFI_ACPI_DESCRIPTION_HEADER **TableList;
1090 UINTN Index;
1091
1092 ASSERT (This != NULL);
1093 ASSERT (AcpiTableInfo != NULL);
1094 ASSERT (CfgMgrProtocol != NULL);
1095 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
1096 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
1097
1098 if ((Table == NULL) ||
1099 (*Table == NULL) ||
1100 (TableCount == 0))
1101 {
1102 DEBUG ((DEBUG_ERROR, "ERROR: SSDT-PCI: Invalid Table Pointer\n"));
1103 return EFI_INVALID_PARAMETER;
1104 }
1105
1106 TableList = *Table;
1107 for (Index = 0; Index < TableCount; Index++) {
1108 if ((TableList[Index] != NULL) &&
1109 (TableList[Index]->Signature ==
1110 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE))
1111 {
1112 FreePool (TableList[Index]);
1113 } else {
1114 DEBUG ((
1115 DEBUG_ERROR,
1116 "ERROR: SSDT-PCI: Could not free SSDT table at index %d.",
1117 Index
1118 ));
1119 return EFI_INVALID_PARAMETER;
1120 }
1121 } // for
1122
1123 // Free the table list.
1124 FreePool (*Table);
1125
1126 return EFI_SUCCESS;
1127 }
1128
1129 /** This macro defines the SSDT Pci Table Generator revision.
1130 */
1131 #define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0)
1132
1133 /** The interface for the SSDT Pci Table Generator.
1134 */
1135 STATIC
1136 ACPI_PCI_GENERATOR SsdtPcieGenerator = {
1137 // ACPI table generator header
1138 {
1139 // Generator ID
1140 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress),
1141 // Generator Description
1142 L"ACPI.STD.SSDT.PCI.GENERATOR",
1143 // ACPI Table Signature
1144 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
1145 // ACPI Table Revision - Unused
1146 0,
1147 // Minimum ACPI Table Revision - Unused
1148 0,
1149 // Creator ID
1150 TABLE_GENERATOR_CREATOR_ID_ARM,
1151 // Creator Revision
1152 SSDT_PCI_GENERATOR_REVISION,
1153 // Build table function. Use the extended version instead.
1154 NULL,
1155 // Free table function. Use the extended version instead.
1156 NULL,
1157 // Extended Build table function.
1158 BuildSsdtPciTableEx,
1159 // Extended free function.
1160 FreeSsdtPciTableEx
1161 },
1162
1163 // Private fields are defined from here.
1164
1165 // DeviceTable
1166 {
1167 // Table
1168 NULL,
1169 // LastIndex
1170 0,
1171 // MaxIndex
1172 0
1173 },
1174 };
1175
1176 /** Register the Generator with the ACPI Table Factory.
1177
1178 @param [in] ImageHandle The handle to the image.
1179 @param [in] SystemTable Pointer to the System Table.
1180
1181 @retval EFI_SUCCESS The Generator is registered.
1182 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1183 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1184 is already registered.
1185 **/
1186 EFI_STATUS
1187 EFIAPI
1188 AcpiSsdtPcieLibConstructor (
1189 IN EFI_HANDLE ImageHandle,
1190 IN EFI_SYSTEM_TABLE *SystemTable
1191 )
1192 {
1193 EFI_STATUS Status;
1194
1195 Status = RegisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
1196 DEBUG ((
1197 DEBUG_INFO,
1198 "SSDT-PCI: Register Generator. Status = %r\n",
1199 Status
1200 ));
1201 ASSERT_EFI_ERROR (Status);
1202 return Status;
1203 }
1204
1205 /** Deregister the Generator from the ACPI Table Factory.
1206
1207 @param [in] ImageHandle The handle to the image.
1208 @param [in] SystemTable Pointer to the System Table.
1209
1210 @retval EFI_SUCCESS The Generator is deregistered.
1211 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1212 @retval EFI_NOT_FOUND The Generator is not registered.
1213 **/
1214 EFI_STATUS
1215 EFIAPI
1216 AcpiSsdtPcieLibDestructor (
1217 IN EFI_HANDLE ImageHandle,
1218 IN EFI_SYSTEM_TABLE *SystemTable
1219 )
1220 {
1221 EFI_STATUS Status;
1222
1223 Status = DeregisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
1224 DEBUG ((
1225 DEBUG_INFO,
1226 "SSDT-PCI: Deregister Generator. Status = %r\n",
1227 Status
1228 ));
1229 ASSERT_EFI_ERROR (Status);
1230 return Status;
1231 }