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