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