diff options
31 files changed, 1502 insertions, 1434 deletions
| diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index a5cc0db63d7a..ed511af0f79a 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -582,3 +582,10 @@ Why:	The paravirt mmu host support is slower than non-paravirt mmu, both  Who:	Avi Kivity <avi@redhat.com>  ---------------------------- + +What: 	"acpi=ht" boot option +When:	2.6.35 +Why:	Useful in 2003, implementation is a hack. +	Generally invoked by accident today. +	Seen as doing more harm than good. +Who:	Len Brown <len.brown@intel.com> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 3bc48b0bd3a9..e4cbca58536c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -200,10 +200,6 @@ and is between 256 and 4096 characters. It is defined in the file  			acpi_display_output=video  			See above. -	acpi_early_pdc_eval	[HW,ACPI] Evaluate processor _PDC methods -				early. Needed on some platforms to properly -				initialize the EC. -  	acpi_irq_balance [HW,ACPI]  			ACPI will balance active IRQs  			default in APIC mode diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index a7ca07f3754e..f1c9f70b4e45 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -44,6 +44,7 @@  #include <linux/efi.h>  #include <linux/mmzone.h>  #include <linux/nodemask.h> +#include <acpi/processor.h>  #include <asm/io.h>  #include <asm/iosapic.h>  #include <asm/machvec.h> @@ -907,6 +908,8 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)  	cpu_set(cpu, cpu_present_map);  	ia64_cpu_to_sapicid[cpu] = physid; +	acpi_processor_set_pdc(handle); +  	*pcpu = cpu;  	return (0);  } diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index a54d714545ff..0061ea263061 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -490,6 +490,7 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)   *  ACPI based hotplug support for CPU   */  #ifdef CONFIG_ACPI_HOTPLUG_CPU +#include <acpi/processor.h>  static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)  { @@ -567,6 +568,8 @@ static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)  		goto free_new_map;  	} +	acpi_processor_set_pdc(handle); +  	cpu = cpumask_first(new_map);  	acpi_map_cpu2node(handle, cpu, physid); @@ -1293,23 +1296,6 @@ static int __init dmi_disable_acpi(const struct dmi_system_id *d)  }  /* - * Limit ACPI to CPU enumeration for HT - */ -static int __init force_acpi_ht(const struct dmi_system_id *d) -{ -	if (!acpi_force) { -		printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", -		       d->ident); -		disable_acpi(); -		acpi_ht = 1; -	} else { -		printk(KERN_NOTICE -		       "Warning: acpi=force overrules DMI blacklist: acpi=ht\n"); -	} -	return 0; -} - -/*   * Force ignoring BIOS IRQ0 pin2 override   */  static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d) @@ -1345,82 +1331,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {  	 },  	/* -	 * Boxes that need acpi=ht -	 */ -	{ -	 .callback = force_acpi_ht, -	 .ident = "FSC Primergy T850", -	 .matches = { -		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), -		     DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"), -		     }, -	 }, -	{ -	 .callback = force_acpi_ht, -	 .ident = "HP VISUALIZE NT Workstation", -	 .matches = { -		     DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), -		     DMI_MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"), -		     }, -	 }, -	{ -	 .callback = force_acpi_ht, -	 .ident = "Compaq Workstation W8000", -	 .matches = { -		     DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), -		     DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"), -		     }, -	 }, -	{ -	 .callback = force_acpi_ht, -	 .ident = "ASUS CUR-DLS", -	 .matches = { -		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -		     DMI_MATCH(DMI_BOARD_NAME, "CUR-DLS"), -		     }, -	 }, -	{ -	 .callback = force_acpi_ht, -	 .ident = "ABIT i440BX-W83977", -	 .matches = { -		     DMI_MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"), -		     DMI_MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"), -		     }, -	 }, -	{ -	 .callback = force_acpi_ht, -	 .ident = "IBM Bladecenter", -	 .matches = { -		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), -		     DMI_MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"), -		     }, -	 }, -	{ -	 .callback = force_acpi_ht, -	 .ident = "IBM eServer xSeries 360", -	 .matches = { -		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), -		     DMI_MATCH(DMI_BOARD_NAME, "eServer xSeries 360"), -		     }, -	 }, -	{ -	 .callback = force_acpi_ht, -	 .ident = "IBM eserver xSeries 330", -	 .matches = { -		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), -		     DMI_MATCH(DMI_BOARD_NAME, "eserver xSeries 330"), -		     }, -	 }, -	{ -	 .callback = force_acpi_ht, -	 .ident = "IBM eserver xSeries 440", -	 .matches = { -		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), -		     DMI_MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"), -		     }, -	 }, - -	/*  	 * Boxes that need ACPI PCI IRQ routing disabled  	 */  	{ @@ -1652,8 +1562,10 @@ static int __init parse_acpi(char *arg)  	}  	/* Limit ACPI just to boot-time to enable HT */  	else if (strcmp(arg, "ht") == 0) { -		if (!acpi_force) +		if (!acpi_force) { +			printk(KERN_WARNING "acpi=ht will be removed in Linux-2.6.35\n");  			disable_acpi(); +		}  		acpi_ht = 1;  	}  	/* acpi=rsdt use RSDT instead of XSDT */ diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 66cc3f36a954..a8d8998dd5c5 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -32,7 +32,7 @@ acpi-$(CONFIG_ACPI_SLEEP)	+= proc.o  #  acpi-y				+= bus.o glue.o  acpi-y				+= scan.o -acpi-y				+= processor_pdc.o +acpi-y				+= processor_core.o  acpi-y				+= ec.o  acpi-$(CONFIG_ACPI_DOCK)	+= dock.o  acpi-y				+= pci_root.o pci_link.o pci_irq.o pci_bind.o @@ -61,7 +61,7 @@ obj-$(CONFIG_ACPI_SBS)		+= sbs.o  obj-$(CONFIG_ACPI_POWER_METER)	+= power_meter.o  # processor has its own "processor." module_param namespace -processor-y			:= processor_core.o processor_throttling.o +processor-y			:= processor_driver.o processor_throttling.o  processor-y			+= processor_idle.o processor_thermal.o  processor-$(CONFIG_CPU_FREQ)	+= processor_perflib.o diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index cc8a10268f68..7116bc86494d 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -375,8 +375,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,  		return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);  	} -	/* Must have a valid thread ID */ - +	/* Must have a valid thread. */  	if (!walk_state->thread) {  		ACPI_ERROR((AE_INFO,  			    "Cannot release Mutex [%4.4s], null thread info", diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 58d2c91ba62b..75f39f2c166d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -54,6 +54,7 @@  #define ACPI_BATTERY_DEVICE_NAME	"Battery"  #define ACPI_BATTERY_NOTIFY_STATUS	0x80  #define ACPI_BATTERY_NOTIFY_INFO	0x81 +#define ACPI_BATTERY_NOTIFY_THRESHOLD   0x82  #define _COMPONENT		ACPI_BATTERY_COMPONENT @@ -88,10 +89,15 @@ static const struct acpi_device_id battery_device_ids[] = {  MODULE_DEVICE_TABLE(acpi, battery_device_ids); -/* For buggy DSDTs that report negative 16-bit values for either charging - * or discharging current and/or report 0 as 65536 due to bad math. - */ -#define QUIRK_SIGNED16_CURRENT 0x0001 +enum { +	ACPI_BATTERY_ALARM_PRESENT, +	ACPI_BATTERY_XINFO_PRESENT, +	/* For buggy DSDTs that report negative 16-bit values for either +	 * charging or discharging current and/or report 0 as 65536 +	 * due to bad math. +	 */ +	ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, +};  struct acpi_battery {  	struct mutex lock; @@ -109,6 +115,12 @@ struct acpi_battery {  	int design_voltage;  	int design_capacity_warning;  	int design_capacity_low; +	int cycle_count; +	int measurement_accuracy; +	int max_sampling_time; +	int min_sampling_time; +	int max_averaging_interval; +	int min_averaging_interval;  	int capacity_granularity_1;  	int capacity_granularity_2;  	int alarm; @@ -118,8 +130,7 @@ struct acpi_battery {  	char oem_info[32];  	int state;  	int power_unit; -	u8 alarm_present; -	long quirks; +	unsigned long flags;  };  #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); @@ -198,6 +209,9 @@ static int acpi_battery_get_property(struct power_supply *psy,  	case POWER_SUPPLY_PROP_TECHNOLOGY:  		val->intval = acpi_battery_technology(battery);  		break; +	case POWER_SUPPLY_PROP_CYCLE_COUNT: +		val->intval = battery->cycle_count; +		break;  	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:  		val->intval = battery->design_voltage * 1000;  		break; @@ -239,6 +253,7 @@ static enum power_supply_property charge_battery_props[] = {  	POWER_SUPPLY_PROP_STATUS,  	POWER_SUPPLY_PROP_PRESENT,  	POWER_SUPPLY_PROP_TECHNOLOGY, +	POWER_SUPPLY_PROP_CYCLE_COUNT,  	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,  	POWER_SUPPLY_PROP_VOLTAGE_NOW,  	POWER_SUPPLY_PROP_CURRENT_NOW, @@ -254,6 +269,7 @@ static enum power_supply_property energy_battery_props[] = {  	POWER_SUPPLY_PROP_STATUS,  	POWER_SUPPLY_PROP_PRESENT,  	POWER_SUPPLY_PROP_TECHNOLOGY, +	POWER_SUPPLY_PROP_CYCLE_COUNT,  	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,  	POWER_SUPPLY_PROP_VOLTAGE_NOW,  	POWER_SUPPLY_PROP_CURRENT_NOW, @@ -305,6 +321,28 @@ static struct acpi_offsets info_offsets[] = {  	{offsetof(struct acpi_battery, oem_info), 1},  }; +static struct acpi_offsets extended_info_offsets[] = { +	{offsetof(struct acpi_battery, power_unit), 0}, +	{offsetof(struct acpi_battery, design_capacity), 0}, +	{offsetof(struct acpi_battery, full_charge_capacity), 0}, +	{offsetof(struct acpi_battery, technology), 0}, +	{offsetof(struct acpi_battery, design_voltage), 0}, +	{offsetof(struct acpi_battery, design_capacity_warning), 0}, +	{offsetof(struct acpi_battery, design_capacity_low), 0}, +	{offsetof(struct acpi_battery, cycle_count), 0}, +	{offsetof(struct acpi_battery, measurement_accuracy), 0}, +	{offsetof(struct acpi_battery, max_sampling_time), 0}, +	{offsetof(struct acpi_battery, min_sampling_time), 0}, +	{offsetof(struct acpi_battery, max_averaging_interval), 0}, +	{offsetof(struct acpi_battery, min_averaging_interval), 0}, +	{offsetof(struct acpi_battery, capacity_granularity_1), 0}, +	{offsetof(struct acpi_battery, capacity_granularity_2), 0}, +	{offsetof(struct acpi_battery, model_number), 1}, +	{offsetof(struct acpi_battery, serial_number), 1}, +	{offsetof(struct acpi_battery, type), 1}, +	{offsetof(struct acpi_battery, oem_info), 1}, +}; +  static int extract_package(struct acpi_battery *battery,  			   union acpi_object *package,  			   struct acpi_offsets *offsets, int num) @@ -350,22 +388,29 @@ static int acpi_battery_get_info(struct acpi_battery *battery)  {  	int result = -EFAULT;  	acpi_status status = 0; +	char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)? +			"_BIX" : "_BIF"; +  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };  	if (!acpi_battery_present(battery))  		return 0;  	mutex_lock(&battery->lock); -	status = acpi_evaluate_object(battery->device->handle, "_BIF", -				      NULL, &buffer); +	status = acpi_evaluate_object(battery->device->handle, name, +						NULL, &buffer);  	mutex_unlock(&battery->lock);  	if (ACPI_FAILURE(status)) { -		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); +		ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name));  		return -ENODEV;  	} - -	result = extract_package(battery, buffer.pointer, -				 info_offsets, ARRAY_SIZE(info_offsets)); +	if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)) +		result = extract_package(battery, buffer.pointer, +				extended_info_offsets, +				ARRAY_SIZE(extended_info_offsets)); +	else +		result = extract_package(battery, buffer.pointer, +				info_offsets, ARRAY_SIZE(info_offsets));  	kfree(buffer.pointer);  	return result;  } @@ -399,7 +444,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery)  	battery->update_time = jiffies;  	kfree(buffer.pointer); -	if ((battery->quirks & QUIRK_SIGNED16_CURRENT) && +	if (test_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags) &&  	    battery->rate_now != -1)  		battery->rate_now = abs((s16)battery->rate_now); @@ -412,7 +457,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery)  	union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER };  	struct acpi_object_list arg_list = { 1, &arg0 }; -	if (!acpi_battery_present(battery)|| !battery->alarm_present) +	if (!acpi_battery_present(battery) || +	    !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags))  		return -ENODEV;  	arg0.integer.value = battery->alarm; @@ -437,10 +483,10 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery)  	/* See if alarms are supported, and if so, set default */  	status = acpi_get_handle(battery->device->handle, "_BTP", &handle);  	if (ACPI_FAILURE(status)) { -		battery->alarm_present = 0; +		clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);  		return 0;  	} -	battery->alarm_present = 1; +	set_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);  	if (!battery->alarm)  		battery->alarm = battery->design_capacity_warning;  	return acpi_battery_set_alarm(battery); @@ -510,9 +556,8 @@ static void sysfs_remove_battery(struct acpi_battery *battery)  static void acpi_battery_quirks(struct acpi_battery *battery)  { -	battery->quirks = 0;  	if (dmi_name_in_vendors("Acer") && battery->power_unit) { -		battery->quirks |= QUIRK_SIGNED16_CURRENT; +		set_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags);  	}  } @@ -590,6 +635,7 @@ static int acpi_battery_print_info(struct seq_file *seq, int result)  	seq_printf(seq, "design capacity low:     %d %sh\n",  		   battery->design_capacity_low,  		   acpi_battery_units(battery)); +	seq_printf(seq, "cycle count:		  %i\n", battery->cycle_count);  	seq_printf(seq, "capacity granularity 1:  %d %sh\n",  		   battery->capacity_granularity_1,  		   acpi_battery_units(battery)); @@ -841,6 +887,7 @@ static int acpi_battery_add(struct acpi_device *device)  {  	int result = 0;  	struct acpi_battery *battery = NULL; +	acpi_handle handle;  	if (!device)  		return -EINVAL;  	battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); @@ -851,6 +898,9 @@ static int acpi_battery_add(struct acpi_device *device)  	strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);  	device->driver_data = battery;  	mutex_init(&battery->lock); +	if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, +			"_BIX", &handle))) +		set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);  	acpi_battery_update(battery);  #ifdef CONFIG_ACPI_PROCFS_POWER  	result = acpi_battery_add_fs(device); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a52126e46307..b70cd3756142 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -190,16 +190,16 @@ int acpi_bus_get_power(acpi_handle handle, int *state)  		 * Get the device's power state either directly (via _PSC) or  		 * indirectly (via power resources).  		 */ -		if (device->power.flags.explicit_get) { +		if (device->power.flags.power_resources) { +			result = acpi_power_get_inferred_state(device); +			if (result) +				return result; +		} else if (device->power.flags.explicit_get) {  			status = acpi_evaluate_integer(device->handle, "_PSC",  						       NULL, &psc);  			if (ACPI_FAILURE(status))  				return -ENODEV;  			device->power.state = (int)psc; -		} else if (device->power.flags.power_resources) { -			result = acpi_power_get_inferred_state(device); -			if (result) -				return result;  		}  		*state = device->power.state; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index d7a6bbbb834c..1ac28c6a672e 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -76,8 +76,9 @@ enum ec_command {  enum {  	EC_FLAGS_QUERY_PENDING,		/* Query is pending */  	EC_FLAGS_GPE_STORM,		/* GPE storm detected */ -	EC_FLAGS_HANDLERS_INSTALLED	/* Handlers for GPE and +	EC_FLAGS_HANDLERS_INSTALLED,	/* Handlers for GPE and  					 * OpReg are installed */ +	EC_FLAGS_FROZEN,		/* Transactions are suspended */  };  /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -291,6 +292,10 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)  	if (t->rdata)  		memset(t->rdata, 0, t->rlen);  	mutex_lock(&ec->lock); +	if (test_bit(EC_FLAGS_FROZEN, &ec->flags)) { +		status = -EINVAL; +		goto unlock; +	}  	if (ec->global_lock) {  		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);  		if (ACPI_FAILURE(status)) { @@ -453,6 +458,32 @@ int ec_transaction(u8 command,  EXPORT_SYMBOL(ec_transaction); +void acpi_ec_suspend_transactions(void) +{ +	struct acpi_ec *ec = first_ec; + +	if (!ec) +		return; + +	mutex_lock(&ec->lock); +	/* Prevent transactions from being carried out */ +	set_bit(EC_FLAGS_FROZEN, &ec->flags); +	mutex_unlock(&ec->lock); +} + +void acpi_ec_resume_transactions(void) +{ +	struct acpi_ec *ec = first_ec; + +	if (!ec) +		return; + +	mutex_lock(&ec->lock); +	/* Allow transactions to be carried out again */ +	clear_bit(EC_FLAGS_FROZEN, &ec->flags); +	mutex_unlock(&ec->lock); +} +  static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)  {  	int result; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 9c4c962e46e3..e28411367239 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -49,6 +49,8 @@ void acpi_early_processor_set_pdc(void);  int acpi_ec_init(void);  int acpi_ec_ecdt_probe(void);  int acpi_boot_ec_enable(void); +void acpi_ec_suspend_transactions(void); +void acpi_ec_resume_transactions(void);  /*--------------------------------------------------------------------------                                    Suspend/Resume diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index e9b7b402dbfb..791ac7b0f8df 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -1,383 +1,62 @@  /* - * acpi_processor.c - ACPI Processor Driver ($Revision: 71 $) + * Copyright (C) 2005 Intel Corporation + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.   * - *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> - *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> - *  Copyright (C) 2004       Dominik Brodowski <linux@brodo.de> - *  Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> - *  			- Added processor hotplug support - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - *  This program is free software; you can redistribute it and/or modify - *  it under the terms of the GNU General Public License as published by - *  the Free Software Foundation; either version 2 of the License, or (at - *  your option) any later version. - * - *  This program is distributed in the hope that it will be useful, but - *  WITHOUT ANY WARRANTY; without even the implied warranty of - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - *  General Public License for more details. - * - *  You should have received a copy of the GNU General Public License along - *  with this program; if not, write to the Free Software Foundation, Inc., - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - *  TBD: - *	1. Make # power states dynamic. - *	2. Support duty_cycle values that span bit 4. - *	3. Optimize by having scheduler determine business instead of - *	   having us try to calculate it here. - *	4. Need C1 timing -- must modify kernel (IRQ handler) to get this. + *	Alex Chiang <achiang@hp.com> + *	- Unified x86/ia64 implementations + *	Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> + *	- Added _PDC for platforms with Intel CPUs   */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/pm.h> -#include <linux/cpufreq.h> -#include <linux/cpu.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h>  #include <linux/dmi.h> -#include <linux/moduleparam.h> -#include <linux/cpuidle.h> -#include <asm/io.h> -#include <asm/system.h> -#include <asm/cpu.h> -#include <asm/delay.h> -#include <asm/uaccess.h> -#include <asm/processor.h> -#include <asm/smp.h> -#include <asm/acpi.h> - -#include <acpi/acpi_bus.h>  #include <acpi/acpi_drivers.h>  #include <acpi/processor.h> -#define PREFIX "ACPI: " - -#define ACPI_PROCESSOR_CLASS		"processor" -#define ACPI_PROCESSOR_DEVICE_NAME	"Processor" -#define ACPI_PROCESSOR_FILE_INFO	"info" -#define ACPI_PROCESSOR_FILE_THROTTLING	"throttling" -#define ACPI_PROCESSOR_FILE_LIMIT	"limit" -#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 -#define ACPI_PROCESSOR_NOTIFY_POWER	0x81 -#define ACPI_PROCESSOR_NOTIFY_THROTTLING	0x82 - -#define ACPI_PROCESSOR_LIMIT_USER	0 -#define ACPI_PROCESSOR_LIMIT_THERMAL	1 +#include "internal.h" +#define PREFIX			"ACPI: "  #define _COMPONENT		ACPI_PROCESSOR_COMPONENT  ACPI_MODULE_NAME("processor_core"); -MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION("ACPI Processor Driver"); -MODULE_LICENSE("GPL"); - -static int acpi_processor_add(struct acpi_device *device); -static int acpi_processor_remove(struct acpi_device *device, int type); -#ifdef CONFIG_ACPI_PROCFS -static int acpi_processor_info_open_fs(struct inode *inode, struct file *file); -#endif -static void acpi_processor_notify(struct acpi_device *device, u32 event); -static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); -static int acpi_processor_handle_eject(struct acpi_processor *pr); - - -static const struct acpi_device_id processor_device_ids[] = { -	{ACPI_PROCESSOR_OBJECT_HID, 0}, -	{"ACPI0007", 0}, -	{"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, processor_device_ids); - -static struct acpi_driver acpi_processor_driver = { -	.name = "processor", -	.class = ACPI_PROCESSOR_CLASS, -	.ids = processor_device_ids, -	.ops = { -		.add = acpi_processor_add, -		.remove = acpi_processor_remove, -		.suspend = acpi_processor_suspend, -		.resume = acpi_processor_resume, -		.notify = acpi_processor_notify, -		}, -}; - -#define INSTALL_NOTIFY_HANDLER		1 -#define UNINSTALL_NOTIFY_HANDLER	2 -#ifdef CONFIG_ACPI_PROCFS -static const struct file_operations acpi_processor_info_fops = { -	.owner = THIS_MODULE, -	.open = acpi_processor_info_open_fs, -	.read = seq_read, -	.llseek = seq_lseek, -	.release = single_release, -}; -#endif - -DEFINE_PER_CPU(struct acpi_processor *, processors); -EXPORT_PER_CPU_SYMBOL(processors); - -struct acpi_processor_errata errata __read_mostly; - -/* -------------------------------------------------------------------------- -                                Errata Handling -   -------------------------------------------------------------------------- */ - -static int acpi_processor_errata_piix4(struct pci_dev *dev) +static int set_no_mwait(const struct dmi_system_id *id)  { -	u8 value1 = 0; -	u8 value2 = 0; - - -	if (!dev) -		return -EINVAL; - -	/* -	 * Note that 'dev' references the PIIX4 ACPI Controller. -	 */ - -	switch (dev->revision) { -	case 0: -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n")); -		break; -	case 1: -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n")); -		break; -	case 2: -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n")); -		break; -	case 3: -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n")); -		break; -	default: -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n")); -		break; -	} - -	switch (dev->revision) { - -	case 0:		/* PIIX4 A-step */ -	case 1:		/* PIIX4 B-step */ -		/* -		 * See specification changes #13 ("Manual Throttle Duty Cycle") -		 * and #14 ("Enabling and Disabling Manual Throttle"), plus -		 * erratum #5 ("STPCLK# Deassertion Time") from the January -		 * 2002 PIIX4 specification update.  Applies to only older -		 * PIIX4 models. -		 */ -		errata.piix4.throttle = 1; - -	case 2:		/* PIIX4E */ -	case 3:		/* PIIX4M */ -		/* -		 * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA -		 * Livelock") from the January 2002 PIIX4 specification update. -		 * Applies to all PIIX4 models. -		 */ - -		/* -		 * BM-IDE -		 * ------ -		 * Find the PIIX4 IDE Controller and get the Bus Master IDE -		 * Status register address.  We'll use this later to read -		 * each IDE controller's DMA status to make sure we catch all -		 * DMA activity. -		 */ -		dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, -				     PCI_DEVICE_ID_INTEL_82371AB, -				     PCI_ANY_ID, PCI_ANY_ID, NULL); -		if (dev) { -			errata.piix4.bmisx = pci_resource_start(dev, 4); -			pci_dev_put(dev); -		} - -		/* -		 * Type-F DMA -		 * ---------- -		 * Find the PIIX4 ISA Controller and read the Motherboard -		 * DMA controller's status to see if Type-F (Fast) DMA mode -		 * is enabled (bit 7) on either channel.  Note that we'll -		 * disable C3 support if this is enabled, as some legacy -		 * devices won't operate well if fast DMA is disabled. -		 */ -		dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, -				     PCI_DEVICE_ID_INTEL_82371AB_0, -				     PCI_ANY_ID, PCI_ANY_ID, NULL); -		if (dev) { -			pci_read_config_byte(dev, 0x76, &value1); -			pci_read_config_byte(dev, 0x77, &value2); -			if ((value1 & 0x80) || (value2 & 0x80)) -				errata.piix4.fdma = 1; -			pci_dev_put(dev); -		} - -		break; -	} - -	if (errata.piix4.bmisx) -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -				  "Bus master activity detection (BM-IDE) erratum enabled\n")); -	if (errata.piix4.fdma) -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -				  "Type-F DMA livelock erratum (C3 disabled)\n")); - +	printk(KERN_NOTICE PREFIX "%s detected - " +		"disabling mwait for CPU C-states\n", id->ident); +	idle_nomwait = 1;  	return 0;  } -static int acpi_processor_errata(struct acpi_processor *pr) -{ -	int result = 0; -	struct pci_dev *dev = NULL; - - -	if (!pr) -		return -EINVAL; - -	/* -	 * PIIX4 -	 */ -	dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, -			     PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, -			     PCI_ANY_ID, NULL); -	if (dev) { -		result = acpi_processor_errata_piix4(dev); -		pci_dev_put(dev); -	} - -	return result; -} - -/* -------------------------------------------------------------------------- -                              FS Interface (/proc) -   -------------------------------------------------------------------------- */ - -#ifdef CONFIG_ACPI_PROCFS -static struct proc_dir_entry *acpi_processor_dir = NULL; - -static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset) -{ -	struct acpi_processor *pr = seq->private; - - -	if (!pr) -		goto end; - -	seq_printf(seq, "processor id:            %d\n" -		   "acpi id:                 %d\n" -		   "bus mastering control:   %s\n" -		   "power management:        %s\n" -		   "throttling control:      %s\n" -		   "limit interface:         %s\n", -		   pr->id, -		   pr->acpi_id, -		   pr->flags.bm_control ? "yes" : "no", -		   pr->flags.power ? "yes" : "no", -		   pr->flags.throttling ? "yes" : "no", -		   pr->flags.limit ? "yes" : "no"); - -      end: -	return 0; -} - -static int acpi_processor_info_open_fs(struct inode *inode, struct file *file) -{ -	return single_open(file, acpi_processor_info_seq_show, -			   PDE(inode)->data); -} - -static int __cpuinit acpi_processor_add_fs(struct acpi_device *device) -{ -	struct proc_dir_entry *entry = NULL; - - -	if (!acpi_device_dir(device)) { -		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), -						     acpi_processor_dir); -		if (!acpi_device_dir(device)) -			return -ENODEV; -	} - -	/* 'info' [R] */ -	entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO, -				 S_IRUGO, acpi_device_dir(device), -				 &acpi_processor_info_fops, -				 acpi_driver_data(device)); -	if (!entry) -		return -EIO; - -	/* 'throttling' [R/W] */ -	entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING, -				 S_IFREG | S_IRUGO | S_IWUSR, -				 acpi_device_dir(device), -				 &acpi_processor_throttling_fops, -				 acpi_driver_data(device)); -	if (!entry) -		return -EIO; - -	/* 'limit' [R/W] */ -	entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT, -				 S_IFREG | S_IRUGO | S_IWUSR, -				 acpi_device_dir(device), -				 &acpi_processor_limit_fops, -				 acpi_driver_data(device)); -	if (!entry) -		return -EIO; -	return 0; -} -static int acpi_processor_remove_fs(struct acpi_device *device) -{ - -	if (acpi_device_dir(device)) { -		remove_proc_entry(ACPI_PROCESSOR_FILE_INFO, -				  acpi_device_dir(device)); -		remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, -				  acpi_device_dir(device)); -		remove_proc_entry(ACPI_PROCESSOR_FILE_LIMIT, -				  acpi_device_dir(device)); -		remove_proc_entry(acpi_device_bid(device), acpi_processor_dir); -		acpi_device_dir(device) = NULL; -	} - -	return 0; -} -#else -static inline int acpi_processor_add_fs(struct acpi_device *device) -{ -	return 0; -} -static inline int acpi_processor_remove_fs(struct acpi_device *device) -{ -	return 0; -} -#endif - -/* Use the acpiid in MADT to map cpus in case of SMP */ - -#ifndef CONFIG_SMP -static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id) { return -1; } -#else - -static struct acpi_table_madt *madt; +static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = { +	{ +	set_no_mwait, "IFL91 board", { +	DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), +	DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"), +	DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"), +	DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL}, +	{ +	set_no_mwait, "Extensa 5220", { +	DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), +	DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +	DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), +	DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, +	{}, +}; +#ifdef CONFIG_SMP  static int map_lapic_id(struct acpi_subtable_header *entry,  		 u32 acpi_id, int *apic_id)  {  	struct acpi_madt_local_apic *lapic =  		(struct acpi_madt_local_apic *)entry; -	if ((lapic->lapic_flags & ACPI_MADT_ENABLED) && -	    lapic->processor_id == acpi_id) { -		*apic_id = lapic->id; -		return 1; -	} -	return 0; + +	if (!(lapic->lapic_flags & ACPI_MADT_ENABLED)) +		return 0; + +	if (lapic->processor_id != acpi_id) +		return 0; + +	*apic_id = lapic->id; +	return 1;  }  static int map_x2apic_id(struct acpi_subtable_header *entry, @@ -385,22 +64,16 @@ static int map_x2apic_id(struct acpi_subtable_header *entry,  {  	struct acpi_madt_local_x2apic *apic =  		(struct acpi_madt_local_x2apic *)entry; -	u32 tmp = apic->local_apic_id; -	/* Only check enabled APICs*/  	if (!(apic->lapic_flags & ACPI_MADT_ENABLED))  		return 0; -	/* Device statement declaration type */ -	if (device_declaration) { -		if (apic->uid == acpi_id) -			goto found; +	if (device_declaration && (apic->uid == acpi_id)) { +		*apic_id = apic->local_apic_id; +		return 1;  	}  	return 0; -found: -	*apic_id = tmp; -	return 1;  }  static int map_lsapic_id(struct acpi_subtable_header *entry, @@ -408,35 +81,34 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,  {  	struct acpi_madt_local_sapic *lsapic =  		(struct acpi_madt_local_sapic *)entry; -	u32 tmp = (lsapic->id << 8) | lsapic->eid; -	/* Only check enabled APICs*/  	if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))  		return 0; -	/* Device statement declaration type */  	if (device_declaration) { -		if (entry->length < 16) -			printk(KERN_ERR PREFIX -			    "Invalid LSAPIC with Device type processor (SAPIC ID %#x)\n", -			    tmp); -		else if (lsapic->uid == acpi_id) -			goto found; -	/* Processor statement declaration type */ -	} else if (lsapic->processor_id == acpi_id) -		goto found; +		if ((entry->length < 16) || (lsapic->uid != acpi_id)) +			return 0; +	} else if (lsapic->processor_id != acpi_id) +		return 0; -	return 0; -found: -	*apic_id = tmp; +	*apic_id = (lsapic->id << 8) | lsapic->eid;  	return 1;  }  static int map_madt_entry(int type, u32 acpi_id)  {  	unsigned long madt_end, entry; +	static struct acpi_table_madt *madt; +	static int read_madt;  	int apic_id = -1; +	if (!read_madt) { +		if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, +					(struct acpi_table_header **)&madt))) +			madt = NULL; +		read_madt++; +	} +  	if (!madt)  		return apic_id; @@ -496,7 +168,7 @@ exit:  	return apic_id;  } -static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id) +int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)  {  	int i;  	int apic_id = -1; @@ -513,630 +185,170 @@ static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id)  	}  	return -1;  } +EXPORT_SYMBOL_GPL(acpi_get_cpuid);  #endif -/* -------------------------------------------------------------------------- -                                 Driver Interface -   -------------------------------------------------------------------------- */ - -static int acpi_processor_get_info(struct acpi_device *device) +static bool processor_physically_present(acpi_handle handle)  { -	acpi_status status = 0; +	int cpuid, type; +	u32 acpi_id; +	acpi_status status; +	acpi_object_type acpi_type; +	unsigned long long tmp;  	union acpi_object object = { 0 };  	struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; -	struct acpi_processor *pr; -	int cpu_index, device_declaration = 0; -	static int cpu0_initialized; - -	pr = acpi_driver_data(device); -	if (!pr) -		return -EINVAL; - -	if (num_online_cpus() > 1) -		errata.smp = TRUE; - -	acpi_processor_errata(pr); - -	/* -	 * Check to see if we have bus mastering arbitration control.  This -	 * is required for proper C3 usage (to maintain cache coherency). -	 */ -	if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) { -		pr->flags.bm_control = 1; -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -				  "Bus mastering arbitration control present\n")); -	} else -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -				  "No bus mastering arbitration control\n")); - -	if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) { -		/* Declared with "Processor" statement; match ProcessorID */ -		status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); -		if (ACPI_FAILURE(status)) { -			printk(KERN_ERR PREFIX "Evaluating processor object\n"); -			return -ENODEV; -		} - -		/* -		 * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. -		 *      >>> 'acpi_get_processor_id(acpi_id, &id)' in -		 *      arch/xxx/acpi.c -		 */ -		pr->acpi_id = object.processor.proc_id; -	} else { -		/* -		 * Declared with "Device" statement; match _UID. -		 * Note that we don't handle string _UIDs yet. -		 */ -		unsigned long long value; -		status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, -						NULL, &value); -		if (ACPI_FAILURE(status)) { -			printk(KERN_ERR PREFIX -			    "Evaluating processor _UID [%#x]\n", status); -			return -ENODEV; -		} -		device_declaration = 1; -		pr->acpi_id = value; -	} -	cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id); - -	/* Handle UP system running SMP kernel, with no LAPIC in MADT */ -	if (!cpu0_initialized && (cpu_index == -1) && -	    (num_online_cpus() == 1)) { -		cpu_index = 0; -	} - -	cpu0_initialized = 1; - -	pr->id = cpu_index; - -	/* -	 *  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. -	 */ -	if (pr->id == -1) { -		if (ACPI_FAILURE -		    (acpi_processor_hotadd_init(pr->handle, &pr->id))) { -			return -ENODEV; -		} -	} -	/* -	 * On some boxes several processors use the same processor bus id. -	 * But they are located in different scope. For example: -	 * \_SB.SCK0.CPU0 -	 * \_SB.SCK1.CPU0 -	 * Rename the processor device bus id. And the new bus id will be -	 * generated as the following format: -	 * CPU+CPU ID. -	 */ -	sprintf(acpi_device_bid(device), "CPU%X", pr->id); -	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, -			  pr->acpi_id)); - -	if (!object.processor.pblk_address) -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); -	else if (object.processor.pblk_length != 6) -		printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n", -			    object.processor.pblk_length); -	else { -		pr->throttling.address = object.processor.pblk_address; -		pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset; -		pr->throttling.duty_width = acpi_gbl_FADT.duty_width; - -		pr->pblk = object.processor.pblk_address; - -		/* -		 * We don't care about error returns - we just try to mark -		 * these reserved so that nobody else is confused into thinking -		 * that this region might be unused.. -		 * -		 * (In particular, allocating the IO range for Cardbus) -		 */ -		request_region(pr->throttling.address, 6, "ACPI CPU throttle"); -	} - -	/* -	 * If ACPI describes a slot number for this CPU, we can use it -	 * ensure we get the right value in the "physical id" field -	 * of /proc/cpuinfo -	 */ -	status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer); -	if (ACPI_SUCCESS(status)) -		arch_fix_phys_package_id(pr->id, object.integer.value); - -	return 0; -} - -static DEFINE_PER_CPU(void *, processor_device_array); - -static void acpi_processor_notify(struct acpi_device *device, u32 event) -{ -	struct acpi_processor *pr = acpi_driver_data(device); -	int saved; - -	if (!pr) -		return; -	switch (event) { -	case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: -		saved = pr->performance_platform_limit; -		acpi_processor_ppc_has_changed(pr, 1); -		if (saved == pr->performance_platform_limit) -			break; -		acpi_bus_generate_proc_event(device, event, -					pr->performance_platform_limit); -		acpi_bus_generate_netlink_event(device->pnp.device_class, -						  dev_name(&device->dev), event, -						  pr->performance_platform_limit); +	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_PROCESSOR_NOTIFY_POWER: -		acpi_processor_cst_has_changed(pr); -		acpi_bus_generate_proc_event(device, event, 0); -		acpi_bus_generate_netlink_event(device->pnp.device_class, -						  dev_name(&device->dev), event, 0); +	case ACPI_TYPE_DEVICE: +		status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp); +		if (ACPI_FAILURE(status)) +			return false; +		acpi_id = tmp;  		break; -	case ACPI_PROCESSOR_NOTIFY_THROTTLING: -		acpi_processor_tstate_has_changed(pr); -		acpi_bus_generate_proc_event(device, event, 0); -		acpi_bus_generate_netlink_event(device->pnp.device_class, -						  dev_name(&device->dev), event, 0);  	default: -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -				  "Unsupported event [0x%x]\n", event)); -		break; +		return false;  	} -	return; -} +	type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; +	cpuid = acpi_get_cpuid(handle, type, acpi_id); -static int acpi_cpu_soft_notify(struct notifier_block *nfb, -		unsigned long action, void *hcpu) -{ -	unsigned int cpu = (unsigned long)hcpu; -	struct acpi_processor *pr = per_cpu(processors, cpu); +	if (cpuid == -1) +		return false; -	if (action == CPU_ONLINE && pr) { -		acpi_processor_ppc_has_changed(pr, 0); -		acpi_processor_cst_has_changed(pr); -		acpi_processor_tstate_has_changed(pr); -	} -	return NOTIFY_OK; +	return true;  } -static struct notifier_block acpi_cpu_notifier = +static void acpi_set_pdc_bits(u32 *buf)  { -	    .notifier_call = acpi_cpu_soft_notify, -}; - -static int __cpuinit acpi_processor_add(struct acpi_device *device) -{ -	struct acpi_processor *pr = NULL; -	int result = 0; -	struct sys_device *sysdev; - -	pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); -	if (!pr) -		return -ENOMEM; - -	if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { -		kfree(pr); -		return -ENOMEM; -	} - -	pr->handle = device->handle; -	strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); -	strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); -	device->driver_data = pr; - -	result = acpi_processor_get_info(device); -	if (result) { -		/* Processor is physically not present */ -		return 0; -	} - -	BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0)); - -	/* -	 * 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) { -		printk(KERN_WARNING "BIOS reported wrong ACPI id " -			"for the processor\n"); -		result = -ENODEV; -		goto err_free_cpumask; -	} -	per_cpu(processor_device_array, pr->id) = device; +	buf[0] = ACPI_PDC_REVISION_ID; +	buf[1] = 1; -	per_cpu(processors, pr->id) = pr; +	/* Enable coordination with firmware's _TSD info */ +	buf[2] = ACPI_PDC_SMP_T_SWCOORD; -	result = acpi_processor_add_fs(device); -	if (result) -		goto err_free_cpumask; - -	sysdev = get_cpu_sysdev(pr->id); -	if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) { -		result = -EFAULT; -		goto err_remove_fs; -	} - -	/* _PDC call should be done before doing anything else (if reqd.). */ -	acpi_processor_set_pdc(pr->handle); - -#ifdef CONFIG_CPU_FREQ -	acpi_processor_ppc_has_changed(pr, 0); -#endif -	acpi_processor_get_throttling_info(pr); -	acpi_processor_get_limit_info(pr); - - -	acpi_processor_power_init(pr, device); - -	pr->cdev = thermal_cooling_device_register("Processor", device, -						&processor_cooling_ops); -	if (IS_ERR(pr->cdev)) { -		result = PTR_ERR(pr->cdev); -		goto err_power_exit; -	} - -	dev_dbg(&device->dev, "registered as cooling_device%d\n", -		 pr->cdev->id); - -	result = sysfs_create_link(&device->dev.kobj, -				   &pr->cdev->device.kobj, -				   "thermal_cooling"); -	if (result) { -		printk(KERN_ERR PREFIX "Create sysfs link\n"); -		goto err_thermal_unregister; -	} -	result = sysfs_create_link(&pr->cdev->device.kobj, -				   &device->dev.kobj, -				   "device"); -	if (result) { -		printk(KERN_ERR PREFIX "Create sysfs link\n"); -		goto err_remove_sysfs; -	} - -	return 0; - -err_remove_sysfs: -	sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); -err_thermal_unregister: -	thermal_cooling_device_unregister(pr->cdev); -err_power_exit: -	acpi_processor_power_exit(pr, device); -err_remove_fs: -	acpi_processor_remove_fs(device); -err_free_cpumask: -	free_cpumask_var(pr->throttling.shared_cpu_map); - -	return result; +	/* Twiddle arch-specific bits needed for _PDC */ +	arch_acpi_set_pdc_bits(buf);  } -static int acpi_processor_remove(struct acpi_device *device, int type) +static struct acpi_object_list *acpi_processor_alloc_pdc(void)  { -	struct acpi_processor *pr = NULL; - - -	if (!device || !acpi_driver_data(device)) -		return -EINVAL; - -	pr = acpi_driver_data(device); - -	if (pr->id >= nr_cpu_ids) -		goto free; +	struct acpi_object_list *obj_list; +	union acpi_object *obj; +	u32 *buf; -	if (type == ACPI_BUS_REMOVAL_EJECT) { -		if (acpi_processor_handle_eject(pr)) -			return -EINVAL; +	/* allocate and initialize pdc. It will be used later. */ +	obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); +	if (!obj_list) { +		printk(KERN_ERR "Memory allocation error\n"); +		return NULL;  	} -	acpi_processor_power_exit(pr, device); - -	sysfs_remove_link(&device->dev.kobj, "sysdev"); - -	acpi_processor_remove_fs(device); - -	if (pr->cdev) { -		sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); -		sysfs_remove_link(&pr->cdev->device.kobj, "device"); -		thermal_cooling_device_unregister(pr->cdev); -		pr->cdev = NULL; +	obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); +	if (!obj) { +		printk(KERN_ERR "Memory allocation error\n"); +		kfree(obj_list); +		return NULL;  	} -	per_cpu(processors, pr->id) = NULL; -	per_cpu(processor_device_array, pr->id) = NULL; - -free: -	free_cpumask_var(pr->throttling.shared_cpu_map); -	kfree(pr); - -	return 0; -} - -#ifdef CONFIG_ACPI_HOTPLUG_CPU -/**************************************************************************** - * 	Acpi processor hotplug support 				       	    * - ****************************************************************************/ - -static int is_processor_present(acpi_handle handle) -{ -	acpi_status status; -	unsigned long long sta = 0; - - -	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - -	if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT)) -		return 1; - -	/* -	 * _STA is mandatory for a processor that supports hot plug -	 */ -	if (status == AE_NOT_FOUND) -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -				"Processor does not support hot plug\n")); -	else -		ACPI_EXCEPTION((AE_INFO, status, -				"Processor Device is not present")); -	return 0; -} - -static -int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) -{ -	acpi_handle phandle; -	struct acpi_device *pdev; - - -	if (acpi_get_parent(handle, &phandle)) { -		return -ENODEV; +	buf = kmalloc(12, GFP_KERNEL); +	if (!buf) { +		printk(KERN_ERR "Memory allocation error\n"); +		kfree(obj); +		kfree(obj_list); +		return NULL;  	} -	if (acpi_bus_get_device(phandle, &pdev)) { -		return -ENODEV; -	} +	acpi_set_pdc_bits(buf); -	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) { -		return -ENODEV; -	} +	obj->type = ACPI_TYPE_BUFFER; +	obj->buffer.length = 12; +	obj->buffer.pointer = (u8 *) buf; +	obj_list->count = 1; +	obj_list->pointer = obj; -	return 0; +	return obj_list;  } -static void __ref acpi_processor_hotplug_notify(acpi_handle handle, -						u32 event, void *data) +/* + * _PDC is required for a BIOS-OS handshake for most of the newer + * ACPI processor features. + */ +static int +acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)  { -	struct acpi_processor *pr; -	struct acpi_device *device = NULL; -	int result; - +	acpi_status status = AE_OK; -	switch (event) { -	case ACPI_NOTIFY_BUS_CHECK: -	case ACPI_NOTIFY_DEVICE_CHECK: -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -		"Processor driver received %s event\n", -		       (event == ACPI_NOTIFY_BUS_CHECK) ? -		       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK")); - -		if (!is_processor_present(handle)) -			break; +	if (idle_nomwait) { +		/* +		 * If mwait is disabled for CPU C-states, the C2C3_FFH access +		 * mode will be disabled in the parameter of _PDC object. +		 * Of course C1_FFH access mode will also be disabled. +		 */ +		union acpi_object *obj; +		u32 *buffer = NULL; -		if (acpi_bus_get_device(handle, &device)) { -			result = acpi_processor_device_add(handle, &device); -			if (result) -				printk(KERN_ERR PREFIX -					    "Unable to add the device\n"); -			break; -		} -		break; -	case ACPI_NOTIFY_EJECT_REQUEST: -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -				  "received ACPI_NOTIFY_EJECT_REQUEST\n")); +		obj = pdc_in->pointer; +		buffer = (u32 *)(obj->buffer.pointer); +		buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH); -		if (acpi_bus_get_device(handle, &device)) { -			printk(KERN_ERR PREFIX -				    "Device don't exist, dropping EJECT\n"); -			break; -		} -		pr = acpi_driver_data(device); -		if (!pr) { -			printk(KERN_ERR PREFIX -				    "Driver data is NULL, dropping EJECT\n"); -			return; -		} -		break; -	default: -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -				  "Unsupported event [0x%x]\n", event)); -		break;  	} +	status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); -	return; -} - -static acpi_status -processor_walk_namespace_cb(acpi_handle handle, -			    u32 lvl, void *context, void **rv) -{ -	acpi_status status; -	int *action = context; -	acpi_object_type type = 0; - -	status = acpi_get_type(handle, &type);  	if (ACPI_FAILURE(status)) -		return (AE_OK); - -	if (type != ACPI_TYPE_PROCESSOR) -		return (AE_OK); - -	switch (*action) { -	case INSTALL_NOTIFY_HANDLER: -		acpi_install_notify_handler(handle, -					    ACPI_SYSTEM_NOTIFY, -					    acpi_processor_hotplug_notify, -					    NULL); -		break; -	case UNINSTALL_NOTIFY_HANDLER: -		acpi_remove_notify_handler(handle, -					   ACPI_SYSTEM_NOTIFY, -					   acpi_processor_hotplug_notify); -		break; -	default: -		break; -	} +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +		    "Could not evaluate _PDC, using legacy perf. control.\n")); -	return (AE_OK); +	return status;  } -static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu) +void acpi_processor_set_pdc(acpi_handle handle)  { +	struct acpi_object_list *obj_list; -	if (!is_processor_present(handle)) { -		return AE_ERROR; -	} +	if (arch_has_acpi_pdc() == false) +		return; -	if (acpi_map_lsapic(handle, p_cpu)) -		return AE_ERROR; +	obj_list = acpi_processor_alloc_pdc(); +	if (!obj_list) +		return; -	if (arch_register_cpu(*p_cpu)) { -		acpi_unmap_lsapic(*p_cpu); -		return AE_ERROR; -	} +	acpi_processor_eval_pdc(handle, obj_list); -	return AE_OK; +	kfree(obj_list->pointer->buffer.pointer); +	kfree(obj_list->pointer); +	kfree(obj_list);  } +EXPORT_SYMBOL_GPL(acpi_processor_set_pdc); -static int acpi_processor_handle_eject(struct acpi_processor *pr) +static acpi_status +early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)  { -	if (cpu_online(pr->id)) -		cpu_down(pr->id); +	if (processor_physically_present(handle) == false) +		return AE_OK; -	arch_unregister_cpu(pr->id); -	acpi_unmap_lsapic(pr->id); -	return (0); -} -#else -static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu) -{ -	return AE_ERROR; -} -static int acpi_processor_handle_eject(struct acpi_processor *pr) -{ -	return (-EINVAL); +	acpi_processor_set_pdc(handle); +	return AE_OK;  } -#endif -static -void acpi_processor_install_hotplug_notify(void) +void __init acpi_early_processor_set_pdc(void)  { -#ifdef CONFIG_ACPI_HOTPLUG_CPU -	int action = INSTALL_NOTIFY_HANDLER; -	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, -			    ACPI_ROOT_OBJECT, -			    ACPI_UINT32_MAX, -			    processor_walk_namespace_cb, NULL, &action, NULL); -#endif -	register_hotcpu_notifier(&acpi_cpu_notifier); -} +	/* +	 * Check whether the system is DMI table. If yes, OSPM +	 * should not use mwait for CPU-states. +	 */ +	dmi_check_system(processor_idle_dmi_table); -static -void acpi_processor_uninstall_hotplug_notify(void) -{ -#ifdef CONFIG_ACPI_HOTPLUG_CPU -	int action = UNINSTALL_NOTIFY_HANDLER; -	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, -			    ACPI_ROOT_OBJECT, +	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,  			    ACPI_UINT32_MAX, -			    processor_walk_namespace_cb, NULL, &action, NULL); -#endif -	unregister_hotcpu_notifier(&acpi_cpu_notifier); +			    early_init_pdc, NULL, NULL, NULL);  } - -/* - * We keep the driver loaded even when ACPI is not running. - * This is needed for the powernow-k8 driver, that works even without - * ACPI, but needs symbols from this driver - */ - -static int __init acpi_processor_init(void) -{ -	int result = 0; - -	if (acpi_disabled) -		return 0; - -	memset(&errata, 0, sizeof(errata)); - -#ifdef CONFIG_SMP -	if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, -				(struct acpi_table_header **)&madt))) -		madt = NULL; -#endif -#ifdef CONFIG_ACPI_PROCFS -	acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); -	if (!acpi_processor_dir) -		return -ENOMEM; -#endif -	result = cpuidle_register_driver(&acpi_idle_driver); -	if (result < 0) -		goto out_proc; - -	result = acpi_bus_register_driver(&acpi_processor_driver); -	if (result < 0) -		goto out_cpuidle; - -	acpi_processor_install_hotplug_notify(); - -	acpi_thermal_cpufreq_init(); - -	acpi_processor_ppc_init(); - -	acpi_processor_throttling_init(); - -	return 0; - -out_cpuidle: -	cpuidle_unregister_driver(&acpi_idle_driver); - -out_proc: -#ifdef CONFIG_ACPI_PROCFS -	remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); -#endif - -	return result; -} - -static void __exit acpi_processor_exit(void) -{ -	if (acpi_disabled) -		return; - -	acpi_processor_ppc_exit(); - -	acpi_thermal_cpufreq_exit(); - -	acpi_processor_uninstall_hotplug_notify(); - -	acpi_bus_unregister_driver(&acpi_processor_driver); - -	cpuidle_unregister_driver(&acpi_idle_driver); - -#ifdef CONFIG_ACPI_PROCFS -	remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); -#endif - -	return; -} - -module_init(acpi_processor_init); -module_exit(acpi_processor_exit); - -EXPORT_SYMBOL(acpi_processor_set_thermal_limit); - -MODULE_ALIAS("processor"); diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c new file mode 100644 index 000000000000..b5658cdce27f --- /dev/null +++ b/drivers/acpi/processor_driver.c @@ -0,0 +1,978 @@ +/* + * acpi_processor.c - ACPI Processor Driver ($Revision: 71 $) + * + *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> + *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> + *  Copyright (C) 2004       Dominik Brodowski <linux@brodo.de> + *  Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> + *  			- Added processor hotplug support + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or (at + *  your option) any later version. + * + *  This program is distributed in the hope that it will be useful, but + *  WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License along + *  with this program; if not, write to the Free Software Foundation, Inc., + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + *  TBD: + *	1. Make # power states dynamic. + *	2. Support duty_cycle values that span bit 4. + *	3. Optimize by having scheduler determine business instead of + *	   having us try to calculate it here. + *	4. Need C1 timing -- must modify kernel (IRQ handler) to get this. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/pm.h> +#include <linux/cpufreq.h> +#include <linux/cpu.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/dmi.h> +#include <linux/moduleparam.h> +#include <linux/cpuidle.h> + +#include <asm/io.h> +#include <asm/system.h> +#include <asm/cpu.h> +#include <asm/delay.h> +#include <asm/uaccess.h> +#include <asm/processor.h> +#include <asm/smp.h> +#include <asm/acpi.h> + +#include <acpi/acpi_bus.h> +#include <acpi/acpi_drivers.h> +#include <acpi/processor.h> + +#define PREFIX "ACPI: " + +#define ACPI_PROCESSOR_CLASS		"processor" +#define ACPI_PROCESSOR_DEVICE_NAME	"Processor" +#define ACPI_PROCESSOR_FILE_INFO	"info" +#define ACPI_PROCESSOR_FILE_THROTTLING	"throttling" +#define ACPI_PROCESSOR_FILE_LIMIT	"limit" +#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 +#define ACPI_PROCESSOR_NOTIFY_POWER	0x81 +#define ACPI_PROCESSOR_NOTIFY_THROTTLING	0x82 + +#define ACPI_PROCESSOR_LIMIT_USER	0 +#define ACPI_PROCESSOR_LIMIT_THERMAL	1 + +#define _COMPONENT		ACPI_PROCESSOR_COMPONENT +ACPI_MODULE_NAME("processor_driver"); + +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Processor Driver"); +MODULE_LICENSE("GPL"); + +static int acpi_processor_add(struct acpi_device *device); +static int acpi_processor_remove(struct acpi_device *device, int type); +#ifdef CONFIG_ACPI_PROCFS +static int acpi_processor_info_open_fs(struct inode *inode, struct file *file); +#endif +static void acpi_processor_notify(struct acpi_device *device, u32 event); +static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); +static int acpi_processor_handle_eject(struct acpi_processor *pr); + + +static const struct acpi_device_id processor_device_ids[] = { +	{ACPI_PROCESSOR_OBJECT_HID, 0}, +	{"ACPI0007", 0}, +	{"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, processor_device_ids); + +static struct acpi_driver acpi_processor_driver = { +	.name = "processor", +	.class = ACPI_PROCESSOR_CLASS, +	.ids = processor_device_ids, +	.ops = { +		.add = acpi_processor_add, +		.remove = acpi_processor_remove, +		.suspend = acpi_processor_suspend, +		.resume = acpi_processor_resume, +		.notify = acpi_processor_notify, +		}, +}; + +#define INSTALL_NOTIFY_HANDLER		1 +#define UNINSTALL_NOTIFY_HANDLER	2 +#ifdef CONFIG_ACPI_PROCFS +static const struct file_operations acpi_processor_info_fops = { +	.owner = THIS_MODULE, +	.open = acpi_processor_info_open_fs, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = single_release, +}; +#endif + +DEFINE_PER_CPU(struct acpi_processor *, processors); +EXPORT_PER_CPU_SYMBOL(processors); + +struct acpi_processor_errata errata __read_mostly; + +/* -------------------------------------------------------------------------- +                                Errata Handling +   -------------------------------------------------------------------------- */ + +static int acpi_processor_errata_piix4(struct pci_dev *dev) +{ +	u8 value1 = 0; +	u8 value2 = 0; + + +	if (!dev) +		return -EINVAL; + +	/* +	 * Note that 'dev' references the PIIX4 ACPI Controller. +	 */ + +	switch (dev->revision) { +	case 0: +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n")); +		break; +	case 1: +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n")); +		break; +	case 2: +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n")); +		break; +	case 3: +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n")); +		break; +	default: +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n")); +		break; +	} + +	switch (dev->revision) { + +	case 0:		/* PIIX4 A-step */ +	case 1:		/* PIIX4 B-step */ +		/* +		 * See specification changes #13 ("Manual Throttle Duty Cycle") +		 * and #14 ("Enabling and Disabling Manual Throttle"), plus +		 * erratum #5 ("STPCLK# Deassertion Time") from the January +		 * 2002 PIIX4 specification update.  Applies to only older +		 * PIIX4 models. +		 */ +		errata.piix4.throttle = 1; + +	case 2:		/* PIIX4E */ +	case 3:		/* PIIX4M */ +		/* +		 * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA +		 * Livelock") from the January 2002 PIIX4 specification update. +		 * Applies to all PIIX4 models. +		 */ + +		/* +		 * BM-IDE +		 * ------ +		 * Find the PIIX4 IDE Controller and get the Bus Master IDE +		 * Status register address.  We'll use this later to read +		 * each IDE controller's DMA status to make sure we catch all +		 * DMA activity. +		 */ +		dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, +				     PCI_DEVICE_ID_INTEL_82371AB, +				     PCI_ANY_ID, PCI_ANY_ID, NULL); +		if (dev) { +			errata.piix4.bmisx = pci_resource_start(dev, 4); +			pci_dev_put(dev); +		} + +		/* +		 * Type-F DMA +		 * ---------- +		 * Find the PIIX4 ISA Controller and read the Motherboard +		 * DMA controller's status to see if Type-F (Fast) DMA mode +		 * is enabled (bit 7) on either channel.  Note that we'll +		 * disable C3 support if this is enabled, as some legacy +		 * devices won't operate well if fast DMA is disabled. +		 */ +		dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, +				     PCI_DEVICE_ID_INTEL_82371AB_0, +				     PCI_ANY_ID, PCI_ANY_ID, NULL); +		if (dev) { +			pci_read_config_byte(dev, 0x76, &value1); +			pci_read_config_byte(dev, 0x77, &value2); +			if ((value1 & 0x80) || (value2 & 0x80)) +				errata.piix4.fdma = 1; +			pci_dev_put(dev); +		} + +		break; +	} + +	if (errata.piix4.bmisx) +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +				  "Bus master activity detection (BM-IDE) erratum enabled\n")); +	if (errata.piix4.fdma) +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +				  "Type-F DMA livelock erratum (C3 disabled)\n")); + +	return 0; +} + +static int acpi_processor_errata(struct acpi_processor *pr) +{ +	int result = 0; +	struct pci_dev *dev = NULL; + + +	if (!pr) +		return -EINVAL; + +	/* +	 * PIIX4 +	 */ +	dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, +			     PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, +			     PCI_ANY_ID, NULL); +	if (dev) { +		result = acpi_processor_errata_piix4(dev); +		pci_dev_put(dev); +	} + +	return result; +} + +/* -------------------------------------------------------------------------- +                              FS Interface (/proc) +   -------------------------------------------------------------------------- */ + +#ifdef CONFIG_ACPI_PROCFS +static struct proc_dir_entry *acpi_processor_dir = NULL; + +static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset) +{ +	struct acpi_processor *pr = seq->private; + + +	if (!pr) +		goto end; + +	seq_printf(seq, "processor id:            %d\n" +		   "acpi id:                 %d\n" +		   "bus mastering control:   %s\n" +		   "power management:        %s\n" +		   "throttling control:      %s\n" +		   "limit interface:         %s\n", +		   pr->id, +		   pr->acpi_id, +		   pr->flags.bm_control ? "yes" : "no", +		   pr->flags.power ? "yes" : "no", +		   pr->flags.throttling ? "yes" : "no", +		   pr->flags.limit ? "yes" : "no"); + +      end: +	return 0; +} + +static int acpi_processor_info_open_fs(struct inode *inode, struct file *file) +{ +	return single_open(file, acpi_processor_info_seq_show, +			   PDE(inode)->data); +} + +static int __cpuinit acpi_processor_add_fs(struct acpi_device *device) +{ +	struct proc_dir_entry *entry = NULL; + + +	if (!acpi_device_dir(device)) { +		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), +						     acpi_processor_dir); +		if (!acpi_device_dir(device)) +			return -ENODEV; +	} + +	/* 'info' [R] */ +	entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO, +				 S_IRUGO, acpi_device_dir(device), +				 &acpi_processor_info_fops, +				 acpi_driver_data(device)); +	if (!entry) +		return -EIO; + +	/* 'throttling' [R/W] */ +	entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING, +				 S_IFREG | S_IRUGO | S_IWUSR, +				 acpi_device_dir(device), +				 &acpi_processor_throttling_fops, +				 acpi_driver_data(device)); +	if (!entry) +		return -EIO; + +	/* 'limit' [R/W] */ +	entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT, +				 S_IFREG | S_IRUGO | S_IWUSR, +				 acpi_device_dir(device), +				 &acpi_processor_limit_fops, +				 acpi_driver_data(device)); +	if (!entry) +		return -EIO; +	return 0; +} +static int acpi_processor_remove_fs(struct acpi_device *device) +{ + +	if (acpi_device_dir(device)) { +		remove_proc_entry(ACPI_PROCESSOR_FILE_INFO, +				  acpi_device_dir(device)); +		remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, +				  acpi_device_dir(device)); +		remove_proc_entry(ACPI_PROCESSOR_FILE_LIMIT, +				  acpi_device_dir(device)); +		remove_proc_entry(acpi_device_bid(device), acpi_processor_dir); +		acpi_device_dir(device) = NULL; +	} + +	return 0; +} +#else +static inline int acpi_processor_add_fs(struct acpi_device *device) +{ +	return 0; +} +static inline int acpi_processor_remove_fs(struct acpi_device *device) +{ +	return 0; +} +#endif + +/* -------------------------------------------------------------------------- +                                 Driver Interface +   -------------------------------------------------------------------------- */ + +static int acpi_processor_get_info(struct acpi_device *device) +{ +	acpi_status status = 0; +	union acpi_object object = { 0 }; +	struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; +	struct acpi_processor *pr; +	int cpu_index, device_declaration = 0; +	static int cpu0_initialized; + +	pr = acpi_driver_data(device); +	if (!pr) +		return -EINVAL; + +	if (num_online_cpus() > 1) +		errata.smp = TRUE; + +	acpi_processor_errata(pr); + +	/* +	 * Check to see if we have bus mastering arbitration control.  This +	 * is required for proper C3 usage (to maintain cache coherency). +	 */ +	if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) { +		pr->flags.bm_control = 1; +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +				  "Bus mastering arbitration control present\n")); +	} else +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +				  "No bus mastering arbitration control\n")); + +	if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) { +		/* Declared with "Processor" statement; match ProcessorID */ +		status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); +		if (ACPI_FAILURE(status)) { +			printk(KERN_ERR PREFIX "Evaluating processor object\n"); +			return -ENODEV; +		} + +		/* +		 * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. +		 *      >>> 'acpi_get_processor_id(acpi_id, &id)' in +		 *      arch/xxx/acpi.c +		 */ +		pr->acpi_id = object.processor.proc_id; +	} else { +		/* +		 * Declared with "Device" statement; match _UID. +		 * Note that we don't handle string _UIDs yet. +		 */ +		unsigned long long value; +		status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, +						NULL, &value); +		if (ACPI_FAILURE(status)) { +			printk(KERN_ERR PREFIX +			    "Evaluating processor _UID [%#x]\n", status); +			return -ENODEV; +		} +		device_declaration = 1; +		pr->acpi_id = value; +	} +	cpu_index = acpi_get_cpuid(pr->handle, device_declaration, pr->acpi_id); + +	/* Handle UP system running SMP kernel, with no LAPIC in MADT */ +	if (!cpu0_initialized && (cpu_index == -1) && +	    (num_online_cpus() == 1)) { +		cpu_index = 0; +	} + +	cpu0_initialized = 1; + +	pr->id = cpu_index; + +	/* +	 *  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. +	 */ +	if (pr->id == -1) { +		if (ACPI_FAILURE +		    (acpi_processor_hotadd_init(pr->handle, &pr->id))) { +			return -ENODEV; +		} +	} +	/* +	 * On some boxes several processors use the same processor bus id. +	 * But they are located in different scope. For example: +	 * \_SB.SCK0.CPU0 +	 * \_SB.SCK1.CPU0 +	 * Rename the processor device bus id. And the new bus id will be +	 * generated as the following format: +	 * CPU+CPU ID. +	 */ +	sprintf(acpi_device_bid(device), "CPU%X", pr->id); +	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, +			  pr->acpi_id)); + +	if (!object.processor.pblk_address) +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); +	else if (object.processor.pblk_length != 6) +		printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n", +			    object.processor.pblk_length); +	else { +		pr->throttling.address = object.processor.pblk_address; +		pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset; +		pr->throttling.duty_width = acpi_gbl_FADT.duty_width; + +		pr->pblk = object.processor.pblk_address; + +		/* +		 * We don't care about error returns - we just try to mark +		 * these reserved so that nobody else is confused into thinking +		 * that this region might be unused.. +		 * +		 * (In particular, allocating the IO range for Cardbus) +		 */ +		request_region(pr->throttling.address, 6, "ACPI CPU throttle"); +	} + +	/* +	 * If ACPI describes a slot number for this CPU, we can use it +	 * ensure we get the right value in the "physical id" field +	 * of /proc/cpuinfo +	 */ +	status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer); +	if (ACPI_SUCCESS(status)) +		arch_fix_phys_package_id(pr->id, object.integer.value); + +	return 0; +} + +static DEFINE_PER_CPU(void *, processor_device_array); + +static void acpi_processor_notify(struct acpi_device *device, u32 event) +{ +	struct acpi_processor *pr = acpi_driver_data(device); +	int saved; + +	if (!pr) +		return; + +	switch (event) { +	case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: +		saved = pr->performance_platform_limit; +		acpi_processor_ppc_has_changed(pr, 1); +		if (saved == pr->performance_platform_limit) +			break; +		acpi_bus_generate_proc_event(device, event, +					pr->performance_platform_limit); +		acpi_bus_generate_netlink_event(device->pnp.device_class, +						  dev_name(&device->dev), event, +						  pr->performance_platform_limit); +		break; +	case ACPI_PROCESSOR_NOTIFY_POWER: +		acpi_processor_cst_has_changed(pr); +		acpi_bus_generate_proc_event(device, event, 0); +		acpi_bus_generate_netlink_event(device->pnp.device_class, +						  dev_name(&device->dev), event, 0); +		break; +	case ACPI_PROCESSOR_NOTIFY_THROTTLING: +		acpi_processor_tstate_has_changed(pr); +		acpi_bus_generate_proc_event(device, event, 0); +		acpi_bus_generate_netlink_event(device->pnp.device_class, +						  dev_name(&device->dev), event, 0); +	default: +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +				  "Unsupported event [0x%x]\n", event)); +		break; +	} + +	return; +} + +static int acpi_cpu_soft_notify(struct notifier_block *nfb, +		unsigned long action, void *hcpu) +{ +	unsigned int cpu = (unsigned long)hcpu; +	struct acpi_processor *pr = per_cpu(processors, cpu); + +	if (action == CPU_ONLINE && pr) { +		acpi_processor_ppc_has_changed(pr, 0); +		acpi_processor_cst_has_changed(pr); +		acpi_processor_tstate_has_changed(pr); +	} +	return NOTIFY_OK; +} + +static struct notifier_block acpi_cpu_notifier = +{ +	    .notifier_call = acpi_cpu_soft_notify, +}; + +static int __cpuinit acpi_processor_add(struct acpi_device *device) +{ +	struct acpi_processor *pr = NULL; +	int result = 0; +	struct sys_device *sysdev; + +	pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); +	if (!pr) +		return -ENOMEM; + +	if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { +		kfree(pr); +		return -ENOMEM; +	} + +	pr->handle = device->handle; +	strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); +	strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); +	device->driver_data = pr; + +	result = acpi_processor_get_info(device); +	if (result) { +		/* Processor is physically not present */ +		return 0; +	} + +	BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0)); + +	/* +	 * 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) { +		printk(KERN_WARNING "BIOS reported wrong ACPI id " +			"for the processor\n"); +		result = -ENODEV; +		goto err_free_cpumask; +	} +	per_cpu(processor_device_array, pr->id) = device; + +	per_cpu(processors, pr->id) = pr; + +	result = acpi_processor_add_fs(device); +	if (result) +		goto err_free_cpumask; + +	sysdev = get_cpu_sysdev(pr->id); +	if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) { +		result = -EFAULT; +		goto err_remove_fs; +	} + +#ifdef CONFIG_CPU_FREQ +	acpi_processor_ppc_has_changed(pr, 0); +#endif +	acpi_processor_get_throttling_info(pr); +	acpi_processor_get_limit_info(pr); + + +	acpi_processor_power_init(pr, device); + +	pr->cdev = thermal_cooling_device_register("Processor", device, +						&processor_cooling_ops); +	if (IS_ERR(pr->cdev)) { +		result = PTR_ERR(pr->cdev); +		goto err_power_exit; +	} + +	dev_dbg(&device->dev, "registered as cooling_device%d\n", +		 pr->cdev->id); + +	result = sysfs_create_link(&device->dev.kobj, +				   &pr->cdev->device.kobj, +				   "thermal_cooling"); +	if (result) { +		printk(KERN_ERR PREFIX "Create sysfs link\n"); +		goto err_thermal_unregister; +	} +	result = sysfs_create_link(&pr->cdev->device.kobj, +				   &device->dev.kobj, +				   "device"); +	if (result) { +		printk(KERN_ERR PREFIX "Create sysfs link\n"); +		goto err_remove_sysfs; +	} + +	return 0; + +err_remove_sysfs: +	sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); +err_thermal_unregister: +	thermal_cooling_device_unregister(pr->cdev); +err_power_exit: +	acpi_processor_power_exit(pr, device); +err_remove_fs: +	acpi_processor_remove_fs(device); +err_free_cpumask: +	free_cpumask_var(pr->throttling.shared_cpu_map); + +	return result; +} + +static int acpi_processor_remove(struct acpi_device *device, int type) +{ +	struct acpi_processor *pr = NULL; + + +	if (!device || !acpi_driver_data(device)) +		return -EINVAL; + +	pr = acpi_driver_data(device); + +	if (pr->id >= nr_cpu_ids) +		goto free; + +	if (type == ACPI_BUS_REMOVAL_EJECT) { +		if (acpi_processor_handle_eject(pr)) +			return -EINVAL; +	} + +	acpi_processor_power_exit(pr, device); + +	sysfs_remove_link(&device->dev.kobj, "sysdev"); + +	acpi_processor_remove_fs(device); + +	if (pr->cdev) { +		sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); +		sysfs_remove_link(&pr->cdev->device.kobj, "device"); +		thermal_cooling_device_unregister(pr->cdev); +		pr->cdev = NULL; +	} + +	per_cpu(processors, pr->id) = NULL; +	per_cpu(processor_device_array, pr->id) = NULL; + +free: +	free_cpumask_var(pr->throttling.shared_cpu_map); +	kfree(pr); + +	return 0; +} + +#ifdef CONFIG_ACPI_HOTPLUG_CPU +/**************************************************************************** + * 	Acpi processor hotplug support 				       	    * + ****************************************************************************/ + +static int is_processor_present(acpi_handle handle) +{ +	acpi_status status; +	unsigned long long sta = 0; + + +	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + +	if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT)) +		return 1; + +	/* +	 * _STA is mandatory for a processor that supports hot plug +	 */ +	if (status == AE_NOT_FOUND) +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +				"Processor does not support hot plug\n")); +	else +		ACPI_EXCEPTION((AE_INFO, status, +				"Processor Device is not present")); +	return 0; +} + +static +int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) +{ +	acpi_handle phandle; +	struct acpi_device *pdev; + + +	if (acpi_get_parent(handle, &phandle)) { +		return -ENODEV; +	} + +	if (acpi_bus_get_device(phandle, &pdev)) { +		return -ENODEV; +	} + +	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) { +		return -ENODEV; +	} + +	return 0; +} + +static void __ref acpi_processor_hotplug_notify(acpi_handle handle, +						u32 event, void *data) +{ +	struct acpi_processor *pr; +	struct acpi_device *device = NULL; +	int result; + + +	switch (event) { +	case ACPI_NOTIFY_BUS_CHECK: +	case ACPI_NOTIFY_DEVICE_CHECK: +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +		"Processor driver received %s event\n", +		       (event == ACPI_NOTIFY_BUS_CHECK) ? +		       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK")); + +		if (!is_processor_present(handle)) +			break; + +		if (acpi_bus_get_device(handle, &device)) { +			result = acpi_processor_device_add(handle, &device); +			if (result) +				printk(KERN_ERR PREFIX +					    "Unable to add the device\n"); +			break; +		} +		break; +	case ACPI_NOTIFY_EJECT_REQUEST: +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +				  "received ACPI_NOTIFY_EJECT_REQUEST\n")); + +		if (acpi_bus_get_device(handle, &device)) { +			printk(KERN_ERR PREFIX +				    "Device don't exist, dropping EJECT\n"); +			break; +		} +		pr = acpi_driver_data(device); +		if (!pr) { +			printk(KERN_ERR PREFIX +				    "Driver data is NULL, dropping EJECT\n"); +			return; +		} +		break; +	default: +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, +				  "Unsupported event [0x%x]\n", event)); +		break; +	} + +	return; +} + +static acpi_status +processor_walk_namespace_cb(acpi_handle handle, +			    u32 lvl, void *context, void **rv) +{ +	acpi_status status; +	int *action = context; +	acpi_object_type type = 0; + +	status = acpi_get_type(handle, &type); +	if (ACPI_FAILURE(status)) +		return (AE_OK); + +	if (type != ACPI_TYPE_PROCESSOR) +		return (AE_OK); + +	switch (*action) { +	case INSTALL_NOTIFY_HANDLER: +		acpi_install_notify_handler(handle, +					    ACPI_SYSTEM_NOTIFY, +					    acpi_processor_hotplug_notify, +					    NULL); +		break; +	case UNINSTALL_NOTIFY_HANDLER: +		acpi_remove_notify_handler(handle, +					   ACPI_SYSTEM_NOTIFY, +					   acpi_processor_hotplug_notify); +		break; +	default: +		break; +	} + +	return (AE_OK); +} + +static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu) +{ + +	if (!is_processor_present(handle)) { +		return AE_ERROR; +	} + +	if (acpi_map_lsapic(handle, p_cpu)) +		return AE_ERROR; + +	if (arch_register_cpu(*p_cpu)) { +		acpi_unmap_lsapic(*p_cpu); +		return AE_ERROR; +	} + +	return AE_OK; +} + +static int acpi_processor_handle_eject(struct acpi_processor *pr) +{ +	if (cpu_online(pr->id)) +		cpu_down(pr->id); + +	arch_unregister_cpu(pr->id); +	acpi_unmap_lsapic(pr->id); +	return (0); +} +#else +static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu) +{ +	return AE_ERROR; +} +static int acpi_processor_handle_eject(struct acpi_processor *pr) +{ +	return (-EINVAL); +} +#endif + +static +void acpi_processor_install_hotplug_notify(void) +{ +#ifdef CONFIG_ACPI_HOTPLUG_CPU +	int action = INSTALL_NOTIFY_HANDLER; +	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, +			    ACPI_ROOT_OBJECT, +			    ACPI_UINT32_MAX, +			    processor_walk_namespace_cb, NULL, &action, NULL); +#endif +	register_hotcpu_notifier(&acpi_cpu_notifier); +} + +static +void acpi_processor_uninstall_hotplug_notify(void) +{ +#ifdef CONFIG_ACPI_HOTPLUG_CPU +	int action = UNINSTALL_NOTIFY_HANDLER; +	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, +			    ACPI_ROOT_OBJECT, +			    ACPI_UINT32_MAX, +			    processor_walk_namespace_cb, NULL, &action, NULL); +#endif +	unregister_hotcpu_notifier(&acpi_cpu_notifier); +} + +/* + * We keep the driver loaded even when ACPI is not running. + * This is needed for the powernow-k8 driver, that works even without + * ACPI, but needs symbols from this driver + */ + +static int __init acpi_processor_init(void) +{ +	int result = 0; + +	if (acpi_disabled) +		return 0; + +	memset(&errata, 0, sizeof(errata)); + +#ifdef CONFIG_ACPI_PROCFS +	acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); +	if (!acpi_processor_dir) +		return -ENOMEM; +#endif +	result = cpuidle_register_driver(&acpi_idle_driver); +	if (result < 0) +		goto out_proc; + +	result = acpi_bus_register_driver(&acpi_processor_driver); +	if (result < 0) +		goto out_cpuidle; + +	acpi_processor_install_hotplug_notify(); + +	acpi_thermal_cpufreq_init(); + +	acpi_processor_ppc_init(); + +	acpi_processor_throttling_init(); + +	return 0; + +out_cpuidle: +	cpuidle_unregister_driver(&acpi_idle_driver); + +out_proc: +#ifdef CONFIG_ACPI_PROCFS +	remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); +#endif + +	return result; +} + +static void __exit acpi_processor_exit(void) +{ +	if (acpi_disabled) +		return; + +	acpi_processor_ppc_exit(); + +	acpi_thermal_cpufreq_exit(); + +	acpi_processor_uninstall_hotplug_notify(); + +	acpi_bus_unregister_driver(&acpi_processor_driver); + +	cpuidle_unregister_driver(&acpi_idle_driver); + +#ifdef CONFIG_ACPI_PROCFS +	remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); +#endif + +	return; +} + +module_init(acpi_processor_init); +module_exit(acpi_processor_exit); + +EXPORT_SYMBOL(acpi_processor_set_thermal_limit); + +MODULE_ALIAS("processor"); diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c deleted file mode 100644 index e306ba9aa34e..000000000000 --- a/drivers/acpi/processor_pdc.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2005 Intel Corporation - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * - *	Alex Chiang <achiang@hp.com> - *	- Unified x86/ia64 implementations - *	Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> - *	- Added _PDC for platforms with Intel CPUs - */ -#include <linux/dmi.h> - -#include <acpi/acpi_drivers.h> -#include <acpi/processor.h> - -#include "internal.h" - -#define PREFIX			"ACPI: " -#define _COMPONENT		ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("processor_pdc"); - -static int set_no_mwait(const struct dmi_system_id *id) -{ -	printk(KERN_NOTICE PREFIX "%s detected - " -		"disabling mwait for CPU C-states\n", id->ident); -	idle_nomwait = 1; -	return 0; -} - -static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = { -	{ -	set_no_mwait, "IFL91 board", { -	DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), -	DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"), -	DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"), -	DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL}, -	{ -	set_no_mwait, "Extensa 5220", { -	DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), -	DMI_MATCH(DMI_SYS_VENDOR, "Acer"), -	DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), -	DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, -	{}, -}; - -static void acpi_set_pdc_bits(u32 *buf) -{ -	buf[0] = ACPI_PDC_REVISION_ID; -	buf[1] = 1; - -	/* Enable coordination with firmware's _TSD info */ -	buf[2] = ACPI_PDC_SMP_T_SWCOORD; - -	/* Twiddle arch-specific bits needed for _PDC */ -	arch_acpi_set_pdc_bits(buf); -} - -static struct acpi_object_list *acpi_processor_alloc_pdc(void) -{ -	struct acpi_object_list *obj_list; -	union acpi_object *obj; -	u32 *buf; - -	/* allocate and initialize pdc. It will be used later. */ -	obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); -	if (!obj_list) { -		printk(KERN_ERR "Memory allocation error\n"); -		return NULL; -	} - -	obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); -	if (!obj) { -		printk(KERN_ERR "Memory allocation error\n"); -		kfree(obj_list); -		return NULL; -	} - -	buf = kmalloc(12, GFP_KERNEL); -	if (!buf) { -		printk(KERN_ERR "Memory allocation error\n"); -		kfree(obj); -		kfree(obj_list); -		return NULL; -	} - -	acpi_set_pdc_bits(buf); - -	obj->type = ACPI_TYPE_BUFFER; -	obj->buffer.length = 12; -	obj->buffer.pointer = (u8 *) buf; -	obj_list->count = 1; -	obj_list->pointer = obj; - -	return obj_list; -} - -/* - * _PDC is required for a BIOS-OS handshake for most of the newer - * ACPI processor features. - */ -static int -acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) -{ -	acpi_status status = AE_OK; - -	if (idle_nomwait) { -		/* -		 * If mwait is disabled for CPU C-states, the C2C3_FFH access -		 * mode will be disabled in the parameter of _PDC object. -		 * Of course C1_FFH access mode will also be disabled. -		 */ -		union acpi_object *obj; -		u32 *buffer = NULL; - -		obj = pdc_in->pointer; -		buffer = (u32 *)(obj->buffer.pointer); -		buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH); - -	} -	status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); - -	if (ACPI_FAILURE(status)) -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -		    "Could not evaluate _PDC, using legacy perf. control.\n")); - -	return status; -} - -static int early_pdc_done; - -void acpi_processor_set_pdc(acpi_handle handle) -{ -	struct acpi_object_list *obj_list; - -	if (arch_has_acpi_pdc() == false) -		return; - -	if (early_pdc_done) -		return; - -	obj_list = acpi_processor_alloc_pdc(); -	if (!obj_list) -		return; - -	acpi_processor_eval_pdc(handle, obj_list); - -	kfree(obj_list->pointer->buffer.pointer); -	kfree(obj_list->pointer); -	kfree(obj_list); -} -EXPORT_SYMBOL_GPL(acpi_processor_set_pdc); - -static int early_pdc_optin; -static int set_early_pdc_optin(const struct dmi_system_id *id) -{ -	early_pdc_optin = 1; -	return 0; -} - -static int param_early_pdc_optin(char *s) -{ -	early_pdc_optin = 1; -	return 1; -} -__setup("acpi_early_pdc_eval", param_early_pdc_optin); - -static struct dmi_system_id __cpuinitdata early_pdc_optin_table[] = { -	{ -	set_early_pdc_optin, "HP Envy", { -	DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"), -	DMI_MATCH(DMI_PRODUCT_NAME, "HP Envy") }, NULL}, -	{ -	set_early_pdc_optin, "HP Pavilion dv6", { -	DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"), -	DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv6") }, NULL}, -	{ -	set_early_pdc_optin, "HP Pavilion dv7", { -	DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"), -	DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv7") }, NULL}, -	{}, -}; - -static acpi_status -early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) -{ -	acpi_processor_set_pdc(handle); -	return AE_OK; -} - -void __init acpi_early_processor_set_pdc(void) -{ -	/* -	 * Check whether the system is DMI table. If yes, OSPM -	 * should not use mwait for CPU-states. -	 */ -	dmi_check_system(processor_idle_dmi_table); - -	/* -	 * Allow systems to opt-in to early _PDC evaluation. -	 */ -	dmi_check_system(early_pdc_optin_table); -	if (!early_pdc_optin) -		return; - -	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, -			    ACPI_UINT32_MAX, -			    early_init_pdc, NULL, NULL, NULL); - -	early_pdc_done = 1; -} diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 7ded7542fc9d..29c6f5766dcf 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -1133,9 +1133,6 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)  	int result = 0;  	struct acpi_processor_throttling *pthrottling; -	if (!pr) -		return -EINVAL; -  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,  			  "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",  			  pr->throttling.address, diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index b16ddbf23a9c..89ad11138e48 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -217,6 +217,9 @@ static int acpi_sbs_battery_get_property(struct power_supply *psy,  	case POWER_SUPPLY_PROP_TECHNOLOGY:  		val->intval = acpi_battery_technology(battery);  		break; +	case POWER_SUPPLY_PROP_CYCLE_COUNT: +		val->intval = battery->cycle_count; +		break;  	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:  		val->intval = battery->design_voltage *  			acpi_battery_vscale(battery) * 1000; @@ -276,6 +279,7 @@ static enum power_supply_property sbs_charge_battery_props[] = {  	POWER_SUPPLY_PROP_STATUS,  	POWER_SUPPLY_PROP_PRESENT,  	POWER_SUPPLY_PROP_TECHNOLOGY, +	POWER_SUPPLY_PROP_CYCLE_COUNT,  	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,  	POWER_SUPPLY_PROP_VOLTAGE_NOW,  	POWER_SUPPLY_PROP_CURRENT_NOW, @@ -560,6 +564,7 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)  		   battery->design_voltage * acpi_battery_vscale(battery));  	seq_printf(seq, "design capacity warning: unknown\n");  	seq_printf(seq, "design capacity low:     unknown\n"); +	seq_printf(seq, "cycle count:		  %i\n", battery->cycle_count);  	seq_printf(seq, "capacity granularity 1:  unknown\n");  	seq_printf(seq, "capacity granularity 2:  unknown\n");  	seq_printf(seq, "model number:            %s\n", battery->device_name); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 3bde594a9979..f74834a544fd 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -552,8 +552,17 @@ static void acpi_hibernation_leave(void)  	hibernate_nvs_restore();  } -static void acpi_pm_enable_gpes(void) +static int acpi_pm_pre_restore(void)  { +	acpi_disable_all_gpes(); +	acpi_os_wait_events_complete(NULL); +	acpi_ec_suspend_transactions(); +	return 0; +} + +static void acpi_pm_restore_cleanup(void) +{ +	acpi_ec_resume_transactions();  	acpi_enable_all_runtime_gpes();  } @@ -565,8 +574,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {  	.prepare = acpi_pm_prepare,  	.enter = acpi_hibernation_enter,  	.leave = acpi_hibernation_leave, -	.pre_restore = acpi_pm_disable_gpes, -	.restore_cleanup = acpi_pm_enable_gpes, +	.pre_restore = acpi_pm_pre_restore, +	.restore_cleanup = acpi_pm_restore_cleanup,  };  /** @@ -618,8 +627,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = {  	.prepare = acpi_pm_disable_gpes,  	.enter = acpi_hibernation_enter,  	.leave = acpi_hibernation_leave, -	.pre_restore = acpi_pm_disable_gpes, -	.restore_cleanup = acpi_pm_enable_gpes, +	.pre_restore = acpi_pm_pre_restore, +	.restore_cleanup = acpi_pm_restore_cleanup,  	.recover = acpi_pm_finish,  };  #endif /* CONFIG_HIBERNATION */ diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 9073ada88835..5d3893558cf7 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -368,7 +368,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)  	int valid = 0;  	int i; -	/* Critical Shutdown (required) */ +	/* Critical Shutdown */  	if (flag & ACPI_TRIPS_CRITICAL) {  		status = acpi_evaluate_integer(tz->device->handle,  				"_CRT", NULL, &tmp); @@ -379,17 +379,19 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)  		 * Below zero (Celsius) values clearly aren't right for sure..  		 * ... so lets discard those as invalid.  		 */ -		if (ACPI_FAILURE(status) || -				tz->trips.critical.temperature <= 2732) { +		if (ACPI_FAILURE(status)) { +			tz->trips.critical.flags.valid = 0; +			ACPI_DEBUG_PRINT((ACPI_DB_INFO, +					  "No critical threshold\n")); +		} else if (tmp <= 2732) { +			printk(KERN_WARNING FW_BUG "Invalid critical threshold " +			       "(%llu)\n", tmp);  			tz->trips.critical.flags.valid = 0; -			ACPI_EXCEPTION((AE_INFO, status, -					"No or invalid critical threshold")); -			return -ENODEV;  		} else {  			tz->trips.critical.flags.valid = 1;  			ACPI_DEBUG_PRINT((ACPI_DB_INFO, -					"Found critical threshold [%lu]\n", -					tz->trips.critical.temperature)); +					  "Found critical threshold [%lu]\n", +					  tz->trips.critical.temperature));  		}  		if (tz->trips.critical.flags.valid == 1) {  			if (crt == -1) { @@ -575,7 +577,23 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)  static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)  { -	return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); +	int i, valid, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); + +	if (ret) +		return ret; + +	valid = tz->trips.critical.flags.valid | +		tz->trips.hot.flags.valid | +		tz->trips.passive.flags.valid; + +	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) +		valid |= tz->trips.active[i].flags.valid; + +	if (!valid) { +		printk(KERN_WARNING FW_BUG "No valid trip found\n"); +		return -ENODEV; +	} +	return 0;  }  static void acpi_thermal_check(void *data) diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 11882dbe2094..c9a49f4747e6 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -289,51 +289,6 @@ acpi_evaluate_integer(acpi_handle handle,  EXPORT_SYMBOL(acpi_evaluate_integer); -#if 0 -acpi_status -acpi_evaluate_string(acpi_handle handle, -		     acpi_string pathname, -		     acpi_object_list * arguments, acpi_string * data) -{ -	acpi_status status = AE_OK; -	acpi_object *element = NULL; -	acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - -	if (!data) -		return AE_BAD_PARAMETER; - -	status = acpi_evaluate_object(handle, pathname, arguments, &buffer); -	if (ACPI_FAILURE(status)) { -		acpi_util_eval_error(handle, pathname, status); -		return status; -	} - -	element = (acpi_object *) buffer.pointer; - -	if ((element->type != ACPI_TYPE_STRING) -	    || (element->type != ACPI_TYPE_BUFFER) -	    || !element->string.length) { -		acpi_util_eval_error(handle, pathname, AE_BAD_DATA); -		return AE_BAD_DATA; -	} - -	*data = kzalloc(element->string.length + 1, GFP_KERNEL); -	if (!data) { -		printk(KERN_ERR PREFIX "Memory allocation\n"); -		return -ENOMEM; -	} - -	memcpy(*data, element->string.pointer, element->string.length); - -	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%s]\n", *data)); - -	kfree(buffer.pointer); - -	return AE_OK; -} -#endif -  acpi_status  acpi_evaluate_reference(acpi_handle handle,  			acpi_string pathname, diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 6e9b49149fce..2ff2b6ab5b6c 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -327,7 +327,7 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,  			int level);  static int acpi_video_device_lcd_get_level_current(  			struct acpi_video_device *device, -			unsigned long long *level); +			unsigned long long *level, int init);  static int acpi_video_get_next_level(struct acpi_video_device *device,  				     u32 level_current, u32 event);  static int acpi_video_switch_brightness(struct acpi_video_device *device, @@ -345,7 +345,7 @@ static int acpi_video_get_brightness(struct backlight_device *bd)  	struct acpi_video_device *vd =  		(struct acpi_video_device *)bl_get_data(bd); -	if (acpi_video_device_lcd_get_level_current(vd, &cur_level)) +	if (acpi_video_device_lcd_get_level_current(vd, &cur_level, 0))  		return -EINVAL;  	for (i = 2; i < vd->brightness->count; i++) {  		if (vd->brightness->levels[i] == cur_level) @@ -414,7 +414,7 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsig  	unsigned long long level;  	int offset; -	if (acpi_video_device_lcd_get_level_current(video, &level)) +	if (acpi_video_device_lcd_get_level_current(video, &level, 0))  		return -EINVAL;  	for (offset = 2; offset < video->brightness->count; offset++)  		if (level == video->brightness->levels[offset]) { @@ -609,7 +609,7 @@ static struct dmi_system_id video_dmi_table[] __initdata = {  static int  acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, -					unsigned long long *level) +					unsigned long long *level, int init)  {  	acpi_status status = AE_OK;  	int i; @@ -633,10 +633,16 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,  					device->brightness->curr = *level;  					return 0;  			} -			/* BQC returned an invalid level. Stop using it.  */ -			ACPI_WARNING((AE_INFO, "%s returned an invalid level", -						buf)); -			device->cap._BQC = device->cap._BCQ = 0; +			if (!init) { +				/* +				 * BQC returned an invalid level. +				 * Stop using it. +				 */ +				ACPI_WARNING((AE_INFO, +					      "%s returned an invalid level", +					      buf)); +				device->cap._BQC = device->cap._BCQ = 0; +			}  		} else {  			/* Fixme:  			 * should we return an error or ignore this failure? @@ -892,7 +898,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)  	if (!device->cap._BQC)  		goto set_level; -	result = acpi_video_device_lcd_get_level_current(device, &level_old); +	result = acpi_video_device_lcd_get_level_current(device, &level_old, 1);  	if (result)  		goto out_free_levels; @@ -903,7 +909,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)  	if (result)  		goto out_free_levels; -	result = acpi_video_device_lcd_get_level_current(device, &level); +	result = acpi_video_device_lcd_get_level_current(device, &level, 0);  	if (result)  		goto out_free_levels; @@ -1996,7 +2002,7 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)  		goto out;  	result = acpi_video_device_lcd_get_level_current(device, -							 &level_current); +							 &level_current, 0);  	if (result)  		goto out; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cb2fd01eddae..b5dad9f37453 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -749,6 +749,24 @@ static int acpiphp_bus_trim(acpi_handle handle)  	return retval;  } +static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) +{ +	struct acpiphp_func *func; +	union acpi_object params[2]; +	struct acpi_object_list arg_list; + +	list_for_each_entry(func, &slot->funcs, sibling) { +		arg_list.count = 2; +		arg_list.pointer = params; +		params[0].type = ACPI_TYPE_INTEGER; +		params[0].integer.value = ACPI_ADR_SPACE_PCI_CONFIG; +		params[1].type = ACPI_TYPE_INTEGER; +		params[1].integer.value = 1; +		/* _REG is optional, we don't care about if there is failure */ +		acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL); +	} +} +  /**   * enable_device - enable, configure a slot   * @slot: slot to be enabled @@ -805,6 +823,7 @@ static int __ref enable_device(struct acpiphp_slot *slot)  	pci_bus_assign_resources(bus);  	acpiphp_sanitize_bus(bus);  	acpiphp_set_hpp_values(bus); +	acpiphp_set_acpi_region(slot);  	pci_enable_bridges(bus);  	pci_bus_add_devices(bus); diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 3f71a605a492..5a3d8514c66d 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -145,7 +145,7 @@ struct sony_laptop_input_s {  	struct input_dev	*key_dev;  	struct kfifo		fifo;  	spinlock_t		fifo_lock; -	struct workqueue_struct	*wq; +	struct timer_list	release_key_timer;  };  static struct sony_laptop_input_s sony_laptop_input = { @@ -299,20 +299,26 @@ static int sony_laptop_input_keycode_map[] = {  };  /* release buttons after a short delay if pressed */ -static void do_sony_laptop_release_key(struct work_struct *work) +static void do_sony_laptop_release_key(unsigned long unused)  {  	struct sony_laptop_keypress kp; +	unsigned long flags; + +	spin_lock_irqsave(&sony_laptop_input.fifo_lock, flags); -	while (kfifo_out_locked(&sony_laptop_input.fifo, (unsigned char *)&kp, -			sizeof(kp), &sony_laptop_input.fifo_lock) -			== sizeof(kp)) { -		msleep(10); +	if (kfifo_out(&sony_laptop_input.fifo, +		      (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {  		input_report_key(kp.dev, kp.key, 0);  		input_sync(kp.dev);  	} + +	/* If there is something in the fifo schedule next release. */ +	if (kfifo_len(&sony_laptop_input.fifo) != 0) +		mod_timer(&sony_laptop_input.release_key_timer, +			  jiffies + msecs_to_jiffies(10)); + +	spin_unlock_irqrestore(&sony_laptop_input.fifo_lock, flags);  } -static DECLARE_WORK(sony_laptop_release_key_work, -		do_sony_laptop_release_key);  /* forward event to the input subsystem */  static void sony_laptop_report_input_event(u8 event) @@ -366,13 +372,13 @@ static void sony_laptop_report_input_event(u8 event)  		/* we emit the scancode so we can always remap the key */  		input_event(kp.dev, EV_MSC, MSC_SCAN, event);  		input_sync(kp.dev); -		kfifo_in_locked(&sony_laptop_input.fifo, -			  (unsigned char *)&kp, sizeof(kp), -			  &sony_laptop_input.fifo_lock); -		if (!work_pending(&sony_laptop_release_key_work)) -			queue_work(sony_laptop_input.wq, -					&sony_laptop_release_key_work); +		/* schedule key release */ +		kfifo_in_locked(&sony_laptop_input.fifo, +				(unsigned char *)&kp, sizeof(kp), +				&sony_laptop_input.fifo_lock); +		mod_timer(&sony_laptop_input.release_key_timer, +			  jiffies + msecs_to_jiffies(10));  	} else  		dprintk("unknown input event %.2x\n", event);  } @@ -390,27 +396,21 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)  	/* kfifo */  	spin_lock_init(&sony_laptop_input.fifo_lock); -	error = -	 kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); +	error = kfifo_alloc(&sony_laptop_input.fifo, +			    SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);  	if (error) {  		printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");  		goto err_dec_users;  	} -	/* init workqueue */ -	sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop"); -	if (!sony_laptop_input.wq) { -		printk(KERN_ERR DRV_PFX -				"Unable to create workqueue.\n"); -		error = -ENXIO; -		goto err_free_kfifo; -	} +	setup_timer(&sony_laptop_input.release_key_timer, +		    do_sony_laptop_release_key, 0);  	/* input keys */  	key_dev = input_allocate_device();  	if (!key_dev) {  		error = -ENOMEM; -		goto err_destroy_wq; +		goto err_free_kfifo;  	}  	key_dev->name = "Sony Vaio Keys"; @@ -419,18 +419,15 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)  	key_dev->dev.parent = &acpi_device->dev;  	/* Initialize the Input Drivers: special keys */ -	set_bit(EV_KEY, key_dev->evbit); -	set_bit(EV_MSC, key_dev->evbit); -	set_bit(MSC_SCAN, key_dev->mscbit); +	input_set_capability(key_dev, EV_MSC, MSC_SCAN); + +	__set_bit(EV_KEY, key_dev->evbit);  	key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);  	key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);  	key_dev->keycode = &sony_laptop_input_keycode_map; -	for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) { -		if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) { -			set_bit(sony_laptop_input_keycode_map[i], -				key_dev->keybit); -		} -	} +	for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) +		__set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit); +	__clear_bit(KEY_RESERVED, key_dev->keybit);  	error = input_register_device(key_dev);  	if (error) @@ -450,9 +447,8 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)  	jog_dev->id.vendor = PCI_VENDOR_ID_SONY;  	key_dev->dev.parent = &acpi_device->dev; -	jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); -	jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE); -	jog_dev->relbit[0] = BIT_MASK(REL_WHEEL); +	input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE); +	input_set_capability(jog_dev, EV_REL, REL_WHEEL);  	error = input_register_device(jog_dev);  	if (error) @@ -473,9 +469,6 @@ err_unregister_keydev:  err_free_keydev:  	input_free_device(key_dev); -err_destroy_wq: -	destroy_workqueue(sony_laptop_input.wq); -  err_free_kfifo:  	kfifo_free(&sony_laptop_input.fifo); @@ -486,12 +479,23 @@ err_dec_users:  static void sony_laptop_remove_input(void)  { -	/* cleanup only after the last user has gone */ +	struct sony_laptop_keypress kp = { NULL }; + +	/* Cleanup only after the last user has gone */  	if (!atomic_dec_and_test(&sony_laptop_input.users))  		return; -	/* flush workqueue first */ -	flush_workqueue(sony_laptop_input.wq); +	del_timer_sync(&sony_laptop_input.release_key_timer); + +	/* +	 * Generate key-up events for remaining keys. Note that we don't +	 * need locking since nobody is adding new events to the kfifo. +	 */ +	while (kfifo_out(&sony_laptop_input.fifo, +			 (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) { +		input_report_key(kp.dev, kp.key, 0); +		input_sync(kp.dev); +	}  	/* destroy input devs */  	input_unregister_device(sony_laptop_input.key_dev); @@ -502,7 +506,6 @@ static void sony_laptop_remove_input(void)  		sony_laptop_input.jog_dev = NULL;  	} -	destroy_workqueue(sony_laptop_input.wq);  	kfifo_free(&sony_laptop_input.fifo);  } diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index 0b8d14050efa..0bab84ebb15d 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -166,6 +166,9 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,  struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,  					  resource_size_t start,  					  resource_size_t end, int flags); +struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev, +					  resource_size_t start, +					  resource_size_t end);  extern int pnp_debug; diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 68b0c04987e4..cfaf5b73540b 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -278,9 +278,12 @@ static ssize_t pnp_show_current_resources(struct device *dmdev,  		switch (pnp_resource_type(res)) {  		case IORESOURCE_IO:  		case IORESOURCE_MEM: -			pnp_printf(buffer, " %#llx-%#llx\n", +		case IORESOURCE_BUS: +			pnp_printf(buffer, " %#llx-%#llx%s\n",  				   (unsigned long long) res->start, -				   (unsigned long long) res->end); +				   (unsigned long long) res->end, +				   res->flags & IORESOURCE_WINDOW ? +					" window" : "");  			break;  		case IORESOURCE_IRQ:  		case IORESOURCE_DMA: diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 5702b2c8691f..54514aa35b09 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -177,7 +177,8 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master,  }  static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, -					       u64 len, int io_decode) +					       u64 len, int io_decode, +					       int window)  {  	int flags = 0;  	u64 end = start + len - 1; @@ -186,6 +187,8 @@ static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,  		flags |= IORESOURCE_IO_16BIT_ADDR;  	if (len == 0 || end >= 0x10003)  		flags |= IORESOURCE_DISABLED; +	if (window) +		flags |= IORESOURCE_WINDOW;  	pnp_add_io_resource(dev, start, end, flags);  } @@ -247,7 +250,7 @@ static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev,  static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,  						u64 start, u64 len, -						int write_protect) +						int write_protect, int window)  {  	int flags = 0;  	u64 end = start + len - 1; @@ -256,15 +259,26 @@ static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,  		flags |= IORESOURCE_DISABLED;  	if (write_protect == ACPI_READ_WRITE_MEMORY)  		flags |= IORESOURCE_MEM_WRITEABLE; +	if (window) +		flags |= IORESOURCE_WINDOW;  	pnp_add_mem_resource(dev, start, end, flags);  } +static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev, +						u64 start, u64 len) +{ +	u64 end = start + len - 1; + +	pnp_add_bus_resource(dev, start, end); +} +  static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,  						  struct acpi_resource *res)  {  	struct acpi_resource_address64 addr, *p = &addr;  	acpi_status status; +	int window;  	status = acpi_resource_to_address64(res, p);  	if (!ACPI_SUCCESS(status)) { @@ -273,37 +287,42 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,  		return;  	} -	if (p->producer_consumer == ACPI_PRODUCER) -		return; +	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;  	if (p->resource_type == ACPI_MEMORY_RANGE)  		pnpacpi_parse_allocated_memresource(dev,  			p->minimum, p->address_length, -			p->info.mem.write_protect); +			p->info.mem.write_protect, window);  	else if (p->resource_type == ACPI_IO_RANGE)  		pnpacpi_parse_allocated_ioresource(dev,  			p->minimum, p->address_length,  			p->granularity == 0xfff ? ACPI_DECODE_10 : -				ACPI_DECODE_16); +				ACPI_DECODE_16, window); +	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) +		pnpacpi_parse_allocated_busresource(dev, p->minimum, +						    p->address_length);  }  static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,  						      struct acpi_resource *res)  {  	struct acpi_resource_extended_address64 *p = &res->data.ext_address64; +	int window; -	if (p->producer_consumer == ACPI_PRODUCER) -		return; +	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;  	if (p->resource_type == ACPI_MEMORY_RANGE)  		pnpacpi_parse_allocated_memresource(dev,  			p->minimum, p->address_length, -			p->info.mem.write_protect); +			p->info.mem.write_protect, window);  	else if (p->resource_type == ACPI_IO_RANGE)  		pnpacpi_parse_allocated_ioresource(dev,  			p->minimum, p->address_length,  			p->granularity == 0xfff ? ACPI_DECODE_10 : -				ACPI_DECODE_16); +				ACPI_DECODE_16, window); +	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) +		pnpacpi_parse_allocated_busresource(dev, p->minimum, +						    p->address_length);  }  static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, @@ -368,7 +387,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,  		pnpacpi_parse_allocated_ioresource(dev,  			io->minimum,  			io->address_length, -			io->io_decode); +			io->io_decode, 0);  		break;  	case ACPI_RESOURCE_TYPE_START_DEPENDENT: @@ -380,7 +399,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,  		pnpacpi_parse_allocated_ioresource(dev,  			fixed_io->address,  			fixed_io->address_length, -			ACPI_DECODE_10); +			ACPI_DECODE_10, 0);  		break;  	case ACPI_RESOURCE_TYPE_VENDOR: @@ -396,21 +415,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,  		pnpacpi_parse_allocated_memresource(dev,  			memory24->minimum,  			memory24->address_length, -			memory24->write_protect); +			memory24->write_protect, 0);  		break;  	case ACPI_RESOURCE_TYPE_MEMORY32:  		memory32 = &res->data.memory32;  		pnpacpi_parse_allocated_memresource(dev,  			memory32->minimum,  			memory32->address_length, -			memory32->write_protect); +			memory32->write_protect, 0);  		break;  	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:  		fixed_memory32 = &res->data.fixed_memory32;  		pnpacpi_parse_allocated_memresource(dev,  			fixed_memory32->address,  			fixed_memory32->address_length, -			fixed_memory32->write_protect); +			fixed_memory32->write_protect, 0);  		break;  	case ACPI_RESOURCE_TYPE_ADDRESS16:  	case ACPI_RESOURCE_TYPE_ADDRESS32: diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 64d0596bafb5..5b277dbaacde 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -470,7 +470,8 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res)  unsigned long pnp_resource_type(struct resource *res)  {  	return res->flags & (IORESOURCE_IO  | IORESOURCE_MEM | -			     IORESOURCE_IRQ | IORESOURCE_DMA); +			     IORESOURCE_IRQ | IORESOURCE_DMA | +			     IORESOURCE_BUS);  }  struct resource *pnp_get_resource(struct pnp_dev *dev, @@ -590,6 +591,30 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,  	return pnp_res;  } +struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev, +					  resource_size_t start, +					  resource_size_t end) +{ +	struct pnp_resource *pnp_res; +	struct resource *res; + +	pnp_res = pnp_new_resource(dev); +	if (!pnp_res) { +		dev_err(&dev->dev, "can't add resource for BUS %#llx-%#llx\n", +			(unsigned long long) start, +			(unsigned long long) end); +		return NULL; +	} + +	res = &pnp_res->res; +	res->flags = IORESOURCE_BUS; +	res->start = start; +	res->end = end; + +	pnp_dbg(&dev->dev, "  add %pr\n", res); +	return pnp_res; +} +  /*   * Determine whether the specified resource is a possible configuration   * for this device. diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c index 9585c1c1cc36..f5beb24d036a 100644 --- a/drivers/pnp/support.c +++ b/drivers/pnp/support.c @@ -69,8 +69,10 @@ char *pnp_resource_type_name(struct resource *res)  		return "irq";  	case IORESOURCE_DMA:  		return "dma"; +	case IORESOURCE_BUS: +		return "bus";  	} -	return NULL; +	return "unknown";  }  void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc) diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index c790e0c77d4b..ff05e6189768 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -99,6 +99,7 @@ static struct device_attribute power_supply_attrs[] = {  	POWER_SUPPLY_ATTR(present),  	POWER_SUPPLY_ATTR(online),  	POWER_SUPPLY_ATTR(technology), +	POWER_SUPPLY_ATTR(cycle_count),  	POWER_SUPPLY_ATTR(voltage_max),  	POWER_SUPPLY_ATTR(voltage_min),  	POWER_SUPPLY_ATTR(voltage_max_design), diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 1172c27adadf..86825ddbe14e 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -320,8 +320,16 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)  #endif				/* CONFIG_CPU_FREQ */ -/* in processor_pdc.c */ +/* in processor_core.c */  void acpi_processor_set_pdc(acpi_handle handle); +#ifdef CONFIG_SMP +int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id); +#else +static inline int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) +{ +	return -1; +} +#endif  /* in processor_throttling.c */  int acpi_processor_tstate_has_changed(struct acpi_processor *pr); diff --git a/include/linux/ioport.h b/include/linux/ioport.h index dda98410d588..71ab79da7e7f 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -34,22 +34,24 @@ struct resource_list {   */  #define IORESOURCE_BITS		0x000000ff	/* Bus-specific bits */ -#define IORESOURCE_TYPE_BITS	0x00000f00	/* Resource type */ +#define IORESOURCE_TYPE_BITS	0x00001f00	/* Resource type */  #define IORESOURCE_IO		0x00000100  #define IORESOURCE_MEM		0x00000200  #define IORESOURCE_IRQ		0x00000400  #define IORESOURCE_DMA		0x00000800 +#define IORESOURCE_BUS		0x00001000 -#define IORESOURCE_PREFETCH	0x00001000	/* No side effects */ -#define IORESOURCE_READONLY	0x00002000 -#define IORESOURCE_CACHEABLE	0x00004000 -#define IORESOURCE_RANGELENGTH	0x00008000 -#define IORESOURCE_SHADOWABLE	0x00010000 +#define IORESOURCE_PREFETCH	0x00002000	/* No side effects */ +#define IORESOURCE_READONLY	0x00004000 +#define IORESOURCE_CACHEABLE	0x00008000 +#define IORESOURCE_RANGELENGTH	0x00010000 +#define IORESOURCE_SHADOWABLE	0x00020000 -#define IORESOURCE_SIZEALIGN	0x00020000	/* size indicates alignment */ -#define IORESOURCE_STARTALIGN	0x00040000	/* start field is alignment */ +#define IORESOURCE_SIZEALIGN	0x00040000	/* size indicates alignment */ +#define IORESOURCE_STARTALIGN	0x00080000	/* start field is alignment */  #define IORESOURCE_MEM_64	0x00100000 +#define IORESOURCE_WINDOW	0x00200000	/* forwarded by bridge */  #define IORESOURCE_EXCLUSIVE	0x08000000	/* Userland may not map this resource */  #define IORESOURCE_DISABLED	0x10000000 diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index b5d096d3a9be..ebd2b8fb00d0 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -82,6 +82,7 @@ enum power_supply_property {  	POWER_SUPPLY_PROP_PRESENT,  	POWER_SUPPLY_PROP_ONLINE,  	POWER_SUPPLY_PROP_TECHNOLOGY, +	POWER_SUPPLY_PROP_CYCLE_COUNT,  	POWER_SUPPLY_PROP_VOLTAGE_MAX,  	POWER_SUPPLY_PROP_VOLTAGE_MIN,  	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 0d461c7c14db..24112e5a5780 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -609,6 +609,12 @@ static char *resource_string(char *buf, char *end, struct resource *res,  		.precision = -1,  		.flags = SPECIAL | SMALL | ZEROPAD,  	}; +	static const struct printf_spec bus_spec = { +		.base = 16, +		.field_width = 2, +		.precision = -1, +		.flags = SMALL | ZEROPAD, +	};  	static const struct printf_spec dec_spec = {  		.base = 10,  		.precision = -1, @@ -629,7 +635,7 @@ static char *resource_string(char *buf, char *end, struct resource *res,  	 * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */  #define RSRC_BUF_SIZE		((2 * sizeof(resource_size_t)) + 4)  #define FLAG_BUF_SIZE		(2 * sizeof(res->flags)) -#define DECODED_BUF_SIZE	sizeof("[mem - 64bit pref disabled]") +#define DECODED_BUF_SIZE	sizeof("[mem - 64bit pref window disabled]")  #define RAW_BUF_SIZE		sizeof("[mem - flags 0x]")  	char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE,  		     2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)]; @@ -651,6 +657,9 @@ static char *resource_string(char *buf, char *end, struct resource *res,  	} else if (res->flags & IORESOURCE_DMA) {  		p = string(p, pend, "dma ", str_spec);  		specp = &dec_spec; +	} else if (res->flags & IORESOURCE_BUS) { +		p = string(p, pend, "bus ", str_spec); +		specp = &bus_spec;  	} else {  		p = string(p, pend, "??? ", str_spec);  		specp = &mem_spec; @@ -666,6 +675,8 @@ static char *resource_string(char *buf, char *end, struct resource *res,  			p = string(p, pend, " 64bit", str_spec);  		if (res->flags & IORESOURCE_PREFETCH)  			p = string(p, pend, " pref", str_spec); +		if (res->flags & IORESOURCE_WINDOW) +			p = string(p, pend, " window", str_spec);  		if (res->flags & IORESOURCE_DISABLED)  			p = string(p, pend, " disabled", str_spec);  	} else { | 
