xref: /openbmc/linux/drivers/acpi/processor_core.c (revision c819e2cf)
1 /*
2  * Copyright (C) 2005 Intel Corporation
3  * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
4  *
5  *	Alex Chiang <achiang@hp.com>
6  *	- Unified x86/ia64 implementations
7  */
8 #include <linux/export.h>
9 #include <linux/acpi.h>
10 #include <acpi/processor.h>
11 
12 #define _COMPONENT		ACPI_PROCESSOR_COMPONENT
13 ACPI_MODULE_NAME("processor_core");
14 
15 static int map_lapic_id(struct acpi_subtable_header *entry,
16 		 u32 acpi_id, int *apic_id)
17 {
18 	struct acpi_madt_local_apic *lapic =
19 		container_of(entry, struct acpi_madt_local_apic, header);
20 
21 	if (!(lapic->lapic_flags & ACPI_MADT_ENABLED))
22 		return -ENODEV;
23 
24 	if (lapic->processor_id != acpi_id)
25 		return -EINVAL;
26 
27 	*apic_id = lapic->id;
28 	return 0;
29 }
30 
31 static int map_x2apic_id(struct acpi_subtable_header *entry,
32 			 int device_declaration, u32 acpi_id, int *apic_id)
33 {
34 	struct acpi_madt_local_x2apic *apic =
35 		container_of(entry, struct acpi_madt_local_x2apic, header);
36 
37 	if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
38 		return -ENODEV;
39 
40 	if (device_declaration && (apic->uid == acpi_id)) {
41 		*apic_id = apic->local_apic_id;
42 		return 0;
43 	}
44 
45 	return -EINVAL;
46 }
47 
48 static int map_lsapic_id(struct acpi_subtable_header *entry,
49 		int device_declaration, u32 acpi_id, int *apic_id)
50 {
51 	struct acpi_madt_local_sapic *lsapic =
52 		container_of(entry, struct acpi_madt_local_sapic, header);
53 
54 	if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
55 		return -ENODEV;
56 
57 	if (device_declaration) {
58 		if ((entry->length < 16) || (lsapic->uid != acpi_id))
59 			return -EINVAL;
60 	} else if (lsapic->processor_id != acpi_id)
61 		return -EINVAL;
62 
63 	*apic_id = (lsapic->id << 8) | lsapic->eid;
64 	return 0;
65 }
66 
67 static int map_madt_entry(int type, u32 acpi_id)
68 {
69 	unsigned long madt_end, entry;
70 	static struct acpi_table_madt *madt;
71 	static int read_madt;
72 	int phys_id = -1;	/* CPU hardware ID */
73 
74 	if (!read_madt) {
75 		if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
76 					(struct acpi_table_header **)&madt)))
77 			madt = NULL;
78 		read_madt++;
79 	}
80 
81 	if (!madt)
82 		return phys_id;
83 
84 	entry = (unsigned long)madt;
85 	madt_end = entry + madt->header.length;
86 
87 	/* Parse all entries looking for a match. */
88 
89 	entry += sizeof(struct acpi_table_madt);
90 	while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
91 		struct acpi_subtable_header *header =
92 			(struct acpi_subtable_header *)entry;
93 		if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
94 			if (!map_lapic_id(header, acpi_id, &phys_id))
95 				break;
96 		} else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
97 			if (!map_x2apic_id(header, type, acpi_id, &phys_id))
98 				break;
99 		} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
100 			if (!map_lsapic_id(header, type, acpi_id, &phys_id))
101 				break;
102 		}
103 		entry += header->length;
104 	}
105 	return phys_id;
106 }
107 
108 static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
109 {
110 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
111 	union acpi_object *obj;
112 	struct acpi_subtable_header *header;
113 	int phys_id = -1;
114 
115 	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
116 		goto exit;
117 
118 	if (!buffer.length || !buffer.pointer)
119 		goto exit;
120 
121 	obj = buffer.pointer;
122 	if (obj->type != ACPI_TYPE_BUFFER ||
123 	    obj->buffer.length < sizeof(struct acpi_subtable_header)) {
124 		goto exit;
125 	}
126 
127 	header = (struct acpi_subtable_header *)obj->buffer.pointer;
128 	if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
129 		map_lapic_id(header, acpi_id, &phys_id);
130 	else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
131 		map_lsapic_id(header, type, acpi_id, &phys_id);
132 	else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
133 		map_x2apic_id(header, type, acpi_id, &phys_id);
134 
135 exit:
136 	kfree(buffer.pointer);
137 	return phys_id;
138 }
139 
140 int acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
141 {
142 	int phys_id;
143 
144 	phys_id = map_mat_entry(handle, type, acpi_id);
145 	if (phys_id == -1)
146 		phys_id = map_madt_entry(type, acpi_id);
147 
148 	return phys_id;
149 }
150 
151 int acpi_map_cpuid(int phys_id, u32 acpi_id)
152 {
153 #ifdef CONFIG_SMP
154 	int i;
155 #endif
156 
157 	if (phys_id == -1) {
158 		/*
159 		 * On UP processor, there is no _MAT or MADT table.
160 		 * So above phys_id is always set to -1.
161 		 *
162 		 * BIOS may define multiple CPU handles even for UP processor.
163 		 * For example,
164 		 *
165 		 * Scope (_PR)
166 		 * {
167 		 *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
168 		 *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
169 		 *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
170 		 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
171 		 * }
172 		 *
173 		 * Ignores phys_id and always returns 0 for the processor
174 		 * handle with acpi id 0 if nr_cpu_ids is 1.
175 		 * This should be the case if SMP tables are not found.
176 		 * Return -1 for other CPU's handle.
177 		 */
178 		if (nr_cpu_ids <= 1 && acpi_id == 0)
179 			return acpi_id;
180 		else
181 			return phys_id;
182 	}
183 
184 #ifdef CONFIG_SMP
185 	for_each_possible_cpu(i) {
186 		if (cpu_physical_id(i) == phys_id)
187 			return i;
188 	}
189 #else
190 	/* In UP kernel, only processor 0 is valid */
191 	if (phys_id == 0)
192 		return phys_id;
193 #endif
194 	return -1;
195 }
196 
197 int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
198 {
199 	int phys_id;
200 
201 	phys_id = acpi_get_phys_id(handle, type, acpi_id);
202 
203 	return acpi_map_cpuid(phys_id, acpi_id);
204 }
205 EXPORT_SYMBOL_GPL(acpi_get_cpuid);
206