diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/Makefile | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/exmutex.c | 3 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 86 | ||||
-rw-r--r-- | drivers/acpi/bus.c | 10 | ||||
-rw-r--r-- | drivers/acpi/ec.c | 33 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 2 | ||||
-rw-r--r-- | drivers/acpi/processor_core.c | 1118 | ||||
-rw-r--r-- | drivers/acpi/processor_driver.c | 978 | ||||
-rw-r--r-- | drivers/acpi/processor_pdc.c | 209 | ||||
-rw-r--r-- | drivers/acpi/processor_throttling.c | 3 | ||||
-rw-r--r-- | drivers/acpi/sbs.c | 5 | ||||
-rw-r--r-- | drivers/acpi/sleep.c | 19 | ||||
-rw-r--r-- | drivers/acpi/thermal.c | 36 | ||||
-rw-r--r-- | drivers/acpi/utils.c | 45 | ||||
-rw-r--r-- | drivers/acpi/video.c | 28 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 19 | ||||
-rw-r--r-- | drivers/platform/x86/sony-laptop.c | 91 | ||||
-rw-r--r-- | drivers/pnp/base.h | 3 | ||||
-rw-r--r-- | drivers/pnp/interface.c | 7 | ||||
-rw-r--r-- | drivers/pnp/pnpacpi/rsparser.c | 49 | ||||
-rw-r--r-- | drivers/pnp/resource.c | 27 | ||||
-rw-r--r-- | drivers/pnp/support.c | 4 | ||||
-rw-r--r-- | drivers/power/power_supply_sysfs.c | 1 |
23 files changed, 1454 insertions, 1326 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 66cc3f36a95..a8d8998dd5c 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 cc8a10268f6..7116bc86494 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 58d2c91ba62..75f39f2c166 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 a52126e4630..b70cd375614 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 d7a6bbbb834..1ac28c6a672 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 9c4c962e46e..e2841136723 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 e9b7b402dbf..791ac7b0f8d 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 00000000000..b5658cdce27 --- /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 e306ba9aa34..00000000000 --- 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 7ded7542fc9..29c6f5766dc 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 b16ddbf23a9..89ad11138e4 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 3bde594a997..f74834a544f 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 9073ada8883..5d3893558cf 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 11882dbe209..c9a49f4747e 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 6e9b49149fc..2ff2b6ab5b6 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 cb2fd01edda..b5dad9f3745 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 3f71a605a49..5a3d8514c66 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 0b8d14050ef..0bab84ebb15 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 68b0c04987e..cfaf5b73540 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 5702b2c8691..54514aa35b0 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 64d0596bafb..5b277dbaacd 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 9585c1c1cc3..f5beb24d036 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 c790e0c77d4..ff05e618976 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), |