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