]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c
DynamicTablesPkg: Change complex DEBUG_CODE() to DEBUG_CODE_BEGIN/END()
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiSsdtCmn600LibArm / SsdtCmn600Generator.c
CommitLineData
37568365
PG
1/** @file\r
2 SSDT CMN-600 AML Table Generator.\r
3\r
1f515342 4 Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR>\r
37568365
PG
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8 @par Reference(s):\r
9 - Arm CoreLink CMN-600 Coherent Mesh Network Technical Reference Manual r3p0\r
10 - Generic ACPI for Arm Components 1.0 Platform Design Document\r
11**/\r
12\r
37568365
PG
13#include <Library/AcpiLib.h>\r
14#include <Library/BaseLib.h>\r
15#include <Library/BaseMemoryLib.h>\r
16#include <Library/DebugLib.h>\r
17#include <Library/MemoryAllocationLib.h>\r
37568365
PG
18#include <Protocol/AcpiTable.h>\r
19\r
20// Module specific include files.\r
21#include <AcpiTableGenerator.h>\r
22#include <ConfigurationManagerObject.h>\r
23#include <ConfigurationManagerHelper.h>\r
0875443f 24#include <Library/AcpiHelperLib.h>\r
37568365 25#include <Library/AmlLib/AmlLib.h>\r
37568365
PG
26#include <Protocol/ConfigurationManagerProtocol.h>\r
27#include "SsdtCmn600Generator.h"\r
28\r
29/** C array containing the compiled AML template.\r
30 This symbol is defined in the auto generated C file\r
31 containing the AML bytecode array.\r
32*/\r
33extern CHAR8 ssdtcmn600template_aml_code[];\r
34\r
35/** SSDT CMN-600 Table Generator.\r
36\r
37 Requirements:\r
38 The following Configuration Manager Object(s) are required by\r
39 this Generator:\r
40 - EArmObjCmn600Info\r
41*/\r
42\r
43/** This macro expands to a function that retrieves the CMN-600\r
44 Information from the Configuration Manager.\r
45*/\r
46GET_OBJECT_LIST (\r
47 EObjNameSpaceArm,\r
48 EArmObjCmn600Info,\r
49 CM_ARM_CMN_600_INFO\r
50 );\r
51\r
52/** Check the CMN-600 Information.\r
53\r
54 @param [in] Cmn600InfoList Array of CMN-600 information structure.\r
55 @param [in] Cmn600Count Count of CMN-600 information structure.\r
56\r
57 @retval EFI_SUCCESS The function completed successfully.\r
58 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
59**/\r
60STATIC\r
61EFI_STATUS\r
62EFIAPI\r
63ValidateCmn600Info (\r
64 IN CONST CM_ARM_CMN_600_INFO * Cmn600InfoList,\r
65 IN CONST UINT32 Cmn600Count\r
66 )\r
67{\r
68 UINT32 Index;\r
69 UINT32 DtcIndex;\r
70 CONST CM_ARM_CMN_600_INFO * Cmn600Info;\r
71 CONST CM_ARM_GENERIC_INTERRUPT * DtcInterrupt;\r
72\r
73 if ((Cmn600InfoList == NULL) ||\r
74 (Cmn600Count == 0)) {\r
75 return EFI_INVALID_PARAMETER;\r
76 }\r
77\r
78 // Validate each Cmn600Info structure.\r
79 for (Index = 0; Index < Cmn600Count; Index++) {\r
80 Cmn600Info = &Cmn600InfoList[Index];\r
81\r
82 // At least one DTC is required.\r
83 if ((Cmn600Info->DtcCount == 0) ||\r
84 (Cmn600Info->DtcCount > MAX_DTC_COUNT)) {\r
85 DEBUG ((\r
86 DEBUG_ERROR,\r
87 "ERROR: SSDT-CMN-600: Invalid DTC configuration:\n"\r
88 ));\r
89 goto error_handler;\r
90 }\r
91\r
92 // Check PERIPHBASE and ROOTNODEBASE address spaces are initialized.\r
93 if ((Cmn600Info->PeriphBaseAddress == 0) ||\r
94 (Cmn600Info->RootNodeBaseAddress == 0)) {\r
95 DEBUG ((\r
96 DEBUG_ERROR,\r
97 "ERROR: SSDT-CMN-600: Invalid PERIPHBASE or ROOTNODEBASE.\n"\r
98 ));\r
99 goto error_handler;\r
100 }\r
101\r
102 // The PERIPHBASE address must be 64MB aligned for a (X < 4) && (Y < 4)\r
103 // dimension mesh, and 256MB aligned otherwise.\r
104 // Check it is a least 64MB aligned.\r
105 if ((Cmn600Info->PeriphBaseAddress &\r
106 (PERIPHBASE_MIN_ADDRESS_LENGTH - 1)) != 0) {\r
107 DEBUG ((\r
108 DEBUG_ERROR,\r
109 "ERROR: SSDT-CMN-600: PERIPHBASE address must be 64MB aligned.\n"\r
110 ));\r
111 goto error_handler;\r
112 }\r
113\r
114 // The PERIPHBASE address is at most 64MB for a (X < 4) && (Y < 4)\r
115 // dimension mesh, and 256MB otherwise. Check it is not more than 256MB.\r
116 if (Cmn600Info->PeriphBaseAddressLength > PERIPHBASE_MAX_ADDRESS_LENGTH) {\r
117 DEBUG ((\r
118 DEBUG_ERROR,\r
119 "ERROR: SSDT-CMN-600: PERIPHBASE address range must be < 256MB.\n"\r
120 ));\r
121 goto error_handler;\r
122 }\r
123\r
124 // Check the 16 KB alignment of the ROOTNODEBASE address.\r
125 if ((Cmn600Info->PeriphBaseAddress &\r
126 (ROOTNODEBASE_ADDRESS_LENGTH - 1)) != 0) {\r
127 DEBUG ((\r
128 DEBUG_ERROR,\r
129 "ERROR: SSDT-CMN-600: Root base address must be 16KB aligned.\n"\r
130 ));\r
131 goto error_handler;\r
132 }\r
133\r
134 // The ROOTNODEBASE address space should be included in the PERIPHBASE\r
135 // address space.\r
136 if ((Cmn600Info->PeriphBaseAddress > Cmn600Info->RootNodeBaseAddress) ||\r
137 ((Cmn600Info->PeriphBaseAddress + Cmn600Info->PeriphBaseAddressLength) <\r
138 (Cmn600Info->RootNodeBaseAddress + ROOTNODEBASE_ADDRESS_LENGTH))) {\r
139 DEBUG ((\r
140 DEBUG_ERROR,\r
141 "ERROR: SSDT-CMN-600:"\r
142 " ROOTNODEBASE address space not in PERIPHBASE address space.\n"\r
143 ));\r
144 goto error_handler;\r
145 }\r
146\r
147 for (DtcIndex = 0; DtcIndex < Cmn600Info->DtcCount; DtcIndex++) {\r
148 DtcInterrupt = &Cmn600Info->DtcInterrupt[DtcIndex];\r
149 if (((DtcInterrupt->Flags &\r
150 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_PRODUCER_CONSUMER_MASK) == 0)) {\r
151 DEBUG ((\r
152 DEBUG_ERROR,\r
153 "ERROR: SSDT-CMN-600: DTC Interrupt must be consumer.\n"\r
154 ));\r
155 goto error_handler;\r
156 }\r
157 } // for DTC Interrupt\r
158\r
159 } //for Cmn600InfoList\r
160\r
161 return EFI_SUCCESS;\r
162\r
163error_handler:\r
164\r
165 DEBUG ((\r
166 DEBUG_ERROR,\r
167 "PeriphBaseAddress = 0x%llx\n"\r
168 "PeriphBaseAddressLength = 0x%llx\n"\r
169 "RootNodeBaseAddress = 0x%llx\n"\r
170 "DtcCount = %u\n",\r
171 Cmn600Info->PeriphBaseAddress,\r
172 Cmn600Info->PeriphBaseAddressLength,\r
173 Cmn600Info->RootNodeBaseAddress,\r
174 Cmn600Info->DtcCount\r
175 ));\r
176\r
4a9d4116 177 DEBUG_CODE_BEGIN ();\r
37568365
PG
178 for (DtcIndex = 0; DtcIndex < Cmn600Info->DtcCount; DtcIndex++) {\r
179 DtcInterrupt = &Cmn600Info->DtcInterrupt[DtcIndex];\r
180 DEBUG ((\r
181 DEBUG_ERROR,\r
182 " DTC[%d]:\n",\r
183 DtcIndex\r
184 ));\r
185 DEBUG ((\r
186 DEBUG_ERROR,\r
187 " Interrupt = 0x%lx\n",\r
188 DtcInterrupt->Interrupt\r
189 ));\r
190 DEBUG ((\r
191 DEBUG_ERROR,\r
192 " Flags = 0x%lx\n",\r
193 DtcInterrupt->Flags\r
194 ));\r
195 } // for\r
4a9d4116 196 DEBUG_CODE_END ();\r
37568365
PG
197\r
198 return EFI_INVALID_PARAMETER;\r
199}\r
200\r
201/** Build a SSDT table describing the CMN-600 device.\r
202\r
203 The table created by this function must be freed by FreeSsdtCmn600Table.\r
204\r
205 @param [in] Cmn600Info Pointer to a Cmn600 structure.\r
206 @param [in] Name The Name to give to the Device.\r
207 Must be a NULL-terminated ASL NameString\r
208 e.g.: "DEV0", "DV15.DEV0", etc.\r
209 @param [in] Uid UID for the CMN600 device.\r
210 @param [out] Table If success, pointer to the created SSDT table.\r
211\r
212 @retval EFI_SUCCESS Table generated successfully.\r
213 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
214 @retval EFI_NOT_FOUND Could not find information.\r
215 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r
216**/\r
217STATIC\r
218EFI_STATUS\r
219EFIAPI\r
220FixupCmn600Info (\r
221 IN CONST CM_ARM_CMN_600_INFO * Cmn600Info,\r
222 IN CONST CHAR8 * Name,\r
223 IN CONST UINT64 Uid,\r
224 OUT EFI_ACPI_DESCRIPTION_HEADER ** Table\r
225 )\r
226{\r
227 EFI_STATUS Status;\r
228 EFI_STATUS Status1;\r
229 UINT8 Index;\r
230 CONST CM_ARM_GENERIC_INTERRUPT * DtcInt;\r
231\r
232 EFI_ACPI_DESCRIPTION_HEADER * SsdtCmn600Template;\r
233 AML_ROOT_NODE_HANDLE RootNodeHandle;\r
234 AML_OBJECT_NODE_HANDLE NameOpIdNode;\r
235 AML_OBJECT_NODE_HANDLE NameOpCrsNode;\r
236 AML_DATA_NODE_HANDLE CmnPeriphBaseRdNode;\r
237 AML_DATA_NODE_HANDLE CmnRootNodeBaseRdNode;\r
238 AML_OBJECT_NODE_HANDLE DeviceNode;\r
239\r
240 // Parse the Ssdt CMN-600 Template.\r
241 SsdtCmn600Template = (EFI_ACPI_DESCRIPTION_HEADER*)\r
242 ssdtcmn600template_aml_code;\r
243\r
244 RootNodeHandle = NULL;\r
245 Status = AmlParseDefinitionBlock (\r
246 SsdtCmn600Template,\r
247 &RootNodeHandle\r
248 );\r
249 if (EFI_ERROR (Status)) {\r
250 DEBUG ((\r
251 DEBUG_ERROR,\r
252 "ERROR: SSDT-CMN-600: Failed to parse SSDT CMN-600 Template."\r
253 " Status = %r\n",\r
254 Status\r
255 ));\r
256 return Status;\r
257 }\r
258\r
259 // Get the _UID NameOp object defined by the "Name ()" statement,\r
260 // and update its value.\r
261 Status = AmlFindNode (\r
262 RootNodeHandle,\r
263 "\\_SB_.CMN0._UID",\r
264 &NameOpIdNode\r
265 );\r
266 if (EFI_ERROR (Status)) {\r
267 goto error_handler;\r
268 }\r
269\r
270 Status = AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid);\r
271 if (EFI_ERROR (Status)) {\r
272 goto error_handler;\r
273 }\r
274\r
275 // Get the _CRS object defined by the "Name ()" statement.\r
276 Status = AmlFindNode (\r
277 RootNodeHandle,\r
278 "\\_SB.CMN0._CRS",\r
279 &NameOpCrsNode\r
280 );\r
281 if (EFI_ERROR (Status)) {\r
282 goto error_handler;\r
283 }\r
284\r
285 // Get the first Rd node in the "_CRS" object.\r
286 // This is the PERIPHBASE node.\r
691c5f77 287 Status = AmlNameOpGetFirstRdNode (NameOpCrsNode, &CmnPeriphBaseRdNode);\r
37568365
PG
288 if (EFI_ERROR (Status)) {\r
289 goto error_handler;\r
290 }\r
291\r
292 if (CmnPeriphBaseRdNode == NULL) {\r
293 Status = EFI_INVALID_PARAMETER;\r
294 goto error_handler;\r
295 }\r
296\r
297 // Update the PERIPHBASE base address and length.\r
298 Status = AmlUpdateRdQWord (\r
299 CmnPeriphBaseRdNode,\r
300 Cmn600Info->PeriphBaseAddress,\r
301 Cmn600Info->PeriphBaseAddressLength\r
302 );\r
303 if (EFI_ERROR (Status)) {\r
304 goto error_handler;\r
305 }\r
306\r
307 // Get the QWord node corresponding to the ROOTNODEBASE.\r
308 // It is the second Resource Data element in the BufferNode's\r
309 // variable list of arguments.\r
691c5f77 310 Status = AmlNameOpGetNextRdNode (\r
37568365
PG
311 CmnPeriphBaseRdNode,\r
312 &CmnRootNodeBaseRdNode\r
313 );\r
314 if (EFI_ERROR (Status)) {\r
315 goto error_handler;\r
316 }\r
317\r
318 if (CmnRootNodeBaseRdNode == NULL) {\r
319 Status = EFI_INVALID_PARAMETER;\r
320 goto error_handler;\r
321 }\r
322\r
323 // Update the ROOTNODEBASE base address and length.\r
324 Status = AmlUpdateRdQWord (\r
325 CmnRootNodeBaseRdNode,\r
326 Cmn600Info->RootNodeBaseAddress,\r
327 ROOTNODEBASE_ADDRESS_LENGTH\r
328 );\r
329 if (EFI_ERROR (Status)) {\r
330 goto error_handler;\r
331 }\r
332\r
333 // Add the Interrupt node(s).\r
334 // Generate Resource Data node(s) corresponding to the "Interrupt ()"\r
335 // ASL function and add it at the last position in the list of\r
336 // Resource Data nodes.\r
337 for (Index = 0; Index < Cmn600Info->DtcCount; Index++) {\r
338 DtcInt = &Cmn600Info->DtcInterrupt[Index];\r
22873f58
PG
339\r
340 Status = AmlCodeGenRdInterrupt (\r
37568365
PG
341 ((DtcInt->Flags &\r
342 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_PRODUCER_CONSUMER_MASK) != 0),\r
343 ((DtcInt->Flags &\r
344 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_MODE_MASK) != 0),\r
345 ((DtcInt->Flags &\r
346 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_POLARITY_MASK) != 0),\r
347 ((DtcInt->Flags &\r
348 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_SHARABLE_MASK) != 0),\r
349 (UINT32*)&DtcInt->Interrupt,\r
22873f58
PG
350 1,\r
351 NameOpCrsNode,\r
352 NULL\r
37568365
PG
353 );\r
354 if (EFI_ERROR (Status)) {\r
355 goto error_handler;\r
356 }\r
357 } // for\r
358\r
359 // Fixup the CMN600 device name.\r
360 // This MUST be done at the end, otherwise AML paths won't be valid anymore.\r
361 // Get the CMN0 variable defined by the "Device ()" statement.\r
362 Status = AmlFindNode (RootNodeHandle, "\\_SB_.CMN0", &DeviceNode);\r
363 if (EFI_ERROR (Status)) {\r
364 goto error_handler;\r
365 }\r
366\r
367 // Update the CMN600 Device's name.\r
368 Status = AmlDeviceOpUpdateName (DeviceNode, (CHAR8*)Name);\r
369 if (EFI_ERROR (Status)) {\r
370 goto error_handler;\r
371 }\r
372\r
373 // Serialise the definition block\r
374 Status = AmlSerializeDefinitionBlock (\r
375 RootNodeHandle,\r
376 Table\r
377 );\r
378 if (EFI_ERROR (Status)) {\r
379 DEBUG ((\r
380 DEBUG_ERROR,\r
381 "ERROR: SSDT-CMN-600: Failed to Serialize SSDT Table Data."\r
382 " Status = %r\n",\r
383 Status\r
384 ));\r
385 }\r
386\r
387error_handler:\r
388 // Cleanup\r
389 if (RootNodeHandle != NULL) {\r
390 Status1 = AmlDeleteTree (RootNodeHandle);\r
391 if (EFI_ERROR (Status1)) {\r
392 DEBUG ((\r
393 DEBUG_ERROR,\r
394 "ERROR: SSDT-CMN-600: Failed to cleanup AML tree."\r
395 " Status = %r\n",\r
396 Status1\r
397 ));\r
398 // If Status was success but we failed to delete the AML Tree\r
399 // return Status1 else return the original error code, i.e. Status.\r
400 if (!EFI_ERROR (Status)) {\r
401 return Status1;\r
402 }\r
403 }\r
404 }\r
405\r
406 return Status;\r
407}\r
408\r
409/** Free any resources allocated for constructing the SSDT tables for CMN-600.\r
410\r
411 @param [in] This Pointer to the ACPI table generator.\r
412 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
413 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
414 Protocol Interface.\r
415 @param [in, out] Table Pointer to an array of pointers\r
416 to ACPI Table(s).\r
417 @param [in] TableCount Number of ACPI table(s).\r
418\r
419 @retval EFI_SUCCESS The resources were freed successfully.\r
420 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
421**/\r
422STATIC\r
423EFI_STATUS\r
424EFIAPI\r
425FreeSsdtCmn600TableResourcesEx (\r
426 IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
427 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
428 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
429 IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,\r
430 IN CONST UINTN TableCount\r
431 )\r
432{\r
433 EFI_ACPI_DESCRIPTION_HEADER ** TableList;\r
434 UINTN Index;\r
435\r
436 ASSERT (This != NULL);\r
437 ASSERT (AcpiTableInfo != NULL);\r
438 ASSERT (CfgMgrProtocol != NULL);\r
439 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
440 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
441\r
442 if ((Table == NULL) ||\r
443 (*Table == NULL) ||\r
444 (TableCount == 0)) {\r
445 DEBUG ((DEBUG_ERROR, "ERROR: SSDT-CMN-600: Invalid Table Pointer\n"));\r
446 return EFI_INVALID_PARAMETER;\r
447 }\r
448\r
449 TableList = *Table;\r
450\r
451 for (Index = 0; Index < TableCount; Index++) {\r
452 if ((TableList[Index] != NULL) &&\r
453 (TableList[Index]->Signature ==\r
454 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {\r
455 FreePool (TableList[Index]);\r
456 } else {\r
457 DEBUG ((\r
458 DEBUG_ERROR,\r
459 "ERROR: SSDT-CMN-600: Could not free SSDT table at index %d."\r
460 " Status = %r\n",\r
461 Index,\r
462 EFI_INVALID_PARAMETER\r
463 ));\r
464 return EFI_INVALID_PARAMETER;\r
465 }\r
466 } //for\r
467\r
468 // Free the table list.\r
469 FreePool (*Table);\r
470 *Table = NULL;\r
471 return EFI_SUCCESS;\r
472}\r
473\r
474/** Construct SSDT tables for describing CMN-600 meshes.\r
475\r
476 This function invokes the Configuration Manager protocol interface\r
477 to get the required hardware information for generating the ACPI\r
478 table.\r
479\r
480 If this function allocates any resources then they must be freed\r
481 in the FreeXXXXTableResourcesEx function.\r
482\r
483 @param [in] This Pointer to the ACPI table generator.\r
484 @param [in] AcpiTableInfo Pointer to the ACPI table information.\r
485 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
486 Protocol interface.\r
487 @param [out] Table Pointer to a list of generated ACPI table(s).\r
488 @param [out] TableCount Number of generated ACPI table(s).\r
489\r
490 @retval EFI_SUCCESS Table generated successfully.\r
491 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
492 Manager is less than the Object size for\r
493 the requested object.\r
494 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
495 @retval EFI_NOT_FOUND Could not find information.\r
496 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r
497 @retval EFI_UNSUPPORTED Unsupported configuration.\r
498**/\r
499STATIC\r
500EFI_STATUS\r
501EFIAPI\r
502BuildSsdtCmn600TableEx (\r
503 IN CONST ACPI_TABLE_GENERATOR * This,\r
504 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
505 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
506 OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,\r
507 OUT UINTN * CONST TableCount\r
508 )\r
509{\r
510 EFI_STATUS Status;\r
511 UINT64 Index;\r
512 CM_ARM_CMN_600_INFO * Cmn600Info;\r
513 UINT32 Cmn600Count;\r
1f515342 514 CHAR8 NewName[AML_NAME_SEG_SIZE + 1];\r
37568365
PG
515 EFI_ACPI_DESCRIPTION_HEADER ** TableList;\r
516\r
517 ASSERT (This != NULL);\r
518 ASSERT (AcpiTableInfo != NULL);\r
519 ASSERT (CfgMgrProtocol != NULL);\r
520 ASSERT (Table != NULL);\r
521 ASSERT (TableCount != NULL);\r
522 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
523 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
524\r
525 *Table = NULL;\r
526\r
527 // Get CMN-600 information.\r
528 Status = GetEArmObjCmn600Info (\r
529 CfgMgrProtocol,\r
530 CM_NULL_TOKEN,\r
531 &Cmn600Info,\r
532 &Cmn600Count\r
533 );\r
534 if (EFI_ERROR (Status)) {\r
535 DEBUG ((\r
536 DEBUG_ERROR,\r
537 "ERROR: SSDT-CMN-600: Failed to get the CMN-600 information."\r
538 " Status = %r\n",\r
539 Status\r
540 ));\r
541 return Status;\r
542 }\r
543\r
544 if ((Cmn600Count == 0) || (Cmn600Count > MAX_CMN600_DEVICES_SUPPORTED)) {\r
545 DEBUG ((\r
546 DEBUG_ERROR,\r
547 "ERROR: SSDT-CMN-600: CMN600 peripheral count = %d."\r
548 " This must be between 1 to 16.\n",\r
549 Cmn600Count\r
550 ));\r
551 return EFI_INVALID_PARAMETER;\r
552 }\r
553\r
554 // Validate the CMN-600 Info.\r
555 Status = ValidateCmn600Info (Cmn600Info, Cmn600Count);\r
556 if (EFI_ERROR (Status)) {\r
557 DEBUG ((\r
558 DEBUG_ERROR,\r
559 "ERROR: SSDT-CMN-600: Invalid CMN600 information. Status = %r\n",\r
560 Status\r
561 ));\r
562 return Status;\r
563 }\r
564\r
565 // Allocate a table to store pointers to the SSDT tables.\r
566 TableList = (EFI_ACPI_DESCRIPTION_HEADER**)\r
567 AllocateZeroPool (\r
568 (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * Cmn600Count)\r
569 );\r
570 if (TableList == NULL) {\r
571 Status = EFI_OUT_OF_RESOURCES;\r
572 DEBUG ((\r
573 DEBUG_ERROR,\r
574 "ERROR: SSDT-CMN-600: Failed to allocate memory for Table List."\r
575 " Status = %r\n",\r
576 Status\r
577 ));\r
578 return Status;\r
579 }\r
580\r
581 // Setup the table list early so that that appropriate cleanup\r
582 // can be done in case of failure.\r
583 *Table = TableList;\r
584\r
585 NewName[0] = 'C';\r
586 NewName[1] = 'M';\r
587 NewName[2] = 'N';\r
588 NewName[4] = '\0';\r
589 for (Index = 0; Index < Cmn600Count; Index++) {\r
590 NewName[3] = AsciiFromHex ((UINT8)(Index));\r
591\r
592 // Build a SSDT table describing the CMN600 device.\r
593 Status = FixupCmn600Info (\r
594 &Cmn600Info[Index],\r
595 NewName,\r
596 Index,\r
597 &TableList[Index]\r
598 );\r
599 if (EFI_ERROR (Status)) {\r
600 DEBUG ((\r
601 DEBUG_ERROR,\r
602 "ERROR: SSDT-CMN-600: Failed to build associated SSDT table."\r
603 " Status = %r\n",\r
604 Status\r
605 ));\r
606 break;\r
607 }\r
608\r
609 // Increment the table count here so that appropriate clean-up\r
610 // can be done in case of failure.\r
611 *TableCount += 1;\r
612 } // for\r
613\r
614 // Note: Table list and CMN600 device count has been setup. The\r
615 // framework will invoke FreeSsdtCmn600TableResourcesEx() even\r
616 // on failure, so appropriate clean-up will be done.\r
617 return Status;\r
618}\r
619\r
620/** This macro defines the Raw Generator revision.\r
621*/\r
622#define SSDT_CMN_600_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
623\r
624/** The interface for the Raw Table Generator.\r
625*/\r
626STATIC\r
627CONST\r
628ACPI_TABLE_GENERATOR SsdtCmn600Generator = {\r
629 // Generator ID\r
630 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCmn600),\r
631 // Generator Description\r
632 L"ACPI.STD.SSDT.CMN600.GENERATOR",\r
633 // ACPI Table Signature\r
634 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,\r
635 // ACPI Table Revision - Unused\r
636 0,\r
637 // Minimum ACPI Table Revision - Unused\r
638 0,\r
639 // Creator ID\r
640 TABLE_GENERATOR_CREATOR_ID_ARM,\r
641 // Creator Revision\r
642 SSDT_CMN_600_GENERATOR_REVISION,\r
643 // Build table function. Use the extended version instead.\r
644 NULL,\r
645 // Free table function. Use the extended version instead.\r
646 NULL,\r
647 // Build Table function\r
648 BuildSsdtCmn600TableEx,\r
649 // Free Resource function\r
650 FreeSsdtCmn600TableResourcesEx\r
651};\r
652\r
653/** Register the Generator with the ACPI Table Factory.\r
654\r
655 @param [in] ImageHandle The handle to the image.\r
656 @param [in] SystemTable Pointer to the System Table.\r
657\r
658 @retval EFI_SUCCESS The Generator is registered.\r
659 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
660 @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
661 is already registered.\r
662**/\r
663EFI_STATUS\r
664EFIAPI\r
665AcpiSsdtCmn600LibConstructor (\r
666 IN EFI_HANDLE ImageHandle,\r
667 IN EFI_SYSTEM_TABLE * SystemTable\r
668 )\r
669{\r
670 EFI_STATUS Status;\r
671\r
672 Status = RegisterAcpiTableGenerator (&SsdtCmn600Generator);\r
673 DEBUG ((\r
674 DEBUG_INFO,\r
675 "SSDT-CMN-600: Register Generator. Status = %r\n",\r
676 Status\r
677 ));\r
678 ASSERT_EFI_ERROR (Status);\r
679 return Status;\r
680}\r
681\r
682/** Deregister the Generator from the ACPI Table Factory.\r
683\r
684 @param [in] ImageHandle The handle to the image.\r
685 @param [in] SystemTable Pointer to the System Table.\r
686\r
687 @retval EFI_SUCCESS The Generator is deregistered.\r
688 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
689 @retval EFI_NOT_FOUND The Generator is not registered.\r
690**/\r
691EFI_STATUS\r
692EFIAPI\r
693AcpiSsdtCmn600LibDestructor (\r
694 IN EFI_HANDLE ImageHandle,\r
695 IN EFI_SYSTEM_TABLE * SystemTable\r
696 )\r
697{\r
698 EFI_STATUS Status;\r
699\r
700 Status = DeregisterAcpiTableGenerator (&SsdtCmn600Generator);\r
701 DEBUG ((\r
702 DEBUG_INFO,\r
703 "SSDT-CMN-600: Deregister Generator. Status = %r\n",\r
704 Status\r
705 ));\r
706 ASSERT_EFI_ERROR (Status);\r
707 return Status;\r
708}\r