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