1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  * Copyright (c) 2019 Intel Corp.
4  */
5 
6 #include <zephyr/kernel.h>
7 #include <zephyr/acpi/acpi.h>
8 
get_dmar_scope_type(int type)9 static const char *get_dmar_scope_type(int type)
10 {
11 	switch (type) {
12 	case ACPI_DMAR_SCOPE_TYPE_ENDPOINT:
13 		return "PCI Endpoint";
14 	case ACPI_DMAR_SCOPE_TYPE_BRIDGE:
15 		return "PCI Sub-hierarchy";
16 	case ACPI_DMAR_SCOPE_TYPE_IOAPIC:
17 		return "IOAPIC";
18 	case ACPI_DMAR_SCOPE_TYPE_HPET:
19 		return "MSI Capable HPET";
20 	case ACPI_DMAR_SCOPE_TYPE_NAMESPACE:
21 		return "ACPI name-space enumerated";
22 	default:
23 		return "unknown";
24 	}
25 }
26 
dmar_devsope_handler(ACPI_DMAR_DEVICE_SCOPE * devscope,void * arg)27 static void dmar_devsope_handler(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg)
28 {
29 	ARG_UNUSED(arg);
30 
31 	printk("\t\t\t. Scope type %s\n", get_dmar_scope_type(devscope->EntryType));
32 	printk("\t\t\t. Enumeration ID %u\n", devscope->EnumerationId);
33 
34 	if (devscope->EntryType < ACPI_DMAR_SCOPE_TYPE_RESERVED) {
35 		ACPI_DMAR_PCI_PATH *devpath;
36 		int num_path = (devscope->Length - 6u) / 2u;
37 		int i = 0;
38 
39 		devpath = ACPI_ADD_PTR(ACPI_DMAR_PCI_PATH, devscope,
40 				       sizeof(ACPI_DMAR_DEVICE_SCOPE));
41 
42 		while (num_path--) {
43 			printk("\t\t\t. PCI Path %02x:%02x.%02x\n", devscope->Bus,
44 			       devpath[i].Device, devpath[i].Function);
45 		}
46 	}
47 }
48 
vtd_drhd_info(ACPI_DMAR_HEADER * subtable)49 static void vtd_drhd_info(ACPI_DMAR_HEADER *subtable)
50 {
51 	struct acpi_dmar_hardware_unit *drhd = (void *)subtable;
52 	static int unit;
53 
54 	printk("\t\t[ Hardware Unit Definition %d ]\n", unit++);
55 
56 	if (drhd->Flags & ACPI_DRHD_FLAG_INCLUDE_PCI_ALL) {
57 		printk("\t\t- Includes all PCI devices");
58 	} else {
59 		printk("\t\t- Includes only listed PCI devices");
60 	}
61 
62 	printk(" under given Segment\n");
63 
64 	printk("\t\t- Segment number %u\n", drhd->Segment);
65 	printk("\t\t- Base Address 0x%llx\n", drhd->Address);
66 
67 	printk("\t\t- Device Scopes:\n");
68 
69 	acpi_dmar_foreach_devscope(drhd, dmar_devsope_handler, NULL);
70 }
71 
dmar_subtable_handler(ACPI_DMAR_HEADER * subtable,void * arg)72 static void dmar_subtable_handler(ACPI_DMAR_HEADER *subtable, void *arg)
73 {
74 	ARG_UNUSED(arg);
75 
76 	if (subtable->Type != ACPI_DMAR_TYPE_HARDWARE_UNIT) {
77 		return;
78 	}
79 
80 	vtd_drhd_info(subtable);
81 }
82 
vtd_info(void)83 static void vtd_info(void)
84 {
85 	struct acpi_table_dmar *dmar;
86 
87 	dmar = acpi_table_get("DMAR", 0);
88 	if (dmar == NULL) {
89 		printk("\tIntel VT-D not supported or exposed\n");
90 		return;
91 	}
92 
93 	printk("\tIntel VT-D Supported:\n");
94 
95 	printk("\t-> X2APIC ");
96 	if (dmar->Flags & ACPI_DMAR_FLAG_X2APIC_OPT_OUT) {
97 		printk("should be opted out\n");
98 	} else {
99 		printk("does not need to be opted out\n");
100 	}
101 
102 	if (dmar->Flags & ACPI_DMAR_FLAG_INTR_REMAP) {
103 		printk("\t-> Interrupt remapping supported\n");
104 		acpi_dmar_foreach_subtable(dmar, dmar_subtable_handler, NULL);
105 	} else {
106 		printk("\t-> Interrupt remapping not supported\n");
107 	}
108 }
109 
acpi(void)110 void acpi(void)
111 {
112 	int nr_cpus;
113 
114 	for (nr_cpus = 0; acpi_local_apic_get(nr_cpus); ++nr_cpus) {
115 		/* count number of CPUs present */
116 	}
117 
118 	if (nr_cpus == 0) {
119 		printk("ACPI: no RSDT/MADT found\n\n");
120 	} else {
121 		printk("ACPI: %d CPU%s found\n", nr_cpus, nr_cpus == 1 ? "" : "s");
122 
123 		for (int i = 0; i < nr_cpus; ++i) {
124 			struct acpi_madt_local_apic *cpu = acpi_local_apic_get(i);
125 
126 			printk("\tCPU #%d: APIC ID 0x%02x\n", i, cpu->Id);
127 		}
128 	}
129 
130 	printk("\n");
131 
132 	vtd_info();
133 
134 	printk("\n");
135 }
136