147817254b8637b56730aec26eed2c337d3938bb5Alex Chiang/*
247817254b8637b56730aec26eed2c337d3938bb5Alex Chiang * Copyright (C) 2005 Intel Corporation
347817254b8637b56730aec26eed2c337d3938bb5Alex Chiang * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
447817254b8637b56730aec26eed2c337d3938bb5Alex Chiang *
547817254b8637b56730aec26eed2c337d3938bb5Alex Chiang *	Alex Chiang <achiang@hp.com>
647817254b8637b56730aec26eed2c337d3938bb5Alex Chiang *	- Unified x86/ia64 implementations
747817254b8637b56730aec26eed2c337d3938bb5Alex Chiang *	Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
847817254b8637b56730aec26eed2c337d3938bb5Alex Chiang *	- Added _PDC for platforms with Intel CPUs
947817254b8637b56730aec26eed2c337d3938bb5Alex Chiang */
10214f2c90b970e098e75cf719c0c5b0f1fe69b716Paul Gortmaker#include <linux/export.h>
1178f1699659963fff97975df44db6d5dbe7218e55Alex Chiang#include <linux/dmi.h>
125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
1378f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
1478f1699659963fff97975df44db6d5dbe7218e55Alex Chiang#include <acpi/acpi_drivers.h>
1578f1699659963fff97975df44db6d5dbe7218e55Alex Chiang#include <acpi/processor.h>
1678f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
1778f1699659963fff97975df44db6d5dbe7218e55Alex Chiang#include "internal.h"
1878f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
1978f1699659963fff97975df44db6d5dbe7218e55Alex Chiang#define PREFIX			"ACPI: "
2078f1699659963fff97975df44db6d5dbe7218e55Alex Chiang#define _COMPONENT		ACPI_PROCESSOR_COMPONENT
214d5d4cd88c542ff56cf7feacd29cc907f2abbfbbAlex ChiangACPI_MODULE_NAME("processor_core");
2278f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
236430c9c12a7dbb8f60f0d8294b73b3c0bb03f64fJan Beulichstatic int __init set_no_mwait(const struct dmi_system_id *id)
2478f1699659963fff97975df44db6d5dbe7218e55Alex Chiang{
2578f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	printk(KERN_NOTICE PREFIX "%s detected - "
2678f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		"disabling mwait for CPU C-states\n", id->ident);
27d18960494f65ca4fa0d67c865aaca99452070d15Thomas Renninger	boot_option_idle_override = IDLE_NOMWAIT;
2878f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	return 0;
2978f1699659963fff97975df44db6d5dbe7218e55Alex Chiang}
3078f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
316430c9c12a7dbb8f60f0d8294b73b3c0bb03f64fJan Beulichstatic struct dmi_system_id __initdata processor_idle_dmi_table[] = {
3278f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	{
3378f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	set_no_mwait, "Extensa 5220", {
3478f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
3578f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
3678f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
3778f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
3878f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	{},
3978f1699659963fff97975df44db6d5dbe7218e55Alex Chiang};
4078f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
4178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiangstatic int map_lapic_id(struct acpi_subtable_header *entry,
4278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		 u32 acpi_id, int *apic_id)
4378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang{
4478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	struct acpi_madt_local_apic *lapic =
4578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		(struct acpi_madt_local_apic *)entry;
4611130736c99c37e253f45b2d3fd30b07313f83c6Alex Chiang
4711130736c99c37e253f45b2d3fd30b07313f83c6Alex Chiang	if (!(lapic->lapic_flags & ACPI_MADT_ENABLED))
4811130736c99c37e253f45b2d3fd30b07313f83c6Alex Chiang		return 0;
4911130736c99c37e253f45b2d3fd30b07313f83c6Alex Chiang
5011130736c99c37e253f45b2d3fd30b07313f83c6Alex Chiang	if (lapic->processor_id != acpi_id)
5111130736c99c37e253f45b2d3fd30b07313f83c6Alex Chiang		return 0;
5211130736c99c37e253f45b2d3fd30b07313f83c6Alex Chiang
5311130736c99c37e253f45b2d3fd30b07313f83c6Alex Chiang	*apic_id = lapic->id;
5411130736c99c37e253f45b2d3fd30b07313f83c6Alex Chiang	return 1;
5578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang}
5678ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
5778ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiangstatic int map_x2apic_id(struct acpi_subtable_header *entry,
5878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang			 int device_declaration, u32 acpi_id, int *apic_id)
5978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang{
6078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	struct acpi_madt_local_x2apic *apic =
6178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		(struct acpi_madt_local_x2apic *)entry;
6278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
6378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
6478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		return 0;
6578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
66d67420956b7b1dcffb894b2f1f81b9408fca1b4cAlex Chiang	if (device_declaration && (apic->uid == acpi_id)) {
67d67420956b7b1dcffb894b2f1f81b9408fca1b4cAlex Chiang		*apic_id = apic->local_apic_id;
68d67420956b7b1dcffb894b2f1f81b9408fca1b4cAlex Chiang		return 1;
6978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	}
7078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
7178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	return 0;
7278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang}
7378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
7478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiangstatic int map_lsapic_id(struct acpi_subtable_header *entry,
7578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		int device_declaration, u32 acpi_id, int *apic_id)
7678ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang{
7778ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	struct acpi_madt_local_sapic *lsapic =
7878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		(struct acpi_madt_local_sapic *)entry;
7978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
8078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
8178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		return 0;
8278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
8378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (device_declaration) {
84eae701ceadf5aa3fc3b334029ef71f6885ef1cdeAlex Chiang		if ((entry->length < 16) || (lsapic->uid != acpi_id))
85eae701ceadf5aa3fc3b334029ef71f6885ef1cdeAlex Chiang			return 0;
86eae701ceadf5aa3fc3b334029ef71f6885ef1cdeAlex Chiang	} else if (lsapic->processor_id != acpi_id)
87eae701ceadf5aa3fc3b334029ef71f6885ef1cdeAlex Chiang		return 0;
8878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
89eae701ceadf5aa3fc3b334029ef71f6885ef1cdeAlex Chiang	*apic_id = (lsapic->id << 8) | lsapic->eid;
9078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	return 1;
9178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang}
9278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
9378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiangstatic int map_madt_entry(int type, u32 acpi_id)
9478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang{
9578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	unsigned long madt_end, entry;
96149fe9c293f76803206648270ca24fc2604d5f01Alex Chiang	static struct acpi_table_madt *madt;
97149fe9c293f76803206648270ca24fc2604d5f01Alex Chiang	static int read_madt;
9878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	int apic_id = -1;
9978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
100149fe9c293f76803206648270ca24fc2604d5f01Alex Chiang	if (!read_madt) {
101149fe9c293f76803206648270ca24fc2604d5f01Alex Chiang		if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
102149fe9c293f76803206648270ca24fc2604d5f01Alex Chiang					(struct acpi_table_header **)&madt)))
103149fe9c293f76803206648270ca24fc2604d5f01Alex Chiang			madt = NULL;
104149fe9c293f76803206648270ca24fc2604d5f01Alex Chiang		read_madt++;
105149fe9c293f76803206648270ca24fc2604d5f01Alex Chiang	}
106149fe9c293f76803206648270ca24fc2604d5f01Alex Chiang
10778ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (!madt)
10878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		return apic_id;
10978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
11078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	entry = (unsigned long)madt;
11178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	madt_end = entry + madt->header.length;
11278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
11378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	/* Parse all entries looking for a match. */
11478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
11578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	entry += sizeof(struct acpi_table_madt);
11678ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
11778ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		struct acpi_subtable_header *header =
11878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang			(struct acpi_subtable_header *)entry;
11978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
12078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang			if (map_lapic_id(header, acpi_id, &apic_id))
12178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang				break;
12278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		} else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
12378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang			if (map_x2apic_id(header, type, acpi_id, &apic_id))
12478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang				break;
12578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
12678ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang			if (map_lsapic_id(header, type, acpi_id, &apic_id))
12778ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang				break;
12878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		}
12978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		entry += header->length;
13078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	}
13178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	return apic_id;
13278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang}
13378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
13478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiangstatic int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
13578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang{
13678ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
13778ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	union acpi_object *obj;
13878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	struct acpi_subtable_header *header;
13978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	int apic_id = -1;
14078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
14178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
14278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		goto exit;
14378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
14478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (!buffer.length || !buffer.pointer)
14578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		goto exit;
14678ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
14778ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	obj = buffer.pointer;
14878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (obj->type != ACPI_TYPE_BUFFER ||
14978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	    obj->buffer.length < sizeof(struct acpi_subtable_header)) {
15078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		goto exit;
15178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	}
15278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
15378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	header = (struct acpi_subtable_header *)obj->buffer.pointer;
15478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
15578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		map_lapic_id(header, acpi_id, &apic_id);
15678ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
15778ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		map_lsapic_id(header, type, acpi_id, &apic_id);
15878ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	}
15978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
16078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiangexit:
16178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (buffer.pointer)
16278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		kfree(buffer.pointer);
16378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	return apic_id;
16478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang}
16578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
16678ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiangint acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
16778ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang{
168932df7414336a00f45e5aec62724cf736b0bcfd4Lin Ming#ifdef CONFIG_SMP
16978ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	int i;
170932df7414336a00f45e5aec62724cf736b0bcfd4Lin Ming#endif
17178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	int apic_id = -1;
17278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
17378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	apic_id = map_mat_entry(handle, type, acpi_id);
17478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	if (apic_id == -1)
17578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		apic_id = map_madt_entry(type, acpi_id);
176d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming	if (apic_id == -1) {
177d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		/*
178d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 * On UP processor, there is no _MAT or MADT table.
179d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 * So above apic_id is always set to -1.
180d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 *
181d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 * BIOS may define multiple CPU handles even for UP processor.
182d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 * For example,
183d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 *
184d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 * Scope (_PR)
185d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming                 * {
186d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
187d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
188d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
189d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
190d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 * }
191d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 *
192d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 * Ignores apic_id and always return 0 for CPU0's handle.
193d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 * Return -1 for other CPU's handle.
194d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		 */
195d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		if (acpi_id == 0)
196d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming			return acpi_id;
197d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming		else
198d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming			return apic_id;
199d640113fe80e45ebd4a5b420b220d3f6bf37f682Lin Ming	}
20078ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
201932df7414336a00f45e5aec62724cf736b0bcfd4Lin Ming#ifdef CONFIG_SMP
20278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	for_each_possible_cpu(i) {
20378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang		if (cpu_physical_id(i) == apic_id)
20478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang			return i;
20578ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	}
206932df7414336a00f45e5aec62724cf736b0bcfd4Lin Ming#else
207932df7414336a00f45e5aec62724cf736b0bcfd4Lin Ming	/* In UP kernel, only processor 0 is valid */
208932df7414336a00f45e5aec62724cf736b0bcfd4Lin Ming	if (apic_id == 0)
209932df7414336a00f45e5aec62724cf736b0bcfd4Lin Ming		return apic_id;
210932df7414336a00f45e5aec62724cf736b0bcfd4Lin Ming#endif
21178ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang	return -1;
21278ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang}
21378ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex ChiangEXPORT_SYMBOL_GPL(acpi_get_cpuid);
21478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
2156430c9c12a7dbb8f60f0d8294b73b3c0bb03f64fJan Beulichstatic bool __init processor_physically_present(acpi_handle handle)
2165d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang{
2175d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	int cpuid, type;
2185d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	u32 acpi_id;
2195d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	acpi_status status;
2205d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	acpi_object_type acpi_type;
2215d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	unsigned long long tmp;
2225d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	union acpi_object object = { 0 };
2235d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
2245d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang
2255d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	status = acpi_get_type(handle, &acpi_type);
2265d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	if (ACPI_FAILURE(status))
2275d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		return false;
2285d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang
2295d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	switch (acpi_type) {
2305d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	case ACPI_TYPE_PROCESSOR:
2315d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
2325d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		if (ACPI_FAILURE(status))
2335d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang			return false;
2345d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		acpi_id = object.processor.proc_id;
2355d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		break;
2365d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	case ACPI_TYPE_DEVICE:
2375d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp);
2385d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		if (ACPI_FAILURE(status))
2395d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang			return false;
2405d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		acpi_id = tmp;
2415d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		break;
2425d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	default:
2435d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		return false;
2445d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	}
2455d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang
2465d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
2475d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	cpuid = acpi_get_cpuid(handle, type, acpi_id);
2485d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang
249932df7414336a00f45e5aec62724cf736b0bcfd4Lin Ming	if (cpuid == -1)
2505d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		return false;
2515d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang
2525d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	return true;
2535d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang}
25478ed8bd2944b6400f742306e5fe9d1b9b6bf18baAlex Chiang
255af10f941ab7807d8b0bb3c66e679d8a6bbbe7485Jan Beulichstatic void __cpuinit acpi_set_pdc_bits(u32 *buf)
25608ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang{
25708ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang	buf[0] = ACPI_PDC_REVISION_ID;
25808ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang	buf[1] = 1;
25908ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang
26008ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang	/* Enable coordination with firmware's _TSD info */
26108ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang	buf[2] = ACPI_PDC_SMP_T_SWCOORD;
2626c5807d7bc7d051fce00863ffb98d36325501eb2Alex Chiang
2636c5807d7bc7d051fce00863ffb98d36325501eb2Alex Chiang	/* Twiddle arch-specific bits needed for _PDC */
2646c5807d7bc7d051fce00863ffb98d36325501eb2Alex Chiang	arch_acpi_set_pdc_bits(buf);
26508ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang}
26608ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang
267af10f941ab7807d8b0bb3c66e679d8a6bbbe7485Jan Beulichstatic struct acpi_object_list *__cpuinit acpi_processor_alloc_pdc(void)
268407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang{
269407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	struct acpi_object_list *obj_list;
270407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	union acpi_object *obj;
271407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	u32 *buf;
272407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang
273407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	/* allocate and initialize pdc. It will be used later. */
274407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL);
275407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	if (!obj_list) {
276407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang		printk(KERN_ERR "Memory allocation error\n");
2773b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang		return NULL;
278407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	}
279407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang
280407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
281407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	if (!obj) {
282407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang		printk(KERN_ERR "Memory allocation error\n");
283407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang		kfree(obj_list);
2843b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang		return NULL;
285407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	}
286407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang
287407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	buf = kmalloc(12, GFP_KERNEL);
288407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	if (!buf) {
289407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang		printk(KERN_ERR "Memory allocation error\n");
290407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang		kfree(obj);
291407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang		kfree(obj_list);
2923b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang		return NULL;
293407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	}
294407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang
29508ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang	acpi_set_pdc_bits(buf);
29608ea48a326d8030ef5b7fb02292faf5a53c95e0aAlex Chiang
297407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	obj->type = ACPI_TYPE_BUFFER;
298407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	obj->buffer.length = 12;
299407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	obj->buffer.pointer = (u8 *) buf;
300407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	obj_list->count = 1;
301407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang	obj_list->pointer = obj;
302407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang
3033b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang	return obj_list;
304407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang}
305407cd87c54e76c266245e8faef8dd4a84b7254feAlex Chiang
30678f1699659963fff97975df44db6d5dbe7218e55Alex Chiang/*
30778f1699659963fff97975df44db6d5dbe7218e55Alex Chiang * _PDC is required for a BIOS-OS handshake for most of the newer
30878f1699659963fff97975df44db6d5dbe7218e55Alex Chiang * ACPI processor features.
30978f1699659963fff97975df44db6d5dbe7218e55Alex Chiang */
310af10f941ab7807d8b0bb3c66e679d8a6bbbe7485Jan Beulichstatic int __cpuinit
311fa118564ed66f785f957d8230745b62e9244700dAlex Chiangacpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
31278f1699659963fff97975df44db6d5dbe7218e55Alex Chiang{
31378f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	acpi_status status = AE_OK;
31478f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
315d18960494f65ca4fa0d67c865aaca99452070d15Thomas Renninger	if (boot_option_idle_override == IDLE_NOMWAIT) {
31678f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		/*
31778f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		 * If mwait is disabled for CPU C-states, the C2C3_FFH access
31878f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		 * mode will be disabled in the parameter of _PDC object.
31978f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		 * Of course C1_FFH access mode will also be disabled.
32078f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		 */
32178f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		union acpi_object *obj;
32278f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		u32 *buffer = NULL;
32378f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
32478f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		obj = pdc_in->pointer;
32578f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		buffer = (u32 *)(obj->buffer.pointer);
32678f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
32778f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
32878f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	}
329fa118564ed66f785f957d8230745b62e9244700dAlex Chiang	status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL);
33078f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
33178f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	if (ACPI_FAILURE(status))
33278f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
33378f1699659963fff97975df44db6d5dbe7218e55Alex Chiang		    "Could not evaluate _PDC, using legacy perf. control.\n"));
33478f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
33578f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	return status;
33678f1699659963fff97975df44db6d5dbe7218e55Alex Chiang}
33778f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
338af10f941ab7807d8b0bb3c66e679d8a6bbbe7485Jan Beulichvoid __cpuinit acpi_processor_set_pdc(acpi_handle handle)
33978f1699659963fff97975df44db6d5dbe7218e55Alex Chiang{
3403b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang	struct acpi_object_list *obj_list;
3413b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang
3421d9cb470a755409ce97c3376174b1e234bd20371Alex Chiang	if (arch_has_acpi_pdc() == false)
3431d9cb470a755409ce97c3376174b1e234bd20371Alex Chiang		return;
3441d9cb470a755409ce97c3376174b1e234bd20371Alex Chiang
3453b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang	obj_list = acpi_processor_alloc_pdc();
3463b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang	if (!obj_list)
3473b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang		return;
3483b407aef573b82139c3bc4dcaad2731fad56c054Alex Chiang
34943bab25ced218385f7e6a076c2459ea008cfd2e1Alex Chiang	acpi_processor_eval_pdc(handle, obj_list);
350b9c2db783456bcbce31e2482214cd337528db295Alex Chiang
351b9c2db783456bcbce31e2482214cd337528db295Alex Chiang	kfree(obj_list->pointer->buffer.pointer);
352b9c2db783456bcbce31e2482214cd337528db295Alex Chiang	kfree(obj_list->pointer);
353b9c2db783456bcbce31e2482214cd337528db295Alex Chiang	kfree(obj_list);
35478f1699659963fff97975df44db6d5dbe7218e55Alex Chiang}
35578f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
3566430c9c12a7dbb8f60f0d8294b73b3c0bb03f64fJan Beulichstatic acpi_status __init
35778f1699659963fff97975df44db6d5dbe7218e55Alex Chiangearly_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
35878f1699659963fff97975df44db6d5dbe7218e55Alex Chiang{
3595d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang	if (processor_physically_present(handle) == false)
3605d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang		return AE_OK;
3615d554a7bb0643a6151a84319bfeba8270bf5269eAlex Chiang
36243bab25ced218385f7e6a076c2459ea008cfd2e1Alex Chiang	acpi_processor_set_pdc(handle);
36378f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	return AE_OK;
36478f1699659963fff97975df44db6d5dbe7218e55Alex Chiang}
36578f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
3667a0b73a49ab56fb1e836675c00d6d0d2ba39a714Tony Luckvoid __init acpi_early_processor_set_pdc(void)
36778f1699659963fff97975df44db6d5dbe7218e55Alex Chiang{
36878f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	/*
36978f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	 * Check whether the system is DMI table. If yes, OSPM
37078f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	 * should not use mwait for CPU-states.
37178f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	 */
37278f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	dmi_check_system(processor_idle_dmi_table);
37378f1699659963fff97975df44db6d5dbe7218e55Alex Chiang
37478f1699659963fff97975df44db6d5dbe7218e55Alex Chiang	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
37578f1699659963fff97975df44db6d5dbe7218e55Alex Chiang			    ACPI_UINT32_MAX,
37678f1699659963fff97975df44db6d5dbe7218e55Alex Chiang			    early_init_pdc, NULL, NULL, NULL);
377c1e0ddbf0a97e1704d7f13b4934f9acca002402dYinghai Lu	acpi_get_devices("ACPI0007", early_init_pdc, NULL, NULL);
37878f1699659963fff97975df44db6d5dbe7218e55Alex Chiang}
379