diff options
Diffstat (limited to 'drivers/acpi/acpi_processor.c')
| -rw-r--r-- | drivers/acpi/acpi_processor.c | 124 | 
1 files changed, 92 insertions, 32 deletions
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index f9aa02cac6d1..c711db8a9c33 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -9,9 +9,11 @@   * Copyright (C) 2013, Intel Corporation   *                     Rafael J. Wysocki <rafael.j.wysocki@intel.com>   */ +#define pr_fmt(fmt) "ACPI: " fmt  #include <linux/acpi.h>  #include <linux/device.h> +#include <linux/dmi.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/pci.h> @@ -21,6 +23,8 @@  #include <asm/cpu.h> +#include <xen/xen.h> +  #include "internal.h"  DEFINE_PER_CPU(struct acpi_processor *, processors); @@ -508,54 +512,110 @@ static void acpi_processor_remove(struct acpi_device *device)  }  #endif /* CONFIG_ACPI_HOTPLUG_CPU */ -#ifdef CONFIG_X86 -static bool acpi_hwp_native_thermal_lvt_set; -static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle, -							  u32 lvl, -							  void *context, -							  void **rv) +#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC +bool __init processor_physically_present(acpi_handle handle) +{ +	int cpuid, type; +	u32 acpi_id; +	acpi_status status; +	acpi_object_type acpi_type; +	unsigned long long tmp; +	union acpi_object object = {}; +	struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; + +	status = acpi_get_type(handle, &acpi_type); +	if (ACPI_FAILURE(status)) +		return false; + +	switch (acpi_type) { +	case ACPI_TYPE_PROCESSOR: +		status = acpi_evaluate_object(handle, NULL, NULL, &buffer); +		if (ACPI_FAILURE(status)) +			return false; +		acpi_id = object.processor.proc_id; +		break; +	case ACPI_TYPE_DEVICE: +		status = acpi_evaluate_integer(handle, METHOD_NAME__UID, +					       NULL, &tmp); +		if (ACPI_FAILURE(status)) +			return false; +		acpi_id = tmp; +		break; +	default: +		return false; +	} + +	if (xen_initial_domain()) +		/* +		 * When running as a Xen dom0 the number of processors Linux +		 * sees can be different from the real number of processors on +		 * the system, and we still need to execute _PDC or _OSC for +		 * all of them. +		 */ +		return xen_processor_present(acpi_id); + +	type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; +	cpuid = acpi_get_cpuid(handle, type, acpi_id); + +	return !invalid_logical_cpuid(cpuid); +} + +/* vendor specific UUID indicating an Intel platform */ +static u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953"; + +static acpi_status __init acpi_processor_osc(acpi_handle handle, u32 lvl, +					     void *context, void **rv)  { -	u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953"; -	u32 capbuf[2]; +	u32 capbuf[2] = {};  	struct acpi_osc_context osc_context = {  		.uuid_str = sb_uuid_str,  		.rev = 1,  		.cap.length = 8,  		.cap.pointer = capbuf,  	}; +	acpi_status status; -	if (acpi_hwp_native_thermal_lvt_set) -		return AE_CTRL_TERMINATE; +	if (!processor_physically_present(handle)) +		return AE_OK; -	capbuf[0] = 0x0000; -	capbuf[1] = 0x1000; /* set bit 12 */ +	arch_acpi_set_proc_cap_bits(&capbuf[OSC_SUPPORT_DWORD]); -	if (ACPI_SUCCESS(acpi_run_osc(handle, &osc_context))) { -		if (osc_context.ret.pointer && osc_context.ret.length > 1) { -			u32 *capbuf_ret = osc_context.ret.pointer; +	status = acpi_run_osc(handle, &osc_context); +	if (ACPI_FAILURE(status)) +		return status; -			if (capbuf_ret[1] & 0x1000) { -				acpi_handle_info(handle, -					"_OSC native thermal LVT Acked\n"); -				acpi_hwp_native_thermal_lvt_set = true; -			} -		} -		kfree(osc_context.ret.pointer); -	} +	kfree(osc_context.ret.pointer);  	return AE_OK;  } -void __init acpi_early_processor_osc(void) +static bool __init acpi_early_processor_osc(void)  { -	if (boot_cpu_has(X86_FEATURE_HWP)) { -		acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, -				    ACPI_UINT32_MAX, -				    acpi_hwp_native_thermal_lvt_osc, -				    NULL, NULL, NULL); -		acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, -				 acpi_hwp_native_thermal_lvt_osc, -				 NULL, NULL); +	acpi_status status; + +	acpi_proc_quirk_mwait_check(); + +	status = acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, +				     ACPI_UINT32_MAX, acpi_processor_osc, NULL, +				     NULL, NULL); +	if (ACPI_FAILURE(status)) +		return false; + +	status = acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, acpi_processor_osc, +				  NULL, NULL); +	if (ACPI_FAILURE(status)) +		return false; + +	return true; +} + +void __init acpi_early_processor_control_setup(void) +{ +	if (acpi_early_processor_osc()) { +		pr_info("_OSC evaluated successfully for all CPUs\n"); +	} else { +		pr_info("_OSC evaluation for CPUs failed, trying _PDC\n"); +		acpi_early_processor_set_pdc();  	}  }  #endif  | 
