1 /*
2 * Copyright (c) 2023 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "acpi.h"
8 #include "accommon.h"
9 #include "acapps.h"
10 #include <aecommon.h>
11
12 #include <zephyr/drivers/pcie/pcie.h>
13 #include <zephyr/acpi/acpi.h>
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(ACPI, CONFIG_ACPI_LOG_LEVEL);
16
17 static struct {
18 struct acpi_dev child_dev[CONFIG_ACPI_DEV_MAX];
19 int num_dev;
20 #ifdef CONFIG_PCIE_PRT
21 ACPI_PCI_ROUTING_TABLE pci_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY];
22 #endif
23 bool early_init;
24 ACPI_STATUS status;
25 } acpi = {
26 .status = AE_NOT_CONFIGURED,
27 };
28
29 static int acpi_init(void);
30
check_init_status(void)31 static int check_init_status(void)
32 {
33 if (acpi.status == AE_NOT_CONFIGURED) {
34 acpi.status = acpi_init();
35 }
36
37 if (ACPI_FAILURE(acpi.status)) {
38 LOG_ERR("ACPI init was not success");
39 return -EIO;
40 }
41
42 return 0;
43 }
44
notify_handler(ACPI_HANDLE device,UINT32 value,void * ctx)45 static void notify_handler(ACPI_HANDLE device, UINT32 value, void *ctx)
46 {
47 ACPI_INFO(("Received a notify 0x%X", value));
48 }
49
install_handlers(void)50 static ACPI_STATUS install_handlers(void)
51 {
52 ACPI_STATUS status;
53
54 /* Install global notify handler */
55 status = AcpiInstallNotifyHandler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, notify_handler,
56 NULL);
57 if (ACPI_FAILURE(status)) {
58 ACPI_EXCEPTION((AE_INFO, status, "While installing Notify handler"));
59 goto exit;
60 }
61
62 exit:
63 return status;
64 }
65
initialize_acpica(void)66 static ACPI_STATUS initialize_acpica(void)
67 {
68 ACPI_STATUS status;
69
70 /* Initialize the ACPI subsystem */
71 status = AcpiInitializeSubsystem();
72 if (ACPI_FAILURE(status)) {
73 ACPI_EXCEPTION((AE_INFO, status, "While initializing ACPI"));
74 goto exit;
75 }
76
77 /* Initialize the ACPI Table Manager and get all ACPI tables */
78 if (!acpi.early_init) {
79 status = AcpiInitializeTables(NULL, 16, FALSE);
80 if (ACPI_FAILURE(status)) {
81 ACPI_EXCEPTION((AE_INFO, status, "While initializing Table Manager"));
82 goto exit;
83 }
84 }
85
86 /* Create the ACPI namespace from ACPI tables */
87 status = AcpiLoadTables();
88 if (ACPI_FAILURE(status)) {
89 ACPI_EXCEPTION((AE_INFO, status, "While loading ACPI tables"));
90 goto exit;
91 }
92
93 /* Install local handlers */
94 status = install_handlers();
95 if (ACPI_FAILURE(status)) {
96 ACPI_EXCEPTION((AE_INFO, status, "While installing handlers"));
97 goto exit;
98 }
99
100 /* Initialize the ACPI hardware */
101 status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
102 if (ACPI_FAILURE(status)) {
103 ACPI_EXCEPTION((AE_INFO, status, "While enabling ACPI"));
104 goto exit;
105 }
106
107 /* Complete the ACPI namespace object initialization */
108 status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
109 if (ACPI_FAILURE(status)) {
110 ACPI_EXCEPTION((AE_INFO, status, "While initializing ACPI objects"));
111 }
112 exit:
113
114 return status;
115 }
116
acpi_name_lookup(char * name)117 static ACPI_NAMESPACE_NODE *acpi_name_lookup(char *name)
118 {
119 char *path;
120 ACPI_STATUS status;
121 ACPI_NAMESPACE_NODE *node;
122
123 LOG_DBG("");
124
125 status = AcpiNsInternalizeName(name, &path);
126 if (ACPI_FAILURE(status)) {
127 LOG_ERR("Invalid namestring: %s", name);
128 return NULL;
129 }
130
131 status = AcpiNsLookup(NULL, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
132 ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node);
133 if (ACPI_FAILURE(status)) {
134 LOG_ERR("Could not locate name: %s, %d", name, status);
135 node = NULL;
136 }
137
138 ACPI_FREE(path);
139 return node;
140 }
141
acpi_evaluate_method(char * bus_name,char * method)142 static ACPI_NAMESPACE_NODE *acpi_evaluate_method(char *bus_name, char *method)
143 {
144 ACPI_NAMESPACE_NODE *node;
145 ACPI_NAMESPACE_NODE *handle;
146 ACPI_NAMESPACE_NODE *prt_node = NULL;
147
148 LOG_DBG("%s", bus_name);
149
150 handle = acpi_name_lookup(bus_name);
151 if (!handle) {
152 LOG_ERR("No ACPI node with given name: %s", bus_name);
153 goto exit;
154 }
155
156 if (handle->Type != ACPI_TYPE_DEVICE) {
157 LOG_ERR("No ACPI node foud with given name: %s", bus_name);
158 goto exit;
159 }
160
161 node = ACPI_CAST_PTR(ACPI_NAMESPACE_NODE, handle);
162
163 (void)AcpiGetHandle(node, method, ACPI_CAST_PTR(ACPI_HANDLE, &prt_node));
164
165 if (!prt_node) {
166 LOG_ERR("No entry for the ACPI node with given name: %s", bus_name);
167 goto exit;
168 }
169 return node;
170 exit:
171 return NULL;
172 }
173
acpi_enable_pic_mode(void)174 static ACPI_STATUS acpi_enable_pic_mode(void)
175 {
176 ACPI_STATUS status;
177 ACPI_OBJECT_LIST arg_list;
178 ACPI_OBJECT arg[1];
179
180 arg_list.Count = 1;
181 arg_list.Pointer = arg;
182
183 arg[0].Type = ACPI_TYPE_INTEGER;
184 arg[0].Integer.Value = 1;
185
186 status = AcpiEvaluateObject(NULL, "\\_PIC", &arg_list, NULL);
187 if (ACPI_FAILURE(status)) {
188 LOG_WRN("error While executing \\_pic method: %d", status);
189 }
190
191 return status;
192 }
193
dev_resource_enum_callback(ACPI_HANDLE obj_handle,UINT32 level,void * ctx,void ** ret_value)194 static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 level, void *ctx,
195 void **ret_value)
196 {
197 ACPI_NAMESPACE_NODE *node;
198 ACPI_BUFFER rt_buffer;
199 struct acpi_dev *child_dev;
200
201 node = ACPI_CAST_PTR(ACPI_NAMESPACE_NODE, obj_handle);
202 char *path_name;
203 ACPI_STATUS status;
204 ACPI_DEVICE_INFO *dev_info;
205
206 LOG_DBG("%s %p", __func__, node);
207
208 /* get device info such as HID, Class ID etc. */
209 status = AcpiGetObjectInfo(obj_handle, &dev_info);
210 if (ACPI_FAILURE(status)) {
211 LOG_ERR("AcpiGetObjectInfo failed: %s", AcpiFormatException(status));
212 goto exit;
213 }
214
215 if (acpi.num_dev >= CONFIG_ACPI_DEV_MAX) {
216 return AE_NO_MEMORY;
217 }
218
219 if (!(dev_info->Valid & ACPI_VALID_HID)) {
220 goto exit;
221 }
222
223 child_dev = (struct acpi_dev *)&acpi.child_dev[acpi.num_dev++];
224 child_dev->handle = obj_handle;
225 child_dev->dev_info = dev_info;
226
227 path_name = AcpiNsGetNormalizedPathname(node, TRUE);
228 if (!path_name) {
229 LOG_ERR("No memory for path_name");
230 goto exit;
231 } else {
232 LOG_DBG("Device path: %s", path_name);
233 child_dev->path = path_name;
234 }
235
236 rt_buffer.Pointer = NULL;
237 rt_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
238
239 status = AcpiGetCurrentResources(node, &rt_buffer);
240 if (ACPI_FAILURE(status)) {
241 LOG_DBG("AcpiGetCurrentResources failed: %s", AcpiFormatException(status));
242 } else {
243 child_dev->res_lst = rt_buffer.Pointer;
244 }
245
246 exit:
247
248 return AE_OK;
249 }
250
acpi_enum_devices(void)251 static int acpi_enum_devices(void)
252 {
253 LOG_DBG("");
254
255 AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
256 dev_resource_enum_callback, NULL, NULL, NULL);
257
258 return 0;
259 }
260
acpi_early_init(void)261 static int acpi_early_init(void)
262 {
263 ACPI_STATUS status;
264
265 LOG_DBG("");
266
267 if (acpi.early_init) {
268 LOG_DBG("acpi early init already done");
269 return 0;
270 }
271
272 status = AcpiInitializeTables(NULL, 16, FALSE);
273 if (ACPI_FAILURE(status)) {
274 LOG_ERR("Error in acpi table init:%d", status);
275 return -EIO;
276 }
277
278 acpi.early_init = true;
279
280 return 0;
281 }
282
acpi_current_resource_get(char * dev_name,ACPI_RESOURCE ** res)283 int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res)
284 {
285 ACPI_BUFFER rt_buffer;
286 ACPI_NAMESPACE_NODE *node;
287 ACPI_STATUS status;
288
289 LOG_DBG("%s", dev_name);
290
291 status = check_init_status();
292 if (status) {
293 return -EAGAIN;
294 }
295
296 node = acpi_evaluate_method(dev_name, METHOD_NAME__CRS);
297 if (!node) {
298 LOG_ERR("Evaluation failed for given device: %s", dev_name);
299 return -ENOTSUP;
300 }
301
302 rt_buffer.Pointer = NULL;
303 rt_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
304
305 status = AcpiGetCurrentResources(node, &rt_buffer);
306 if (ACPI_FAILURE(status)) {
307 LOG_ERR("AcpiGetCurrentResources failed: %s", AcpiFormatException(status));
308 return -ENOTSUP;
309 }
310
311 *res = rt_buffer.Pointer;
312
313 return 0;
314 }
315
acpi_possible_resource_get(char * dev_name,ACPI_RESOURCE ** res)316 int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res)
317 {
318 ACPI_BUFFER rt_buffer;
319 ACPI_NAMESPACE_NODE *node;
320 ACPI_STATUS status;
321
322 LOG_DBG("%s", dev_name);
323
324 status = check_init_status();
325 if (status) {
326 return -EAGAIN;
327 }
328
329 node = acpi_evaluate_method(dev_name, METHOD_NAME__PRS);
330 if (!node) {
331 LOG_ERR("Evaluation failed for given device: %s", dev_name);
332 return -ENOTSUP;
333 }
334
335 rt_buffer.Pointer = NULL;
336 rt_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
337
338 AcpiGetPossibleResources(node, &rt_buffer);
339 *res = rt_buffer.Pointer;
340
341 return 0;
342 }
343
acpi_current_resource_free(ACPI_RESOURCE * res)344 int acpi_current_resource_free(ACPI_RESOURCE *res)
345 {
346 ACPI_FREE(res);
347
348 return 0;
349 }
350
351 #ifdef CONFIG_PCIE_PRT
acpi_legacy_irq_get(pcie_bdf_t bdf)352 uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf)
353 {
354 uint32_t slot = PCIE_BDF_TO_DEV(bdf), pin;
355
356 LOG_DBG("");
357
358 if (check_init_status()) {
359 return UINT_MAX;
360 }
361
362 pin = (pcie_conf_read(bdf, PCIE_CONF_INTR) >> 8) & 0x3;
363
364 LOG_DBG("Device irq info: slot:%d pin:%d", slot, pin);
365
366 for (int i = 0; i < CONFIG_ACPI_MAX_PRT_ENTRY; i++) {
367 if (((acpi.pci_prt_table[i].Address >> 16) & 0xffff) == slot &&
368 acpi.pci_prt_table[i].Pin + 1 == pin) {
369 LOG_DBG("[%d]Device irq info: slot:%d pin:%d irq:%d", i, slot, pin,
370 acpi.pci_prt_table[i].SourceIndex);
371 return acpi.pci_prt_table[i].SourceIndex;
372 }
373 }
374
375 return UINT_MAX;
376 }
377
acpi_legacy_irq_init(const char * hid,const char * uid)378 int acpi_legacy_irq_init(const char *hid, const char *uid)
379 {
380 struct acpi_dev *child_dev = acpi_device_get(hid, uid);
381 ACPI_PCI_ROUTING_TABLE *rt_table = acpi.pci_prt_table;
382 ACPI_BUFFER rt_buffer;
383 ACPI_NAMESPACE_NODE *node;
384 ACPI_STATUS status;
385
386 if (!child_dev) {
387 LOG_ERR("no such PCI bus device %s %s", hid, uid);
388 return -ENODEV;
389 }
390
391 node = acpi_evaluate_method(child_dev->path, METHOD_NAME__PRT);
392 if (!node) {
393 LOG_ERR("Evaluation failed for given device: %s", child_dev->path);
394 return -ENODEV;
395 }
396
397 rt_buffer.Pointer = rt_table;
398 rt_buffer.Length = ARRAY_SIZE(acpi.pci_prt_table) * sizeof(ACPI_PCI_ROUTING_TABLE);
399
400 status = AcpiGetIrqRoutingTable(node, &rt_buffer);
401 if (ACPI_FAILURE(status)) {
402 LOG_ERR("unable to retrieve IRQ Routing Table: %s", child_dev->path);
403 return -EIO;
404 }
405
406 if (rt_table->Source[0]) {
407 /*
408 * If Name path exist then PCI interrupts are configurable and are not hardwired to
409 * any specific interrupt inputs on the interrupt controller. OSPM can uses
410 * _PRS/_CRS/_SRS to configure interrupts. But currently leave existing PCI bus
411 * driver with arch_irq_allocate() menthod for allocate and configure interrupts
412 * without conflicting.
413 */
414 return -ENOENT;
415 }
416
417 for (size_t i = 0; i < ARRAY_SIZE(acpi.pci_prt_table); i++) {
418 if (!acpi.pci_prt_table[i].SourceIndex) {
419 break;
420 }
421 if (IS_ENABLED(CONFIG_X86_64)) {
422 /* mark the PRT irq numbers as reserved. */
423 arch_irq_set_used(acpi.pci_prt_table[i].SourceIndex);
424 }
425 }
426
427 return 0;
428 }
429 #endif /* CONFIG_PCIE_PRT */
430
acpi_resource_parse(ACPI_RESOURCE * res,int res_type)431 ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type)
432 {
433 do {
434 if (!res->Length) {
435 LOG_DBG("zero length found!");
436 break;
437 } else if (res->Type == res_type) {
438 break;
439 }
440 res = ACPI_NEXT_RESOURCE(res);
441 } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG);
442
443 if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) {
444 return NULL;
445 }
446
447 return res;
448 }
449
acpi_device_irq_get(struct acpi_dev * child_dev,struct acpi_irq_resource * irq_res)450 int acpi_device_irq_get(struct acpi_dev *child_dev, struct acpi_irq_resource *irq_res)
451 {
452 ACPI_RESOURCE *res = acpi_resource_parse(child_dev->res_lst, ACPI_RESOURCE_TYPE_IRQ);
453
454 if (!res) {
455 res = acpi_resource_parse(child_dev->res_lst, ACPI_RESOURCE_TYPE_EXTENDED_IRQ);
456 if (!res) {
457 return -ENODEV;
458 }
459
460 if (res->Data.ExtendedIrq.InterruptCount > irq_res->irq_vector_max) {
461 return -ENOMEM;
462 }
463
464 irq_res->irq_vector_max = res->Data.ExtendedIrq.InterruptCount;
465 for (int i = 0; i < irq_res->irq_vector_max; i++) {
466 irq_res->irqs[i] = (uint16_t)res->Data.ExtendedIrq.Interrupts[i];
467 }
468
469 irq_res->flags = arch_acpi_encode_irq_flags(res->Data.ExtendedIrq.Polarity,
470 res->Data.ExtendedIrq.Triggering);
471 } else {
472 if (res->Data.Irq.InterruptCount > irq_res->irq_vector_max) {
473 return -ENOMEM;
474 }
475
476 irq_res->irq_vector_max = res->Data.Irq.InterruptCount;
477 for (int i = 0; i < irq_res->irq_vector_max; i++) {
478 irq_res->irqs[i] = (uint16_t)res->Data.Irq.Interrupts[i];
479 }
480
481 irq_res->flags = arch_acpi_encode_irq_flags(res->Data.ExtendedIrq.Polarity,
482 res->Data.ExtendedIrq.Triggering);
483 }
484
485 return 0;
486 }
487
acpi_device_mmio_get(struct acpi_dev * child_dev,struct acpi_mmio_resource * mmio_res)488 int acpi_device_mmio_get(struct acpi_dev *child_dev, struct acpi_mmio_resource *mmio_res)
489 {
490 ACPI_RESOURCE *res = child_dev->res_lst;
491 struct acpi_reg_base *reg_base = mmio_res->reg_base;
492 int mmio_cnt = 0;
493
494 do {
495 if (!res->Length) {
496 LOG_DBG("Found Acpi resource with zero length!");
497 break;
498 }
499
500 switch (res->Type) {
501 case ACPI_RESOURCE_TYPE_IO:
502 reg_base[mmio_cnt].type = ACPI_RES_TYPE_IO;
503 reg_base[mmio_cnt].port = (uint32_t)res->Data.Io.Minimum;
504 reg_base[mmio_cnt++].length = res->Data.Io.AddressLength;
505 break;
506
507 case ACPI_RESOURCE_TYPE_FIXED_IO:
508 reg_base[mmio_cnt].type = ACPI_RES_TYPE_IO;
509 reg_base[mmio_cnt].port = (uint32_t)res->Data.FixedIo.Address;
510 reg_base[mmio_cnt++].length = res->Data.FixedIo.AddressLength;
511 break;
512
513 case ACPI_RESOURCE_TYPE_MEMORY24:
514 reg_base[mmio_cnt].type = ACPI_RES_TYPE_MEM;
515 reg_base[mmio_cnt].mmio = (uintptr_t)res->Data.Memory24.Minimum;
516 reg_base[mmio_cnt++].length = res->Data.Memory24.AddressLength;
517 break;
518
519 case ACPI_RESOURCE_TYPE_MEMORY32:
520 reg_base[mmio_cnt].type = ACPI_RES_TYPE_MEM;
521 reg_base[mmio_cnt].mmio = (uintptr_t)res->Data.Memory32.Minimum;
522 reg_base[mmio_cnt++].length = res->Data.Memory32.AddressLength;
523 break;
524
525 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
526 reg_base[mmio_cnt].type = ACPI_RES_TYPE_MEM;
527 reg_base[mmio_cnt].mmio = (uintptr_t)res->Data.FixedMemory32.Address;
528 reg_base[mmio_cnt++].length = res->Data.FixedMemory32.AddressLength;
529 break;
530 }
531
532 res = ACPI_NEXT_RESOURCE(res);
533 if (mmio_cnt >= mmio_res->mmio_max &&
534 res->Type != ACPI_RESOURCE_TYPE_END_TAG) {
535 return -ENOMEM;
536 }
537 } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG);
538
539 if (!mmio_cnt) {
540 return -ENODEV;
541 }
542
543 mmio_res->mmio_max = mmio_cnt;
544
545 return 0;
546 }
547
acpi_res_type(ACPI_RESOURCE * res)548 static int acpi_res_type(ACPI_RESOURCE *res)
549 {
550 int type;
551
552 switch (res->Type) {
553 case ACPI_RESOURCE_TYPE_IO:
554 type = ACPI_RESOURCE_TYPE_IO;
555 break;
556 case ACPI_RESOURCE_TYPE_FIXED_IO:
557 type = ACPI_RESOURCE_TYPE_FIXED_IO;
558 break;
559 case ACPI_RESOURCE_TYPE_MEMORY24:
560 type = ACPI_RESOURCE_TYPE_MEMORY24;
561 break;
562 case ACPI_RESOURCE_TYPE_MEMORY32:
563 type = ACPI_RESOURCE_TYPE_MEMORY32;
564 break;
565 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
566 type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32;
567 break;
568 case ACPI_RESOURCE_TYPE_ADDRESS16:
569 type = ACPI_RESOURCE_TYPE_ADDRESS16;
570 break;
571 case ACPI_RESOURCE_TYPE_ADDRESS32:
572 type = ACPI_RESOURCE_TYPE_ADDRESS32;
573 break;
574 case ACPI_RESOURCE_TYPE_ADDRESS64:
575 type = ACPI_RESOURCE_TYPE_ADDRESS64;
576 break;
577 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
578 type = ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64;
579 break;
580 default:
581 type = ACPI_RESOURCE_TYPE_MAX;
582 }
583
584 return type;
585 }
586
acpi_device_type_get(ACPI_RESOURCE * res)587 int acpi_device_type_get(ACPI_RESOURCE *res)
588 {
589 int type = ACPI_RESOURCE_TYPE_MAX;
590
591 do {
592 if (!res->Length) {
593 LOG_ERR("Error: zero length found!");
594 break;
595 }
596 type = acpi_res_type(res);
597 if (type != ACPI_RESOURCE_TYPE_MAX) {
598 break;
599 }
600 res = ACPI_NEXT_RESOURCE(res);
601 } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG);
602
603 return type;
604 }
605
acpi_device_get(const char * hid,const char * uid)606 struct acpi_dev *acpi_device_get(const char *hid, const char *uid)
607 {
608 struct acpi_dev *child_dev;
609 int i = 0;
610
611 LOG_DBG("");
612
613 if (check_init_status()) {
614 return NULL;
615 }
616
617 do {
618 child_dev = &acpi.child_dev[i];
619 if (!child_dev->path) {
620 LOG_DBG("NULL device path found");
621 continue;
622 }
623
624 if (!child_dev->res_lst || !child_dev->dev_info ||
625 !child_dev->dev_info->HardwareId.Length) {
626 continue;
627 }
628
629 if (!strcmp(hid, child_dev->dev_info->HardwareId.String)) {
630 if (uid && child_dev->dev_info->UniqueId.Length) {
631 if (!strcmp(child_dev->dev_info->UniqueId.String, uid)) {
632 return child_dev;
633 }
634 } else {
635 return child_dev;
636 }
637 }
638 } while (i++ < acpi.num_dev);
639
640 return NULL;
641 }
642
acpi_device_by_index_get(int index)643 struct acpi_dev *acpi_device_by_index_get(int index)
644 {
645 return index < acpi.num_dev ? &acpi.child_dev[index] : NULL;
646 }
647
acpi_table_get(char * signature,int inst)648 void *acpi_table_get(char *signature, int inst)
649 {
650 ACPI_STATUS status;
651 ACPI_TABLE_HEADER *table;
652
653 if (!acpi.early_init) {
654 status = acpi_early_init();
655 if (status) {
656 LOG_ERR("ACPI early init failed");
657 return NULL;
658 }
659 }
660
661 status = AcpiGetTable(signature, inst, &table);
662 if (ACPI_FAILURE(status)) {
663 LOG_ERR("ACPI get table failed: %d", status);
664 return NULL;
665 }
666
667 return (void *)table;
668 }
669
acpi_get_subtable_entry_num(int type,ACPI_SUBTABLE_HEADER * subtable,uintptr_t offset,uintptr_t base,uint32_t madt_len)670 static uint32_t acpi_get_subtable_entry_num(int type, ACPI_SUBTABLE_HEADER *subtable,
671 uintptr_t offset, uintptr_t base, uint32_t madt_len)
672 {
673 uint32_t subtable_cnt = 0;
674
675 while (offset < madt_len) {
676 if (type == subtable->Type) {
677 subtable_cnt++;
678 }
679 offset += subtable->Length;
680 subtable = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, base, offset);
681
682 if (!subtable->Length) {
683 break;
684 }
685 }
686
687 return subtable_cnt;
688 }
689
acpi_madt_entry_get(int type,ACPI_SUBTABLE_HEADER ** tables,int * num_inst)690 int acpi_madt_entry_get(int type, ACPI_SUBTABLE_HEADER **tables, int *num_inst)
691 {
692 ACPI_TABLE_HEADER *madt = acpi_table_get("APIC", 0);
693 uintptr_t base = POINTER_TO_UINT(madt);
694 uintptr_t offset = sizeof(ACPI_TABLE_MADT);
695 ACPI_SUBTABLE_HEADER *subtable;
696
697 if (!madt) {
698 return -EIO;
699 }
700
701 subtable = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, base, offset);
702 while (offset < madt->Length) {
703
704 if (type == subtable->Type) {
705 *tables = subtable;
706 *num_inst = acpi_get_subtable_entry_num(type, subtable, offset, base,
707 madt->Length);
708 return 0;
709 }
710
711 offset += subtable->Length;
712 subtable = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, base, offset);
713 }
714
715 return -ENODEV;
716 }
717
acpi_dmar_entry_get(enum AcpiDmarType type,ACPI_SUBTABLE_HEADER ** tables)718 int acpi_dmar_entry_get(enum AcpiDmarType type, ACPI_SUBTABLE_HEADER **tables)
719 {
720 struct acpi_table_dmar *dmar = acpi_table_get("DMAR", 0);
721 uintptr_t base = POINTER_TO_UINT(dmar);
722 uintptr_t offset = sizeof(ACPI_TABLE_DMAR);
723 ACPI_DMAR_HEADER *subtable;
724
725 if (!dmar) {
726 LOG_ERR("error on get DMAR table");
727 return -EIO;
728 }
729
730 subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, base, offset);
731 while (offset < dmar->Header.Length) {
732 if (type == subtable->Type) {
733 *tables = (struct acpi_subtable_header *)subtable;
734 return 0;
735 }
736 offset += subtable->Length;
737 subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, base, offset);
738 }
739
740 return -ENODEV;
741 }
742
acpi_dmar_foreach_subtable(ACPI_TABLE_DMAR * dmar,dmar_foreach_subtable_func_t func,void * arg)743 void acpi_dmar_foreach_subtable(ACPI_TABLE_DMAR *dmar,
744 dmar_foreach_subtable_func_t func, void *arg)
745 {
746 uint16_t length = dmar->Header.Length;
747 uintptr_t offset = sizeof(ACPI_TABLE_DMAR);
748
749 __ASSERT_NO_MSG(length >= offset);
750
751 while (offset < length) {
752 ACPI_DMAR_HEADER *subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, dmar, offset);
753
754 __ASSERT_NO_MSG(subtable->Length >= sizeof(*subtable));
755 __ASSERT_NO_MSG(subtable->Length <= length - offset);
756
757 func(subtable, arg);
758
759 offset += subtable->Length;
760 }
761 }
762
acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT * hu,dmar_foreach_devscope_func_t func,void * arg)763 void acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT *hu,
764 dmar_foreach_devscope_func_t func, void *arg)
765 {
766 uint16_t length = hu->Header.Length;
767 uintptr_t offset = sizeof(ACPI_DMAR_HARDWARE_UNIT);
768
769 __ASSERT_NO_MSG(length >= offset);
770
771 while (offset < length) {
772 ACPI_DMAR_DEVICE_SCOPE *devscope = ACPI_ADD_PTR(ACPI_DMAR_DEVICE_SCOPE,
773 hu, offset);
774
775 __ASSERT_NO_MSG(devscope->Length >= sizeof(*devscope));
776 __ASSERT_NO_MSG(devscope->Length <= length - offset);
777
778 func(devscope, arg);
779
780 offset += devscope->Length;
781 }
782 }
783
devscope_handler(ACPI_DMAR_DEVICE_SCOPE * devscope,void * arg)784 static void devscope_handler(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg)
785 {
786 ACPI_DMAR_PCI_PATH *dev_path;
787 union acpi_dmar_id pci_path;
788
789 ARG_UNUSED(arg); /* may be unused */
790
791 if (devscope->EntryType == ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
792 uint16_t *ioapic_id = arg;
793
794 dev_path = ACPI_ADD_PTR(ACPI_DMAR_PCI_PATH, devscope,
795 sizeof(ACPI_DMAR_DEVICE_SCOPE));
796
797 /* Get first entry */
798 pci_path.bits.bus = devscope->Bus;
799 pci_path.bits.device = dev_path->Device;
800 pci_path.bits.function = dev_path->Function;
801
802 *ioapic_id = pci_path.raw;
803 }
804 }
805
subtable_handler(ACPI_DMAR_HEADER * subtable,void * arg)806 static void subtable_handler(ACPI_DMAR_HEADER *subtable, void *arg)
807 {
808 ARG_UNUSED(arg); /* may be unused */
809
810 if (subtable->Type == ACPI_DMAR_TYPE_HARDWARE_UNIT) {
811 ACPI_DMAR_HARDWARE_UNIT *hu;
812
813 hu = CONTAINER_OF(subtable, ACPI_DMAR_HARDWARE_UNIT, Header);
814 acpi_dmar_foreach_devscope(hu, devscope_handler, arg);
815 }
816 }
817
acpi_dmar_ioapic_get(uint16_t * ioapic_id)818 int acpi_dmar_ioapic_get(uint16_t *ioapic_id)
819 {
820 ACPI_TABLE_DMAR *dmar = acpi_table_get("DMAR", 0);
821 uint16_t found_ioapic = USHRT_MAX;
822
823 if (dmar == NULL) {
824 return -ENODEV;
825 }
826
827 acpi_dmar_foreach_subtable(dmar, subtable_handler, &found_ioapic);
828 if (found_ioapic != USHRT_MAX) {
829 *ioapic_id = found_ioapic;
830 return 0;
831 }
832
833 return -ENOENT;
834 }
835
acpi_drhd_get(enum AcpiDmarScopeType scope,ACPI_DMAR_DEVICE_SCOPE * dev_scope,union acpi_dmar_id * dmar_id,int * num_inst,int max_inst)836 int acpi_drhd_get(enum AcpiDmarScopeType scope, ACPI_DMAR_DEVICE_SCOPE *dev_scope,
837 union acpi_dmar_id *dmar_id, int *num_inst, int max_inst)
838 {
839 uintptr_t offset = sizeof(ACPI_DMAR_HARDWARE_UNIT);
840 uint32_t i = 0;
841 ACPI_DMAR_HEADER *drdh;
842 ACPI_DMAR_DEVICE_SCOPE *subtable;
843 ACPI_DMAR_PCI_PATH *dev_path;
844 int ret;
845 uintptr_t base;
846 int scope_size;
847
848 ret = acpi_dmar_entry_get(ACPI_DMAR_TYPE_HARDWARE_UNIT,
849 (ACPI_SUBTABLE_HEADER **)&drdh);
850 if (ret) {
851 LOG_ERR("Error on retrieve DMAR table");
852 return ret;
853 }
854
855 scope_size = drdh->Length - sizeof(ACPI_DMAR_HARDWARE_UNIT);
856 base = (uintptr_t)((uintptr_t)drdh + offset);
857
858 offset = 0;
859
860 while (scope_size) {
861 int num_path;
862
863 subtable = ACPI_ADD_PTR(ACPI_DMAR_DEVICE_SCOPE, base, offset);
864 if (!subtable->Length) {
865 break;
866 }
867
868 if (scope == subtable->EntryType) {
869 num_path = (subtable->Length - 6u) / 2u;
870 dev_path = ACPI_ADD_PTR(ACPI_DMAR_PCI_PATH, subtable,
871 sizeof(ACPI_DMAR_DEVICE_SCOPE));
872
873 while (num_path--) {
874 if (i >= max_inst) {
875 LOG_ERR("DHRD not enough buffer size");
876 return -ENOBUFS;
877 }
878 dmar_id[i].bits.bus = subtable->Bus;
879 dmar_id[i].bits.device = dev_path[i].Device;
880 dmar_id[i].bits.function = dev_path[i].Function;
881 i++;
882 }
883 break;
884 }
885
886 offset += subtable->Length;
887
888 if (scope_size < subtable->Length) {
889 break;
890 }
891 scope_size -= subtable->Length;
892 }
893
894 *num_inst = i;
895 if (!i) {
896 LOG_ERR("Error on retrieve DRHD Info");
897 return -ENODEV;
898 }
899
900 if (dev_scope && subtable) {
901 memcpy(dev_scope, subtable, sizeof(struct acpi_dmar_device_scope));
902 }
903
904 return 0;
905 }
906
907 #define ACPI_CPU_FLAGS_ENABLED 0x01u
908
acpi_local_apic_get(int cpu_num)909 ACPI_MADT_LOCAL_APIC *acpi_local_apic_get(int cpu_num)
910 {
911 ACPI_MADT_LOCAL_APIC *lapic;
912 int cpu_cnt;
913 int idx;
914
915 if (acpi_madt_entry_get(ACPI_MADT_TYPE_LOCAL_APIC, (ACPI_SUBTABLE_HEADER **)&lapic,
916 &cpu_cnt)) {
917 /* Error on MAD table. */
918 return NULL;
919 }
920
921 for (idx = 0; cpu_num >= 0 && idx < cpu_cnt; idx++) {
922 if (lapic[idx].LapicFlags & ACPI_CPU_FLAGS_ENABLED) {
923 if (cpu_num == 0) {
924 return &lapic[idx];
925 }
926
927 cpu_num--;
928 }
929 }
930
931 return NULL;
932 }
933
acpi_invoke_method(char * path,ACPI_OBJECT_LIST * arg_list,ACPI_OBJECT * ret_obj)934 int acpi_invoke_method(char *path, ACPI_OBJECT_LIST *arg_list, ACPI_OBJECT *ret_obj)
935 {
936 ACPI_STATUS status;
937 ACPI_BUFFER ret_buff;
938
939 ret_buff.Length = sizeof(*ret_obj);
940 ret_buff.Pointer = ret_obj;
941
942 status = AcpiEvaluateObject(NULL, path, arg_list, &ret_buff);
943 if (ACPI_FAILURE(status)) {
944 LOG_ERR("error While executing %s method: %d", path, status);
945 return -EIO;
946 }
947
948 return 0;
949 }
950
acpi_init(void)951 static int acpi_init(void)
952 {
953 ACPI_STATUS status;
954
955 LOG_DBG("");
956
957 /* For debug version only */
958 ACPI_DEBUG_INITIALIZE();
959
960 status = initialize_acpica();
961 if (ACPI_FAILURE(status)) {
962 LOG_ERR("Error in ACPI init:%d", status);
963 goto exit;
964 }
965
966 /* Enable IO APIC mode */
967 status = acpi_enable_pic_mode();
968 if (ACPI_FAILURE(status)) {
969 LOG_WRN("Error in enable pic mode acpi method:%d", status);
970 }
971
972 acpi_enum_devices();
973
974 exit:
975 return status;
976 }
977