diff options
Diffstat (limited to 'drivers/acpi/acpi_processor.c')
| -rw-r--r-- | drivers/acpi/acpi_processor.c | 145 | 
1 files changed, 83 insertions, 62 deletions
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 7a0dd35d62c9..9916cc7ced39 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -35,6 +35,17 @@ EXPORT_PER_CPU_SYMBOL(processors);  struct acpi_processor_errata errata __read_mostly;  EXPORT_SYMBOL_GPL(errata); +acpi_handle acpi_get_processor_handle(int cpu) +{ +	struct acpi_processor *pr; + +	pr = per_cpu(processors, cpu); +	if (pr) +		return pr->handle; + +	return NULL; +} +  static int acpi_processor_errata_piix4(struct pci_dev *dev)  {  	u8 value1 = 0; @@ -183,20 +194,44 @@ static void __init acpi_pcc_cpufreq_init(void) {}  #endif /* CONFIG_X86 */  /* Initialization */ +static DEFINE_PER_CPU(void *, processor_device_array); + +static int acpi_processor_set_per_cpu(struct acpi_processor *pr, +				      struct acpi_device *device) +{ +	BUG_ON(pr->id >= nr_cpu_ids); + +	/* +	 * Buggy BIOS check. +	 * ACPI id of processors can be reported wrongly by the BIOS. +	 * Don't trust it blindly +	 */ +	if (per_cpu(processor_device_array, pr->id) != NULL && +	    per_cpu(processor_device_array, pr->id) != device) { +		dev_warn(&device->dev, +			 "BIOS reported wrong ACPI id %d for the processor\n", +			 pr->id); +		return -EINVAL; +	} +	/* +	 * processor_device_array is not cleared on errors to allow buggy BIOS +	 * checks. +	 */ +	per_cpu(processor_device_array, pr->id) = device; +	per_cpu(processors, pr->id) = pr; + +	return 0; +} +  #ifdef CONFIG_ACPI_HOTPLUG_CPU -static int acpi_processor_hotadd_init(struct acpi_processor *pr) +static int acpi_processor_hotadd_init(struct acpi_processor *pr, +				      struct acpi_device *device)  { -	unsigned long long sta; -	acpi_status status;  	int ret;  	if (invalid_phys_cpuid(pr->phys_id))  		return -ENODEV; -	status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta); -	if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) -		return -ENODEV; -  	cpu_maps_update_begin();  	cpus_write_lock(); @@ -204,19 +239,26 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)  	if (ret)  		goto out; +	ret = acpi_processor_set_per_cpu(pr, device); +	if (ret) { +		acpi_unmap_cpu(pr->id); +		goto out; +	} +  	ret = arch_register_cpu(pr->id);  	if (ret) { +		/* Leave the processor device array in place to detect buggy bios */ +		per_cpu(processors, pr->id) = NULL;  		acpi_unmap_cpu(pr->id);  		goto out;  	}  	/* -	 * CPU got hot-added, but cpu_data is not initialized yet.  Set a flag -	 * to delay cpu_idle/throttling initialization and do it when the CPU -	 * gets online for the first time. +	 * CPU got hot-added, but cpu_data is not initialized yet. Do +	 * cpu_idle/throttling initialization when the CPU gets online for +	 * the first time.  	 */  	pr_info("CPU%d has been hot-added\n", pr->id); -	pr->flags.need_hotplug_init = 1;  out:  	cpus_write_unlock(); @@ -224,7 +266,8 @@ out:  	return ret;  }  #else -static inline int acpi_processor_hotadd_init(struct acpi_processor *pr) +static inline int acpi_processor_hotadd_init(struct acpi_processor *pr, +					     struct acpi_device *device)  {  	return -ENODEV;  } @@ -239,6 +282,7 @@ static int acpi_processor_get_info(struct acpi_device *device)  	acpi_status status = AE_OK;  	static int cpu0_initialized;  	unsigned long long value; +	int ret;  	acpi_processor_errata(); @@ -315,19 +359,19 @@ static int acpi_processor_get_info(struct acpi_device *device)  	}  	/* -	 *  Extra Processor objects may be enumerated on MP systems with -	 *  less than the max # of CPUs. They should be ignored _iff -	 *  they are physically not present. -	 * -	 *  NOTE: Even if the processor has a cpuid, it may not be present -	 *  because cpuid <-> apicid mapping is persistent now. +	 *  This code is not called unless we know the CPU is present and +	 *  enabled. The two paths are: +	 *  a) Initially present CPUs on architectures that do not defer +	 *     their arch_register_cpu() calls until this point. +	 *  b) Hotplugged CPUs (enabled bit in _STA has transitioned from not +	 *     enabled to enabled)  	 */ -	if (invalid_logical_cpuid(pr->id) || !cpu_present(pr->id)) { -		int ret = acpi_processor_hotadd_init(pr); - -		if (ret) -			return ret; -	} +	if (!get_cpu_device(pr->id)) +		ret = acpi_processor_hotadd_init(pr, device); +	else +		ret = acpi_processor_set_per_cpu(pr, device); +	if (ret) +		return ret;  	/*  	 * On some boxes several processors use the same processor bus id. @@ -372,8 +416,6 @@ static int acpi_processor_get_info(struct acpi_device *device)   * (cpu_data(cpu)) values, like CPU feature flags, family, model, etc.   * Such things have to be put in and set up by the processor driver's .probe().   */ -static DEFINE_PER_CPU(void *, processor_device_array); -  static int acpi_processor_add(struct acpi_device *device,  					const struct acpi_device_id *id)  { @@ -400,39 +442,17 @@ static int acpi_processor_add(struct acpi_device *device,  	result = acpi_processor_get_info(device);  	if (result) /* Processor is not physically present or unavailable */ -		return 0; - -	BUG_ON(pr->id >= nr_cpu_ids); - -	/* -	 * Buggy BIOS check. -	 * ACPI id of processors can be reported wrongly by the BIOS. -	 * Don't trust it blindly -	 */ -	if (per_cpu(processor_device_array, pr->id) != NULL && -	    per_cpu(processor_device_array, pr->id) != device) { -		dev_warn(&device->dev, -			"BIOS reported wrong ACPI id %d for the processor\n", -			pr->id); -		/* Give up, but do not abort the namespace scan. */ -		goto err; -	} -	/* -	 * processor_device_array is not cleared on errors to allow buggy BIOS -	 * checks. -	 */ -	per_cpu(processor_device_array, pr->id) = device; -	per_cpu(processors, pr->id) = pr; +		goto err_clear_driver_data;  	dev = get_cpu_device(pr->id);  	if (!dev) {  		result = -ENODEV; -		goto err; +		goto err_clear_per_cpu;  	}  	result = acpi_bind_one(dev, device);  	if (result) -		goto err; +		goto err_clear_per_cpu;  	pr->dev = dev; @@ -443,10 +463,11 @@ static int acpi_processor_add(struct acpi_device *device,  	dev_err(dev, "Processor driver could not be attached\n");  	acpi_unbind_one(dev); - err: -	free_cpumask_var(pr->throttling.shared_cpu_map); -	device->driver_data = NULL; + err_clear_per_cpu:  	per_cpu(processors, pr->id) = NULL; + err_clear_driver_data: +	device->driver_data = NULL; +	free_cpumask_var(pr->throttling.shared_cpu_map);   err_free_pr:  	kfree(pr);  	return result; @@ -454,7 +475,7 @@ static int acpi_processor_add(struct acpi_device *device,  #ifdef CONFIG_ACPI_HOTPLUG_CPU  /* Removal */ -static void acpi_processor_remove(struct acpi_device *device) +static void acpi_processor_post_eject(struct acpi_device *device)  {  	struct acpi_processor *pr; @@ -476,10 +497,6 @@ static void acpi_processor_remove(struct acpi_device *device)  	device_release_driver(pr->dev);  	acpi_unbind_one(pr->dev); -	/* Clean up. */ -	per_cpu(processor_device_array, pr->id) = NULL; -	per_cpu(processors, pr->id) = NULL; -  	cpu_maps_update_begin();  	cpus_write_lock(); @@ -487,6 +504,10 @@ static void acpi_processor_remove(struct acpi_device *device)  	arch_unregister_cpu(pr->id);  	acpi_unmap_cpu(pr->id); +	/* Clean up. */ +	per_cpu(processor_device_array, pr->id) = NULL; +	per_cpu(processors, pr->id) = NULL; +  	cpus_write_unlock();  	cpu_maps_update_done(); @@ -598,9 +619,9 @@ static bool __init acpi_early_processor_osc(void)  void __init acpi_early_processor_control_setup(void)  {  	if (acpi_early_processor_osc()) { -		pr_info("_OSC evaluated successfully for all CPUs\n"); +		pr_debug("_OSC evaluated successfully for all CPUs\n");  	} else { -		pr_info("_OSC evaluation for CPUs failed, trying _PDC\n"); +		pr_debug("_OSC evaluation for CPUs failed, trying _PDC\n");  		acpi_early_processor_set_pdc();  	}  } @@ -622,7 +643,7 @@ static struct acpi_scan_handler processor_handler = {  	.ids = processor_device_ids,  	.attach = acpi_processor_add,  #ifdef CONFIG_ACPI_HOTPLUG_CPU -	.detach = acpi_processor_remove, +	.post_eject = acpi_processor_post_eject,  #endif  	.hotplug = {  		.enabled = true,  |