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 struct acpi {
18 	struct acpi_dev child_dev[CONFIG_ACPI_DEV_MAX];
19 	int num_dev;
20 	ACPI_PCI_ROUTING_TABLE pci_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY];
21 	bool early_init;
22 	int status;
23 };
24 
25 static struct acpi bus_ctx = {
26 	.status = AE_NOT_CONFIGURED,
27 };
28 
29 static ACPI_TABLE_DESC acpi_tables[CONFIG_ACPI_MAX_INIT_TABLES];
30 
31 static int acpi_init(void);
32 
check_init_status(void)33 static int check_init_status(void)
34 {
35 	int ret;
36 
37 	if (ACPI_SUCCESS(bus_ctx.status)) {
38 		return 0;
39 	}
40 
41 	if (bus_ctx.status == AE_NOT_CONFIGURED) {
42 		ret = acpi_init();
43 	} else {
44 		LOG_ERR("ACPI init was not success\n");
45 		ret = -EIO;
46 	}
47 	return ret;
48 }
49 
notify_handler(ACPI_HANDLE device,UINT32 value,void * ctx)50 static void notify_handler(ACPI_HANDLE device, UINT32 value, void *ctx)
51 {
52 	ACPI_INFO(("Received a notify 0x%X", value));
53 }
54 
region_handler(UINT32 Function,ACPI_PHYSICAL_ADDRESS address,UINT32 bit_width,UINT64 * value,void * handler_ctx,void * region_ctx)55 static ACPI_STATUS region_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS address, UINT32 bit_width,
56 				  UINT64 *value, void *handler_ctx, void *region_ctx)
57 {
58 	return AE_OK;
59 }
60 
region_init(ACPI_HANDLE RegionHandle,UINT32 Function,void * handler_ctx,void ** region_ctx)61 static ACPI_STATUS region_init(ACPI_HANDLE RegionHandle, UINT32 Function, void *handler_ctx,
62 			       void **region_ctx)
63 {
64 	if (Function == ACPI_REGION_DEACTIVATE) {
65 		*region_ctx = NULL;
66 	} else {
67 		*region_ctx = RegionHandle;
68 	}
69 
70 	return AE_OK;
71 }
72 
install_handlers(void)73 static ACPI_STATUS install_handlers(void)
74 {
75 	ACPI_STATUS status;
76 
77 	/* Install global notify handler */
78 	status = AcpiInstallNotifyHandler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, notify_handler,
79 					  NULL);
80 	if (ACPI_FAILURE(status)) {
81 		ACPI_EXCEPTION((AE_INFO, status, "While installing Notify handler"));
82 		goto exit;
83 	}
84 
85 	status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_SYSTEM_MEMORY,
86 						region_handler, region_init, NULL);
87 	if (ACPI_FAILURE(status)) {
88 		ACPI_EXCEPTION((AE_INFO, status, "While installing an OpRegion handler"));
89 	}
90 exit:
91 
92 	return status;
93 }
94 
initialize_acpica(void)95 static ACPI_STATUS initialize_acpica(void)
96 {
97 	ACPI_STATUS status;
98 
99 	/* Initialize the ACPI subsystem */
100 	status = AcpiInitializeSubsystem();
101 	if (ACPI_FAILURE(status)) {
102 		ACPI_EXCEPTION((AE_INFO, status, "While initializing ACPI"));
103 		goto exit;
104 	}
105 
106 	/* Initialize the ACPI Table Manager and get all ACPI tables */
107 	if (!bus_ctx.early_init) {
108 		status = AcpiInitializeTables(NULL, 16, FALSE);
109 	} else {
110 		/* Copy the root table list to dynamic memory if already initialized */
111 		status = AcpiReallocateRootTable();
112 	}
113 	if (ACPI_FAILURE(status)) {
114 		ACPI_EXCEPTION((AE_INFO, status, "While initializing Table Manager"));
115 		goto exit;
116 	}
117 
118 	/* Initialize the ACPI hardware */
119 	status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
120 	if (ACPI_FAILURE(status)) {
121 		ACPI_EXCEPTION((AE_INFO, status, "While enabling ACPI"));
122 		goto exit;
123 	}
124 
125 	/* Install local handlers */
126 	status = install_handlers();
127 	if (ACPI_FAILURE(status)) {
128 		ACPI_EXCEPTION((AE_INFO, status, "While installing handlers"));
129 		goto exit;
130 	}
131 
132 	/* Create the ACPI namespace from ACPI tables */
133 	status = AcpiLoadTables();
134 	if (ACPI_FAILURE(status)) {
135 		ACPI_EXCEPTION((AE_INFO, status, "While loading ACPI tables"));
136 		goto exit;
137 	}
138 
139 	/* Complete the ACPI namespace object initialization */
140 	status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
141 	if (ACPI_FAILURE(status)) {
142 		ACPI_EXCEPTION((AE_INFO, status, "While initializing ACPI objects"));
143 	}
144 exit:
145 
146 	return status;
147 }
148 
acpi_name_lookup(char * name)149 static ACPI_NAMESPACE_NODE *acpi_name_lookup(char *name)
150 {
151 	char *path;
152 	ACPI_STATUS status;
153 	ACPI_NAMESPACE_NODE *node;
154 
155 	LOG_DBG("");
156 
157 	status = AcpiNsInternalizeName(name, &path);
158 	if (ACPI_FAILURE(status)) {
159 		LOG_ERR("Invalid namestring: %s", name);
160 		return NULL;
161 	}
162 
163 	status = AcpiNsLookup(NULL, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
164 			      ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node);
165 	if (ACPI_FAILURE(status)) {
166 		LOG_ERR("Could not locate name: %s, %d", name, status);
167 		node = NULL;
168 	}
169 
170 	ACPI_FREE(path);
171 	return node;
172 }
173 
acpi_evaluate_method(char * bus_name,char * method)174 static ACPI_NAMESPACE_NODE *acpi_evaluate_method(char *bus_name, char *method)
175 {
176 	ACPI_NAMESPACE_NODE *node;
177 	ACPI_NAMESPACE_NODE *handle;
178 	ACPI_NAMESPACE_NODE *prt_node = NULL;
179 
180 	LOG_DBG("%s", bus_name);
181 
182 	handle = acpi_name_lookup(bus_name);
183 	if (!handle) {
184 		LOG_ERR("No ACPI node with given name: %s", bus_name);
185 		goto exit;
186 	}
187 
188 	if (handle->Type != ACPI_TYPE_DEVICE) {
189 		LOG_ERR("No ACPI node foud with given name: %s", bus_name);
190 		goto exit;
191 	}
192 
193 	node = ACPI_CAST_PTR(ACPI_NAMESPACE_NODE, handle);
194 
195 	(void)AcpiGetHandle(node, method, ACPI_CAST_PTR(ACPI_HANDLE, &prt_node));
196 
197 	if (!prt_node) {
198 		LOG_ERR("No entry for the ACPI node with given name: %s", bus_name);
199 		goto exit;
200 	}
201 	return node;
202 exit:
203 	return NULL;
204 }
205 
acpi_enable_pic_mode(void)206 static ACPI_STATUS acpi_enable_pic_mode(void)
207 {
208 	ACPI_STATUS status;
209 	ACPI_OBJECT_LIST arg_list;
210 	ACPI_OBJECT arg[1];
211 
212 	arg_list.Count = 1;
213 	arg_list.Pointer = arg;
214 
215 	arg[0].Type = ACPI_TYPE_INTEGER;
216 	arg[0].Integer.Value = 1;
217 
218 	status = AcpiEvaluateObject(NULL, "\\_PIC", &arg_list, NULL);
219 	if (ACPI_FAILURE(status)) {
220 		LOG_WRN("error While executing \\_pic method: %d", status);
221 	}
222 
223 	return status;
224 }
225 
acpi_get_irq_table(struct acpi * bus,char * bus_name,ACPI_PCI_ROUTING_TABLE * rt_table,uint32_t rt_size)226 static int acpi_get_irq_table(struct acpi *bus, char *bus_name,
227 				ACPI_PCI_ROUTING_TABLE *rt_table, uint32_t rt_size)
228 {
229 	ACPI_BUFFER rt_buffer;
230 	ACPI_NAMESPACE_NODE *node;
231 	int status;
232 
233 	LOG_DBG("%s", bus_name);
234 
235 	node = acpi_evaluate_method(bus_name, METHOD_NAME__PRT);
236 	if (!node) {
237 		LOG_ERR("Evaluation failed for given device: %s", bus_name);
238 		return -ENODEV;
239 	}
240 
241 	rt_buffer.Pointer = rt_table;
242 	rt_buffer.Length = ACPI_DEBUG_BUFFER_SIZE;
243 
244 	status = AcpiGetIrqRoutingTable(node, &rt_buffer);
245 	if (ACPI_FAILURE(status)) {
246 		LOG_ERR("unable to retrieve IRQ Routing Table: %s", bus_name);
247 		return -EIO;
248 	}
249 
250 	for (int i = 0; i < CONFIG_ACPI_MAX_PRT_ENTRY; i++) {
251 		if (!bus->pci_prt_table[i].SourceIndex) {
252 			break;
253 		}
254 		if (IS_ENABLED(CONFIG_X86_64)) {
255 			/* mark the PRT irq numbers as reserved. */
256 			arch_irq_set_used(bus->pci_prt_table[i].SourceIndex);
257 		}
258 	}
259 
260 	return 0;
261 }
262 
acpi_retrieve_legacy_irq(struct acpi * bus)263 static int acpi_retrieve_legacy_irq(struct acpi *bus)
264 {
265 	/* TODO: assume platform have only one PCH with single PCI bus (bus 0). */
266 	return acpi_get_irq_table(bus, "_SB.PC00", bus->pci_prt_table, sizeof(bus->pci_prt_table));
267 }
268 
dev_resource_enum_callback(ACPI_HANDLE obj_handle,UINT32 level,void * ctx,void ** ret_value)269 static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 level, void *ctx,
270 					      void **ret_value)
271 {
272 	ACPI_NAMESPACE_NODE *node;
273 	ACPI_BUFFER rt_buffer;
274 	struct acpi *bus = (struct acpi *)ctx;
275 	struct acpi_dev *child_dev;
276 
277 	node = ACPI_CAST_PTR(ACPI_NAMESPACE_NODE, obj_handle);
278 	char *path_name;
279 	int status;
280 	ACPI_DEVICE_INFO *dev_info;
281 
282 	LOG_DBG("%s %p\n", __func__, node);
283 
284 	/* get device info such as HID, Class ID etc. */
285 	status = AcpiGetObjectInfo(obj_handle, &dev_info);
286 	if (ACPI_FAILURE(status)) {
287 		LOG_ERR("AcpiGetObjectInfo failed: %s", AcpiFormatException(status));
288 		goto exit;
289 	}
290 
291 	if (bus->num_dev >= CONFIG_ACPI_DEV_MAX) {
292 		return AE_NO_MEMORY;
293 	}
294 
295 	child_dev = (struct acpi_dev *)&bus->child_dev[bus->num_dev++];
296 	child_dev->handle = obj_handle;
297 	child_dev->dev_info = dev_info;
298 
299 	path_name = AcpiNsGetNormalizedPathname(node, TRUE);
300 	if (!path_name) {
301 		LOG_ERR("No memory for path_name\n");
302 		goto exit;
303 	} else {
304 		LOG_DBG("Device path: %s\n", path_name);
305 		child_dev->path = path_name;
306 	}
307 
308 	rt_buffer.Pointer = NULL;
309 	rt_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
310 
311 	status = AcpiGetCurrentResources(node, &rt_buffer);
312 	if (ACPI_FAILURE(status)) {
313 		LOG_DBG("AcpiGetCurrentResources failed: %s", AcpiFormatException(status));
314 	} else {
315 		child_dev->res_lst = rt_buffer.Pointer;
316 	}
317 
318 exit:
319 
320 	return status;
321 }
322 
acpi_enum_devices(struct acpi * bus)323 static int acpi_enum_devices(struct acpi *bus)
324 {
325 	LOG_DBG("");
326 
327 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
328 			  dev_resource_enum_callback, NULL, bus, NULL);
329 
330 	return 0;
331 }
332 
acpi_init(void)333 static int acpi_init(void)
334 {
335 	int status;
336 
337 	LOG_DBG("");
338 
339 	if (bus_ctx.status != AE_NOT_CONFIGURED) {
340 		LOG_DBG("acpi init already done");
341 		return bus_ctx.status;
342 	}
343 
344 	/* For debug version only */
345 	ACPI_DEBUG_INITIALIZE();
346 
347 	status = initialize_acpica();
348 	if (ACPI_FAILURE(status)) {
349 		LOG_ERR("Error in ACPI init:%d", status);
350 		goto exit;
351 	}
352 
353 	/* Enable IO APIC mode */
354 	status = acpi_enable_pic_mode();
355 	if (ACPI_FAILURE(status)) {
356 		LOG_WRN("Error in enable pic mode acpi method:%d", status);
357 	}
358 
359 	status = acpi_retrieve_legacy_irq(&bus_ctx);
360 	if (status) {
361 		LOG_ERR("Error in retrieve legacy interrupt info:%d", status);
362 		goto exit;
363 	}
364 
365 	acpi_enum_devices(&bus_ctx);
366 
367 exit:
368 	bus_ctx.status = status;
369 
370 	return status;
371 }
372 
acpi_early_init(void)373 static int acpi_early_init(void)
374 {
375 	ACPI_STATUS status;
376 
377 	LOG_DBG("");
378 
379 	if (bus_ctx.early_init) {
380 		LOG_DBG("acpi early init already done");
381 		return 0;
382 	}
383 
384 	status = AcpiInitializeTables(acpi_tables, CONFIG_ACPI_MAX_INIT_TABLES, TRUE);
385 	if (ACPI_FAILURE(status)) {
386 		LOG_ERR("Error in acpi table init:%d", status);
387 		return -EIO;
388 	}
389 
390 	bus_ctx.early_init = true;
391 
392 	return 0;
393 }
394 
acpi_legacy_irq_get(pcie_bdf_t bdf)395 uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf)
396 {
397 	uint32_t slot = PCIE_BDF_TO_DEV(bdf), pin;
398 
399 	LOG_DBG("");
400 
401 	if (check_init_status()) {
402 		return UINT_MAX;
403 	}
404 
405 	pin = (pcie_conf_read(bdf, PCIE_CONF_INTR) >> 8) & 0x3;
406 
407 	LOG_DBG("Device irq info: slot:%d pin:%d", slot, pin);
408 
409 	for (int i = 0; i < CONFIG_ACPI_MAX_PRT_ENTRY; i++) {
410 		if (((bus_ctx.pci_prt_table[i].Address >> 16) & 0xffff) == slot &&
411 		    bus_ctx.pci_prt_table[i].Pin + 1 == pin) {
412 			LOG_DBG("[%d]Device irq info: slot:%d pin:%d irq:%d", i, slot, pin,
413 				bus_ctx.pci_prt_table[i].SourceIndex);
414 			return bus_ctx.pci_prt_table[i].SourceIndex;
415 		}
416 	}
417 
418 	return UINT_MAX;
419 }
420 
acpi_current_resource_get(char * dev_name,ACPI_RESOURCE ** res)421 int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res)
422 {
423 	ACPI_BUFFER rt_buffer;
424 	ACPI_NAMESPACE_NODE *node;
425 	int status;
426 
427 	LOG_DBG("%s", dev_name);
428 
429 	status = check_init_status();
430 	if (status) {
431 		return status;
432 	}
433 
434 	node = acpi_evaluate_method(dev_name, METHOD_NAME__CRS);
435 	if (!node) {
436 		LOG_ERR("Evaluation failed for given device: %s", dev_name);
437 		status = -ENOTSUP;
438 		goto exit;
439 	}
440 
441 	rt_buffer.Pointer = NULL;
442 	rt_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
443 
444 	status = AcpiGetCurrentResources(node, &rt_buffer);
445 	if (ACPI_FAILURE(status)) {
446 		LOG_ERR("AcpiGetCurrentResources failed: %s", AcpiFormatException(status));
447 		status = -ENOTSUP;
448 	} else {
449 		*res = rt_buffer.Pointer;
450 	}
451 
452 exit:
453 
454 	return status;
455 }
456 
acpi_possible_resource_get(char * dev_name,ACPI_RESOURCE ** res)457 int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res)
458 {
459 	ACPI_BUFFER rt_buffer;
460 	ACPI_NAMESPACE_NODE *node;
461 	int status;
462 
463 	LOG_DBG("%s", dev_name);
464 
465 	status = check_init_status();
466 	if (status) {
467 		return status;
468 	}
469 
470 	node = acpi_evaluate_method(dev_name, METHOD_NAME__PRS);
471 	if (!node) {
472 		LOG_ERR("Evaluation failed for given device: %s", dev_name);
473 		status = -ENOTSUP;
474 		goto exit;
475 	}
476 
477 	rt_buffer.Pointer = NULL;
478 	rt_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
479 
480 	AcpiGetPossibleResources(node, &rt_buffer);
481 	*res = rt_buffer.Pointer;
482 
483 exit:
484 
485 	return status;
486 }
487 
acpi_current_resource_free(ACPI_RESOURCE * res)488 int acpi_current_resource_free(ACPI_RESOURCE *res)
489 {
490 	ACPI_FREE(res);
491 
492 	return 0;
493 }
494 
acpi_get_irq_routing_table(char * bus_name,ACPI_PCI_ROUTING_TABLE * rt_table,size_t rt_size)495 int acpi_get_irq_routing_table(char *bus_name,
496 			       ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size)
497 {
498 	int ret;
499 
500 	ret = check_init_status();
501 	if (ret) {
502 		return ret;
503 	}
504 
505 	return acpi_get_irq_table(&bus_ctx, bus_name, rt_table, rt_size);
506 }
507 
acpi_resource_parse(ACPI_RESOURCE * res,int res_type)508 ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type)
509 {
510 	do {
511 		if (!res->Length) {
512 			LOG_DBG("Error: zero length found!\n");
513 			break;
514 		} else if (res->Type == res_type) {
515 			break;
516 		}
517 		res = ACPI_NEXT_RESOURCE(res);
518 	} while (res->Type != ACPI_RESOURCE_TYPE_END_TAG);
519 
520 	if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) {
521 		return NULL;
522 	}
523 
524 	return res;
525 }
526 
acpi_res_type(ACPI_RESOURCE * res)527 static int acpi_res_type(ACPI_RESOURCE *res)
528 {
529 	int type;
530 
531 	switch (res->Type) {
532 	case ACPI_RESOURCE_TYPE_IO:
533 		type = ACPI_RESOURCE_TYPE_IO;
534 		break;
535 	case ACPI_RESOURCE_TYPE_FIXED_IO:
536 		type = ACPI_RESOURCE_TYPE_FIXED_IO;
537 		break;
538 	case ACPI_RESOURCE_TYPE_MEMORY24:
539 		type = ACPI_RESOURCE_TYPE_MEMORY24;
540 		break;
541 	case ACPI_RESOURCE_TYPE_MEMORY32:
542 		type = ACPI_RESOURCE_TYPE_MEMORY32;
543 		break;
544 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
545 		type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32;
546 		break;
547 	case ACPI_RESOURCE_TYPE_ADDRESS16:
548 		type = ACPI_RESOURCE_TYPE_ADDRESS16;
549 		break;
550 	case ACPI_RESOURCE_TYPE_ADDRESS32:
551 		type = ACPI_RESOURCE_TYPE_ADDRESS32;
552 		break;
553 	case ACPI_RESOURCE_TYPE_ADDRESS64:
554 		type = ACPI_RESOURCE_TYPE_ADDRESS64;
555 		break;
556 	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
557 		type = ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64;
558 		break;
559 	default:
560 		type = ACPI_RESOURCE_TYPE_MAX;
561 	}
562 
563 	return type;
564 }
565 
acpi_device_type_get(ACPI_RESOURCE * res)566 int acpi_device_type_get(ACPI_RESOURCE *res)
567 {
568 	int type = ACPI_RESOURCE_TYPE_MAX;
569 
570 	do {
571 		if (!res->Length) {
572 			LOG_ERR("Error: zero length found!\n");
573 			break;
574 		}
575 		type = acpi_res_type(res);
576 		if (type != ACPI_RESOURCE_TYPE_MAX) {
577 			break;
578 		}
579 		res = ACPI_NEXT_RESOURCE(res);
580 	} while (res->Type != ACPI_RESOURCE_TYPE_END_TAG);
581 
582 	return type;
583 }
584 
acpi_device_get(char * hid,int inst)585 struct acpi_dev *acpi_device_get(char *hid, int inst)
586 {
587 	struct acpi_dev *child_dev;
588 	int i = 0, inst_id;
589 
590 	LOG_DBG("");
591 
592 	if (check_init_status()) {
593 		return NULL;
594 	}
595 
596 	do {
597 		child_dev = &bus_ctx.child_dev[i];
598 		if (!child_dev->path) {
599 			LOG_DBG("NULL device path found\n");
600 			continue;
601 		}
602 
603 		if (!child_dev->res_lst || !child_dev->dev_info ||
604 		    !child_dev->dev_info->HardwareId.Length) {
605 			continue;
606 		}
607 
608 		if (!strcmp(hid, child_dev->dev_info->HardwareId.String)) {
609 			if (child_dev->dev_info->UniqueId.Length) {
610 				inst_id = atoi(child_dev->dev_info->UniqueId.String);
611 				if (inst_id == inst) {
612 					return child_dev;
613 				}
614 			} else {
615 				return child_dev;
616 			}
617 		}
618 	} while (i++ < bus_ctx.num_dev);
619 
620 	return NULL;
621 }
622 
acpi_device_by_index_get(int index)623 struct acpi_dev *acpi_device_by_index_get(int index)
624 {
625 	return index < bus_ctx.num_dev ? &bus_ctx.child_dev[index] : NULL;
626 }
627 
acpi_table_get(char * signature,int inst)628 void *acpi_table_get(char *signature, int inst)
629 {
630 	int status;
631 	ACPI_TABLE_HEADER *table;
632 
633 	if (!bus_ctx.early_init) {
634 		status = acpi_early_init();
635 		if (status) {
636 			LOG_ERR("ACPI early init failed");
637 			return NULL;
638 		}
639 	}
640 
641 	status = AcpiGetTable(signature, inst, &table);
642 	if (ACPI_FAILURE(status)) {
643 		LOG_ERR("ACPI get table failed: %d", status);
644 		return NULL;
645 	}
646 
647 	return (void *)table;
648 }
649 
acpi_get_subtable_entry_num(int type,struct acpi_subtable_header * subtable,uintptr_t offset,uintptr_t base,uint32_t madt_len)650 static uint32_t acpi_get_subtable_entry_num(int type, struct acpi_subtable_header *subtable,
651 					    uintptr_t offset, uintptr_t base, uint32_t madt_len)
652 {
653 	uint32_t subtable_cnt = 0;
654 
655 	while (offset < madt_len) {
656 		if (type == subtable->Type) {
657 			subtable_cnt++;
658 		}
659 		offset += subtable->Length;
660 		subtable = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, base, offset);
661 
662 		if (!subtable->Length) {
663 			break;
664 		}
665 	}
666 
667 	return subtable_cnt;
668 }
669 
acpi_madt_entry_get(int type,struct acpi_subtable_header ** tables,int * num_inst)670 int acpi_madt_entry_get(int type, struct acpi_subtable_header **tables, int *num_inst)
671 {
672 	struct acpi_table_header *madt = acpi_table_get("APIC", 0);
673 	uintptr_t base = POINTER_TO_UINT(madt);
674 	uintptr_t offset = sizeof(ACPI_TABLE_MADT);
675 	struct acpi_subtable_header *subtable;
676 
677 	if (!madt) {
678 		return -EIO;
679 	}
680 
681 	subtable = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, base, offset);
682 	while (offset < madt->Length) {
683 
684 		if (type == subtable->Type) {
685 			*tables = subtable;
686 			*num_inst = acpi_get_subtable_entry_num(type, subtable, offset, base,
687 								madt->Length);
688 			return 0;
689 		}
690 
691 		offset += subtable->Length;
692 		subtable = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, base, offset);
693 	}
694 
695 	return -ENODEV;
696 }
697 
acpi_dmar_entry_get(enum AcpiDmarType type,struct acpi_subtable_header ** tables)698 int acpi_dmar_entry_get(enum AcpiDmarType type, struct acpi_subtable_header **tables)
699 {
700 	struct acpi_table_dmar *dmar = acpi_table_get("DMAR", 0);
701 	uintptr_t base = POINTER_TO_UINT(dmar);
702 	uintptr_t offset = sizeof(ACPI_TABLE_DMAR);
703 	struct acpi_dmar_header *subtable;
704 
705 	if (!dmar) {
706 		LOG_ERR("error on get DMAR table\n");
707 		return -EIO;
708 	}
709 
710 	subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, base, offset);
711 	while (offset < dmar->Header.Length) {
712 		if (type == subtable->Type) {
713 			*tables = (struct acpi_subtable_header *)subtable;
714 			return 0;
715 		}
716 		offset += subtable->Length;
717 		subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, base, offset);
718 	}
719 
720 	return -ENODEV;
721 }
722 
acpi_drhd_get(enum AcpiDmarScopeType scope,struct acpi_dmar_device_scope * dev_scope,union acpi_dmar_id * dmar_id,int * num_inst,int max_inst)723 int acpi_drhd_get(enum AcpiDmarScopeType scope, struct acpi_dmar_device_scope *dev_scope,
724 	union acpi_dmar_id *dmar_id, int *num_inst, int max_inst)
725 {
726 	uintptr_t offset = sizeof(ACPI_DMAR_HARDWARE_UNIT);
727 	uint32_t i = 0;
728 	struct acpi_dmar_header *drdh;
729 	struct acpi_dmar_device_scope *subtable;
730 	struct acpi_dmar_pci_path *dev_path;
731 	int ret;
732 	uintptr_t base;
733 	int scope_size;
734 
735 	ret = acpi_dmar_entry_get(ACPI_DMAR_TYPE_HARDWARE_UNIT,
736 				  (struct acpi_subtable_header **)&drdh);
737 	if (ret) {
738 		LOG_ERR("Error on retrieve DMAR table\n");
739 		return ret;
740 	}
741 
742 	scope_size = drdh->Length - sizeof(ACPI_DMAR_HARDWARE_UNIT);
743 	base = (uintptr_t)((uintptr_t)drdh + offset);
744 
745 	offset = 0;
746 
747 	while (scope_size) {
748 		int num_path;
749 
750 		subtable = ACPI_ADD_PTR(ACPI_DMAR_DEVICE_SCOPE, base, offset);
751 		if (!subtable->Length) {
752 			break;
753 		}
754 
755 		if (scope == subtable->EntryType) {
756 			num_path = (subtable->Length - 6u) / 2u;
757 			dev_path = ACPI_ADD_PTR(ACPI_DMAR_PCI_PATH, subtable,
758 				sizeof(ACPI_DMAR_DEVICE_SCOPE));
759 
760 			while (num_path--) {
761 				if (i >= max_inst) {
762 					LOG_ERR("DHRD not enough buffer size\n");
763 					return -ENOBUFS;
764 				}
765 				dmar_id[i].bits.bus = subtable->Bus;
766 				dmar_id[i].bits.device = dev_path[i].Device;
767 				dmar_id[i].bits.function = dev_path[i].Function;
768 				i++;
769 			}
770 			break;
771 		}
772 
773 		offset += subtable->Length;
774 
775 		if (scope_size < subtable->Length) {
776 			break;
777 		}
778 		scope_size -= subtable->Length;
779 	}
780 
781 	*num_inst = i;
782 	if (!i) {
783 		LOG_ERR("Error on retrieve DRHD Info\n");
784 		return -ENODEV;
785 	}
786 
787 	if (dev_scope && subtable) {
788 		memcpy(dev_scope, subtable, sizeof(struct acpi_dmar_device_scope));
789 	}
790 
791 	return 0;
792 }
793 
acpi_local_apic_get(uint32_t cpu_num)794 struct acpi_madt_local_apic *acpi_local_apic_get(uint32_t cpu_num)
795 {
796 	struct acpi_madt_local_apic *lapic;
797 	int cpu_cnt;
798 
799 	if (acpi_madt_entry_get(ACPI_MADT_TYPE_LOCAL_APIC, (ACPI_SUBTABLE_HEADER **)&lapic,
800 				&cpu_cnt)) {
801 		/* Error on MAD table. */
802 		return NULL;
803 	}
804 
805 	if ((cpu_num >= cpu_cnt) || !(lapic[cpu_num].LapicFlags & 1u)) {
806 		/* Proccessor not enabled. */
807 		return NULL;
808 	}
809 
810 	return &lapic[cpu_num];
811 }
812