xref: /linux-6.15/drivers/acpi/processor_core.c (revision d633da5d)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24d5d4cd8SAlex Chiang /*
34d5d4cd8SAlex Chiang  * Copyright (C) 2005 Intel Corporation
44d5d4cd8SAlex Chiang  * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
54d5d4cd8SAlex Chiang  *
64d5d4cd8SAlex Chiang  *	Alex Chiang <[email protected]>
74d5d4cd8SAlex Chiang  *	- Unified x86/ia64 implementations
8ecf5636dSYinghai Lu  *
9ecf5636dSYinghai Lu  * I/O APIC hotplug support
10ecf5636dSYinghai Lu  *	Yinghai Lu <[email protected]>
11ecf5636dSYinghai Lu  *	Jiang Liu <[email protected]>
124d5d4cd8SAlex Chiang  */
13214f2c90SPaul Gortmaker #include <linux/export.h>
148b48463fSLv Zheng #include <linux/acpi.h>
154d5d4cd8SAlex Chiang #include <acpi/processor.h>
164d5d4cd8SAlex Chiang 
get_madt_table(void)17ecf5636dSYinghai Lu static struct acpi_table_madt *get_madt_table(void)
18ecf5636dSYinghai Lu {
19ecf5636dSYinghai Lu 	static struct acpi_table_madt *madt;
20ecf5636dSYinghai Lu 	static int read_madt;
21ecf5636dSYinghai Lu 
22ecf5636dSYinghai Lu 	if (!read_madt) {
23ecf5636dSYinghai Lu 		if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
24ecf5636dSYinghai Lu 					(struct acpi_table_header **)&madt)))
25ecf5636dSYinghai Lu 			madt = NULL;
26ecf5636dSYinghai Lu 		read_madt++;
27ecf5636dSYinghai Lu 	}
28ecf5636dSYinghai Lu 
29ecf5636dSYinghai Lu 	return madt;
30ecf5636dSYinghai Lu }
31ecf5636dSYinghai Lu 
map_lapic_id(struct acpi_subtable_header * entry,u32 acpi_id,phys_cpuid_t * apic_id)3278ed8bd2SAlex Chiang static int map_lapic_id(struct acpi_subtable_header *entry,
3309c3f2bdSDou Liyang 		 u32 acpi_id, phys_cpuid_t *apic_id)
3478ed8bd2SAlex Chiang {
3578ed8bd2SAlex Chiang 	struct acpi_madt_local_apic *lapic =
36ef86c3f4SFabian Frederick 		container_of(entry, struct acpi_madt_local_apic, header);
3711130736SAlex Chiang 
3809c3f2bdSDou Liyang 	if (!(lapic->lapic_flags & ACPI_MADT_ENABLED))
39038d7b59SHanjun Guo 		return -ENODEV;
4011130736SAlex Chiang 
4111130736SAlex Chiang 	if (lapic->processor_id != acpi_id)
42038d7b59SHanjun Guo 		return -EINVAL;
4311130736SAlex Chiang 
4478ed8bd2SAlex Chiang 	*apic_id = lapic->id;
45038d7b59SHanjun Guo 	return 0;
4678ed8bd2SAlex Chiang }
4778ed8bd2SAlex Chiang 
map_x2apic_id(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * apic_id)4878ed8bd2SAlex Chiang static int map_x2apic_id(struct acpi_subtable_header *entry,
4909c3f2bdSDou Liyang 		int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
5078ed8bd2SAlex Chiang {
5178ed8bd2SAlex Chiang 	struct acpi_madt_local_x2apic *apic =
52ef86c3f4SFabian Frederick 		container_of(entry, struct acpi_madt_local_x2apic, header);
5378ed8bd2SAlex Chiang 
5409c3f2bdSDou Liyang 	if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
55038d7b59SHanjun Guo 		return -ENODEV;
5678ed8bd2SAlex Chiang 
57d6742095SAlex Chiang 	if (device_declaration && (apic->uid == acpi_id)) {
58d6742095SAlex Chiang 		*apic_id = apic->local_apic_id;
59038d7b59SHanjun Guo 		return 0;
6078ed8bd2SAlex Chiang 	}
6178ed8bd2SAlex Chiang 
62038d7b59SHanjun Guo 	return -EINVAL;
6378ed8bd2SAlex Chiang }
6478ed8bd2SAlex Chiang 
map_lsapic_id(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * apic_id)6578ed8bd2SAlex Chiang static int map_lsapic_id(struct acpi_subtable_header *entry,
6609c3f2bdSDou Liyang 		int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
6778ed8bd2SAlex Chiang {
6878ed8bd2SAlex Chiang 	struct acpi_madt_local_sapic *lsapic =
69ef86c3f4SFabian Frederick 		container_of(entry, struct acpi_madt_local_sapic, header);
7078ed8bd2SAlex Chiang 
7109c3f2bdSDou Liyang 	if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
72038d7b59SHanjun Guo 		return -ENODEV;
7378ed8bd2SAlex Chiang 
7478ed8bd2SAlex Chiang 	if (device_declaration) {
75eae701ceSAlex Chiang 		if ((entry->length < 16) || (lsapic->uid != acpi_id))
76038d7b59SHanjun Guo 			return -EINVAL;
77eae701ceSAlex Chiang 	} else if (lsapic->processor_id != acpi_id)
78038d7b59SHanjun Guo 		return -EINVAL;
79eae701ceSAlex Chiang 
80eae701ceSAlex Chiang 	*apic_id = (lsapic->id << 8) | lsapic->eid;
81038d7b59SHanjun Guo 	return 0;
8278ed8bd2SAlex Chiang }
8378ed8bd2SAlex Chiang 
84020295b4SHanjun Guo /*
85020295b4SHanjun Guo  * Retrieve the ARM CPU physical identifier (MPIDR)
86020295b4SHanjun Guo  */
map_gicc_mpidr(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * mpidr)87020295b4SHanjun Guo static int map_gicc_mpidr(struct acpi_subtable_header *entry,
8809c3f2bdSDou Liyang 		int device_declaration, u32 acpi_id, phys_cpuid_t *mpidr)
89020295b4SHanjun Guo {
90020295b4SHanjun Guo 	struct acpi_madt_generic_interrupt *gicc =
91020295b4SHanjun Guo 	    container_of(entry, struct acpi_madt_generic_interrupt, header);
92020295b4SHanjun Guo 
93*d633da5dSJames Morse 	if (!(gicc->flags &
94*d633da5dSJames Morse 	      (ACPI_MADT_ENABLED | ACPI_MADT_GICC_ONLINE_CAPABLE)))
95020295b4SHanjun Guo 		return -ENODEV;
96020295b4SHanjun Guo 
97020295b4SHanjun Guo 	/* device_declaration means Device object in DSDT, in the
98020295b4SHanjun Guo 	 * GIC interrupt model, logical processors are required to
99020295b4SHanjun Guo 	 * have a Processor Device object in the DSDT, so we should
100020295b4SHanjun Guo 	 * check device_declaration here
101020295b4SHanjun Guo 	 */
102020295b4SHanjun Guo 	if (device_declaration && (gicc->uid == acpi_id)) {
103020295b4SHanjun Guo 		*mpidr = gicc->arm_mpidr;
104020295b4SHanjun Guo 		return 0;
105020295b4SHanjun Guo 	}
106020295b4SHanjun Guo 
107020295b4SHanjun Guo 	return -EINVAL;
108020295b4SHanjun Guo }
109020295b4SHanjun Guo 
1108b7809e2SSunil V L /*
1118b7809e2SSunil V L  * Retrieve the RISC-V hartid for the processor
1128b7809e2SSunil V L  */
map_rintc_hartid(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * hartid)1138b7809e2SSunil V L static int map_rintc_hartid(struct acpi_subtable_header *entry,
1148b7809e2SSunil V L 			    int device_declaration, u32 acpi_id,
1158b7809e2SSunil V L 			    phys_cpuid_t *hartid)
1168b7809e2SSunil V L {
1178b7809e2SSunil V L 	struct acpi_madt_rintc *rintc =
1188b7809e2SSunil V L 	    container_of(entry, struct acpi_madt_rintc, header);
1198b7809e2SSunil V L 
1208b7809e2SSunil V L 	if (!(rintc->flags & ACPI_MADT_ENABLED))
1218b7809e2SSunil V L 		return -ENODEV;
1228b7809e2SSunil V L 
1238b7809e2SSunil V L 	/* device_declaration means Device object in DSDT, in the
1248b7809e2SSunil V L 	 * RISC-V, logical processors are required to
1258b7809e2SSunil V L 	 * have a Processor Device object in the DSDT, so we should
1268b7809e2SSunil V L 	 * check device_declaration here
1278b7809e2SSunil V L 	 */
1288b7809e2SSunil V L 	if (device_declaration && rintc->uid == acpi_id) {
1298b7809e2SSunil V L 		*hartid = rintc->hart_id;
1308b7809e2SSunil V L 		return 0;
1318b7809e2SSunil V L 	}
1328b7809e2SSunil V L 
1338b7809e2SSunil V L 	return -EINVAL;
1348b7809e2SSunil V L }
1358b7809e2SSunil V L 
136f6fcf03cSBibo Mao /*
137f6fcf03cSBibo Mao  * Retrieve LoongArch CPU physical id
138f6fcf03cSBibo Mao  */
map_core_pic_id(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * phys_id)139f6fcf03cSBibo Mao static int map_core_pic_id(struct acpi_subtable_header *entry,
140f6fcf03cSBibo Mao 		int device_declaration, u32 acpi_id, phys_cpuid_t *phys_id)
141f6fcf03cSBibo Mao {
142f6fcf03cSBibo Mao 	struct acpi_madt_core_pic *core_pic =
143f6fcf03cSBibo Mao 		container_of(entry, struct acpi_madt_core_pic, header);
144f6fcf03cSBibo Mao 
145f6fcf03cSBibo Mao 	if (!(core_pic->flags & ACPI_MADT_ENABLED))
146f6fcf03cSBibo Mao 		return -ENODEV;
147f6fcf03cSBibo Mao 
148f6fcf03cSBibo Mao 	/* device_declaration means Device object in DSDT, in LoongArch
149f6fcf03cSBibo Mao 	 * system, logical processor acpi_id is required in _UID property
150f6fcf03cSBibo Mao 	 * of DSDT table, so we should check device_declaration here
151f6fcf03cSBibo Mao 	 */
152f6fcf03cSBibo Mao 	if (device_declaration && (core_pic->processor_id == acpi_id)) {
153f6fcf03cSBibo Mao 		*phys_id = core_pic->core_id;
154f6fcf03cSBibo Mao 		return 0;
155f6fcf03cSBibo Mao 	}
156f6fcf03cSBibo Mao 
157f6fcf03cSBibo Mao 	return -EINVAL;
158f6fcf03cSBibo Mao }
159f6fcf03cSBibo Mao 
map_madt_entry(struct acpi_table_madt * madt,int type,u32 acpi_id)160fb7c2baeSDavid Daney static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
16109c3f2bdSDou Liyang 				   int type, u32 acpi_id)
16278ed8bd2SAlex Chiang {
16378ed8bd2SAlex Chiang 	unsigned long madt_end, entry;
164828aef37SCatalin Marinas 	phys_cpuid_t phys_id = PHYS_CPUID_INVALID;	/* CPU hardware ID */
16578ed8bd2SAlex Chiang 
16678ed8bd2SAlex Chiang 	if (!madt)
167af8f3f51SHanjun Guo 		return phys_id;
16878ed8bd2SAlex Chiang 
16978ed8bd2SAlex Chiang 	entry = (unsigned long)madt;
17078ed8bd2SAlex Chiang 	madt_end = entry + madt->header.length;
17178ed8bd2SAlex Chiang 
17278ed8bd2SAlex Chiang 	/* Parse all entries looking for a match. */
17378ed8bd2SAlex Chiang 
17478ed8bd2SAlex Chiang 	entry += sizeof(struct acpi_table_madt);
17578ed8bd2SAlex Chiang 	while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
17678ed8bd2SAlex Chiang 		struct acpi_subtable_header *header =
17778ed8bd2SAlex Chiang 			(struct acpi_subtable_header *)entry;
17878ed8bd2SAlex Chiang 		if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
17909c3f2bdSDou Liyang 			if (!map_lapic_id(header, acpi_id, &phys_id))
18078ed8bd2SAlex Chiang 				break;
18178ed8bd2SAlex Chiang 		} else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
18209c3f2bdSDou Liyang 			if (!map_x2apic_id(header, type, acpi_id, &phys_id))
18378ed8bd2SAlex Chiang 				break;
18478ed8bd2SAlex Chiang 		} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
18509c3f2bdSDou Liyang 			if (!map_lsapic_id(header, type, acpi_id, &phys_id))
18678ed8bd2SAlex Chiang 				break;
187020295b4SHanjun Guo 		} else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
18809c3f2bdSDou Liyang 			if (!map_gicc_mpidr(header, type, acpi_id, &phys_id))
189020295b4SHanjun Guo 				break;
1908b7809e2SSunil V L 		} else if (header->type == ACPI_MADT_TYPE_RINTC) {
1918b7809e2SSunil V L 			if (!map_rintc_hartid(header, type, acpi_id, &phys_id))
1928b7809e2SSunil V L 				break;
193f6fcf03cSBibo Mao 		} else if (header->type == ACPI_MADT_TYPE_CORE_PIC) {
194f6fcf03cSBibo Mao 			if (!map_core_pic_id(header, type, acpi_id, &phys_id))
195f6fcf03cSBibo Mao 				break;
19678ed8bd2SAlex Chiang 		}
19778ed8bd2SAlex Chiang 		entry += header->length;
19878ed8bd2SAlex Chiang 	}
199af8f3f51SHanjun Guo 	return phys_id;
20078ed8bd2SAlex Chiang }
20178ed8bd2SAlex Chiang 
acpi_map_madt_entry(u32 acpi_id)202fb7c2baeSDavid Daney phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id)
203fb7c2baeSDavid Daney {
204fb7c2baeSDavid Daney 	struct acpi_table_madt *madt = NULL;
205fb7c2baeSDavid Daney 	phys_cpuid_t rv;
206fb7c2baeSDavid Daney 
2076b11d1d6SLv Zheng 	acpi_get_table(ACPI_SIG_MADT, 0,
2086b11d1d6SLv Zheng 		       (struct acpi_table_header **)&madt);
209fb7c2baeSDavid Daney 	if (!madt)
210fb7c2baeSDavid Daney 		return PHYS_CPUID_INVALID;
211fb7c2baeSDavid Daney 
21209c3f2bdSDou Liyang 	rv = map_madt_entry(madt, 1, acpi_id);
213fb7c2baeSDavid Daney 
2146b11d1d6SLv Zheng 	acpi_put_table((struct acpi_table_header *)madt);
215fb7c2baeSDavid Daney 
216fb7c2baeSDavid Daney 	return rv;
217fb7c2baeSDavid Daney }
218fb7c2baeSDavid Daney 
acpi_get_madt_revision(void)21909c3f2bdSDou Liyang int __init acpi_get_madt_revision(void)
22078ed8bd2SAlex Chiang {
22178ed8bd2SAlex Chiang 	struct acpi_table_header *madt = NULL;
22278ed8bd2SAlex Chiang 	int revision;
22378ed8bd2SAlex Chiang 
224828aef37SCatalin Marinas 	if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, &madt)))
22578ed8bd2SAlex Chiang 		return -EINVAL;
22678ed8bd2SAlex Chiang 
22778ed8bd2SAlex Chiang 	revision = madt->revision;
22878ed8bd2SAlex Chiang 
22978ed8bd2SAlex Chiang 	acpi_put_table(madt);
23078ed8bd2SAlex Chiang 
23178ed8bd2SAlex Chiang 	return revision;
23278ed8bd2SAlex Chiang }
23378ed8bd2SAlex Chiang 
map_mat_entry(acpi_handle handle,int type,u32 acpi_id)23478ed8bd2SAlex Chiang static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
23578ed8bd2SAlex Chiang {
23678ed8bd2SAlex Chiang 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
23778ed8bd2SAlex Chiang 	union acpi_object *obj;
23878ed8bd2SAlex Chiang 	struct acpi_subtable_header *header;
23913ca62b2SJiang Liu 	phys_cpuid_t phys_id = PHYS_CPUID_INVALID;
24009c3f2bdSDou Liyang 
24113ca62b2SJiang Liu 	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
24209c3f2bdSDou Liyang 		goto exit;
24313ca62b2SJiang Liu 
24409c3f2bdSDou Liyang 	if (!buffer.length || !buffer.pointer)
245020295b4SHanjun Guo 		goto exit;
24609c3f2bdSDou Liyang 
247f6fcf03cSBibo Mao 	obj = buffer.pointer;
248f6fcf03cSBibo Mao 	if (obj->type != ACPI_TYPE_BUFFER ||
24978ed8bd2SAlex Chiang 	    obj->buffer.length < sizeof(struct acpi_subtable_header)) {
25078ed8bd2SAlex Chiang 		goto exit;
25178ed8bd2SAlex Chiang 	}
252af8f3f51SHanjun Guo 
25378ed8bd2SAlex Chiang 	header = (struct acpi_subtable_header *)obj->buffer.pointer;
25478ed8bd2SAlex Chiang 	if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
25509c3f2bdSDou Liyang 		map_lapic_id(header, acpi_id, &phys_id);
25678ed8bd2SAlex Chiang 	else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
257828aef37SCatalin Marinas 		map_lsapic_id(header, type, acpi_id, &phys_id);
25878ed8bd2SAlex Chiang 	else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
25909c3f2bdSDou Liyang 		map_x2apic_id(header, type, acpi_id, &phys_id);
260ddcc18f5SHanjun Guo 	else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
26109c3f2bdSDou Liyang 		map_gicc_mpidr(header, type, acpi_id, &phys_id);
262ca9f62acSJiang Liu 	else if (header->type == ACPI_MADT_TYPE_CORE_PIC)
263af8f3f51SHanjun Guo 		map_core_pic_id(header, type, acpi_id, &phys_id);
264ca9f62acSJiang Liu 
265166deb0fSJan Beulich exit:
266ca9f62acSJiang Liu 	kfree(buffer.pointer);
267828aef37SCatalin Marinas 	return phys_id;
268ca9f62acSJiang Liu }
269ca9f62acSJiang Liu 
acpi_get_phys_id(acpi_handle handle,int type,u32 acpi_id)270ca9f62acSJiang Liu phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
271ca9f62acSJiang Liu {
272ca9f62acSJiang Liu 	phys_cpuid_t phys_id;
273ddcc18f5SHanjun Guo 
274d640113fSLin Ming 	phys_id = map_mat_entry(handle, type, acpi_id);
275d640113fSLin Ming 	if (invalid_phys_cpuid(phys_id))
276828aef37SCatalin Marinas 		phys_id = map_madt_entry(get_madt_table(), type, acpi_id);
277d640113fSLin Ming 
278d640113fSLin Ming 	return phys_id;
279d640113fSLin Ming }
280d640113fSLin Ming EXPORT_SYMBOL_GPL(acpi_get_phys_id);
281d640113fSLin Ming 
acpi_map_cpuid(phys_cpuid_t phys_id,u32 acpi_id)282d640113fSLin Ming int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
283d640113fSLin Ming {
284d640113fSLin Ming #ifdef CONFIG_SMP
285d640113fSLin Ming 	int i;
286d640113fSLin Ming #endif
287d640113fSLin Ming 
288d640113fSLin Ming 	if (invalid_phys_cpuid(phys_id)) {
289af8f3f51SHanjun Guo 		/*
290c4686c71SThomas Renninger 		 * On UP processor, there is no _MAT or MADT table.
291c4686c71SThomas Renninger 		 * So above phys_id is always set to PHYS_CPUID_INVALID.
292d3da7cb9SHanjun Guo 		 *
293d640113fSLin Ming 		 * BIOS may define multiple CPU handles even for UP processor.
294c4686c71SThomas Renninger 		 * For example,
295d640113fSLin Ming 		 *
296d640113fSLin Ming 		 * Scope (_PR)
297d3da7cb9SHanjun Guo 		 * {
298d640113fSLin Ming 		 *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
29978ed8bd2SAlex Chiang 		 *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
300932df741SLin Ming 		 *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
30178ed8bd2SAlex Chiang 		 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
302af8f3f51SHanjun Guo 		 * }
30378ed8bd2SAlex Chiang 		 *
30478ed8bd2SAlex Chiang 		 * Ignores phys_id and always returns 0 for the processor
305932df741SLin Ming 		 * handle with acpi id 0 if nr_cpu_ids is 1.
306932df741SLin Ming 		 * This should be the case if SMP tables are not found.
307af8f3f51SHanjun Guo 		 * Return -EINVAL for other CPU's handle.
308af8f3f51SHanjun Guo 		 */
309932df741SLin Ming 		if (nr_cpu_ids <= 1 && acpi_id == 0)
310d3da7cb9SHanjun Guo 			return acpi_id;
31178ed8bd2SAlex Chiang 		else
312ca9f62acSJiang Liu 			return -EINVAL;
313ca9f62acSJiang Liu 	}
314ca9f62acSJiang Liu 
315828aef37SCatalin Marinas #ifdef CONFIG_SMP
316ca9f62acSJiang Liu 	for_each_possible_cpu(i) {
317af8f3f51SHanjun Guo 		if (cpu_physical_id(i) == phys_id)
318ca9f62acSJiang Liu 			return i;
319af8f3f51SHanjun Guo 	}
320ca9f62acSJiang Liu #else
32178ed8bd2SAlex Chiang 	/* In UP kernel, only processor 0 is valid */
322ecf5636dSYinghai Lu 	if (phys_id == 0)
323ecf5636dSYinghai Lu 		return phys_id;
324ecf5636dSYinghai Lu #endif
325ecf5636dSYinghai Lu 	return -ENODEV;
326ecf5636dSYinghai Lu }
327ecf5636dSYinghai Lu 
acpi_get_cpuid(acpi_handle handle,int type,u32 acpi_id)328ecf5636dSYinghai Lu int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
329ecf5636dSYinghai Lu {
330ecf5636dSYinghai Lu 	phys_cpuid_t phys_id;
331ecf5636dSYinghai Lu 
332ecf5636dSYinghai Lu 	phys_id = acpi_get_phys_id(handle, type, acpi_id);
333ecf5636dSYinghai Lu 
334ecf5636dSYinghai Lu 	return acpi_map_cpuid(phys_id, acpi_id);
335ecf5636dSYinghai Lu }
336ecf5636dSYinghai Lu EXPORT_SYMBOL_GPL(acpi_get_cpuid);
337ecf5636dSYinghai Lu 
338ecf5636dSYinghai Lu #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
get_ioapic_id(struct acpi_subtable_header * entry,u32 gsi_base,u64 * phys_addr,int * ioapic_id)339ecf5636dSYinghai Lu static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
340ecf5636dSYinghai Lu 			 u64 *phys_addr, int *ioapic_id)
341ecf5636dSYinghai Lu {
342ecf5636dSYinghai Lu 	struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
343ecf5636dSYinghai Lu 
344ecf5636dSYinghai Lu 	if (ioapic->global_irq_base != gsi_base)
345ecf5636dSYinghai Lu 		return 0;
346ecf5636dSYinghai Lu 
347ecf5636dSYinghai Lu 	*phys_addr = ioapic->address;
348ecf5636dSYinghai Lu 	*ioapic_id = ioapic->id;
349ecf5636dSYinghai Lu 	return 1;
350ecf5636dSYinghai Lu }
351ecf5636dSYinghai Lu 
parse_madt_ioapic_entry(u32 gsi_base,u64 * phys_addr)352ecf5636dSYinghai Lu static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
353ecf5636dSYinghai Lu {
354ecf5636dSYinghai Lu 	struct acpi_subtable_header *hdr;
355ecf5636dSYinghai Lu 	unsigned long madt_end, entry;
356ecf5636dSYinghai Lu 	struct acpi_table_madt *madt;
357ecf5636dSYinghai Lu 	int apic_id = -1;
358ecf5636dSYinghai Lu 
359ecf5636dSYinghai Lu 	madt = get_madt_table();
360ecf5636dSYinghai Lu 	if (!madt)
361ecf5636dSYinghai Lu 		return apic_id;
362ecf5636dSYinghai Lu 
363ecf5636dSYinghai Lu 	entry = (unsigned long)madt;
364ecf5636dSYinghai Lu 	madt_end = entry + madt->header.length;
365ecf5636dSYinghai Lu 
366ecf5636dSYinghai Lu 	/* Parse all entries looking for a match. */
367ecf5636dSYinghai Lu 	entry += sizeof(struct acpi_table_madt);
368ecf5636dSYinghai Lu 	while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
369ecf5636dSYinghai Lu 		hdr = (struct acpi_subtable_header *)entry;
370ecf5636dSYinghai Lu 		if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
371ecf5636dSYinghai Lu 		    get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
372ecf5636dSYinghai Lu 			break;
373ecf5636dSYinghai Lu 		else
374ecf5636dSYinghai Lu 			entry += hdr->length;
375ecf5636dSYinghai Lu 	}
376ecf5636dSYinghai Lu 
377ecf5636dSYinghai Lu 	return apic_id;
378ecf5636dSYinghai Lu }
379ecf5636dSYinghai Lu 
parse_mat_ioapic_entry(acpi_handle handle,u32 gsi_base,u64 * phys_addr)380ecf5636dSYinghai Lu static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
381ecf5636dSYinghai Lu 				  u64 *phys_addr)
382ecf5636dSYinghai Lu {
383ecf5636dSYinghai Lu 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
384ecf5636dSYinghai Lu 	struct acpi_subtable_header *header;
385ecf5636dSYinghai Lu 	union acpi_object *obj;
386ecf5636dSYinghai Lu 	int apic_id = -1;
387ecf5636dSYinghai Lu 
388ecf5636dSYinghai Lu 	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
389ecf5636dSYinghai Lu 		goto exit;
390ecf5636dSYinghai Lu 
391ecf5636dSYinghai Lu 	if (!buffer.length || !buffer.pointer)
392ecf5636dSYinghai Lu 		goto exit;
393ecf5636dSYinghai Lu 
394ecf5636dSYinghai Lu 	obj = buffer.pointer;
395ecf5636dSYinghai Lu 	if (obj->type != ACPI_TYPE_BUFFER ||
396ecf5636dSYinghai Lu 	    obj->buffer.length < sizeof(struct acpi_subtable_header))
397ecf5636dSYinghai Lu 		goto exit;
398ecf5636dSYinghai Lu 
399ecf5636dSYinghai Lu 	header = (struct acpi_subtable_header *)obj->buffer.pointer;
400ecf5636dSYinghai Lu 	if (header->type == ACPI_MADT_TYPE_IO_APIC)
401ecf5636dSYinghai Lu 		get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
402ecf5636dSYinghai Lu 
403ecf5636dSYinghai Lu exit:
404ecf5636dSYinghai Lu 	kfree(buffer.pointer);
405ecf5636dSYinghai Lu 	return apic_id;
406ecf5636dSYinghai Lu }
407ecf5636dSYinghai Lu 
408ecf5636dSYinghai Lu /**
409ecf5636dSYinghai Lu  * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base
410ecf5636dSYinghai Lu  * @handle:	ACPI object for IOAPIC device
411ecf5636dSYinghai Lu  * @gsi_base:	GSI base to match with
412ecf5636dSYinghai Lu  * @phys_addr:	Pointer to store physical address of matching IOAPIC record
413ecf5636dSYinghai Lu  *
414ecf5636dSYinghai Lu  * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search
415  * for an ACPI IOAPIC record matching @gsi_base.
416  * Return IOAPIC id and store physical address in @phys_addr if found a match,
417  * otherwise return <0.
418  */
acpi_get_ioapic_id(acpi_handle handle,u32 gsi_base,u64 * phys_addr)419 int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr)
420 {
421 	int apic_id;
422 
423 	apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr);
424 	if (apic_id == -1)
425 		apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr);
426 
427 	return apic_id;
428 }
429 #endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */
430