diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-08-02 21:17:02 -1000 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-08-02 21:17:02 -1000 |
commit | c299eba3c5a801657f275d33be588b34831cd30e (patch) | |
tree | 022a2a72604443fa8ce8d3fd040fbda49b04f681 /drivers | |
parent | 1850536b93888e6cc3ee42e63e20e61f35f8b3e2 (diff) | |
parent | 4a8f5058bde15d737abe39b5bed3f21dcb6599d2 (diff) |
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (28 commits)
ACPI: delete stale reference in kernel-parameters.txt
ACPI: add missing _OSI strings
ACPI: remove NID_INVAL
thermal: make THERMAL_HWMON implementation fully internal
thermal: split hwmon lookup to a separate function
thermal: hide CONFIG_THERMAL_HWMON
ACPI print OSI(Linux) warning only once
ACPI: DMI workaround for Asus A8N-SLI Premium and Asus A8N-SLI DELUX
ACPI / Battery: propagate sysfs error in acpi_battery_add()
ACPI / Battery: avoid acpi_battery_add() use-after-free
ACPI: introduce "acpi_rsdp=" parameter for kdump
ACPI: constify ops structs
ACPI: fix CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS
ACPI: fix 80 char overflow
ACPI / Battery: Resolve the race condition in the sysfs_remove_battery()
ACPI / Battery: Add the check before refresh sysfs in the battery_notify()
ACPI / Battery: Add the hibernation process in the battery_notify()
ACPI / Battery: Rename acpi_battery_quirks2 with acpi_battery_quirks
ACPI / Battery: Change 16-bit signed negative battery current into correct value
ACPI / Battery: Add the power unit macro
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/acpica/acglobal.h | 6 | ||||
-rw-r--r-- | drivers/acpi/acpica/aclocal.h | 1 | ||||
-rw-r--r-- | drivers/acpi/acpica/acpredef.h | 1 | ||||
-rw-r--r-- | drivers/acpi/acpica/nspredef.c | 19 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsrepair2.c | 15 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbinstal.c | 27 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 82 | ||||
-rw-r--r-- | drivers/acpi/dock.c | 4 | ||||
-rw-r--r-- | drivers/acpi/ec_sys.c | 2 | ||||
-rw-r--r-- | drivers/acpi/fan.c | 2 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 25 | ||||
-rw-r--r-- | drivers/acpi/pci_irq.c | 58 | ||||
-rw-r--r-- | drivers/acpi/pci_root.c | 3 | ||||
-rw-r--r-- | drivers/acpi/processor_thermal.c | 2 | ||||
-rw-r--r-- | drivers/acpi/sbs.c | 13 | ||||
-rw-r--r-- | drivers/acpi/sleep.c | 16 | ||||
-rw-r--r-- | drivers/acpi/sysfs.c | 4 | ||||
-rw-r--r-- | drivers/acpi/thermal.c | 2 | ||||
-rw-r--r-- | drivers/acpi/video.c | 2 | ||||
-rw-r--r-- | drivers/ata/libata-acpi.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 2 | ||||
-rw-r--r-- | drivers/thermal/Kconfig | 8 | ||||
-rw-r--r-- | drivers/thermal/thermal_sys.c | 142 |
23 files changed, 343 insertions, 97 deletions
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 73863d86f022..76dc02f15574 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -126,6 +126,12 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE); */ u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE); +/* + * Disable runtime checking and repair of values returned by control methods. + * Use only if the repair is causing a problem on a particular machine. + */ +u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE); + /* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */ struct acpi_table_fadt acpi_gbl_FADT; diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index c7f743ca395b..5552125d8340 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -357,6 +357,7 @@ struct acpi_predefined_data { char *pathname; const union acpi_predefined_info *predefined; union acpi_operand_object *parent_package; + struct acpi_namespace_node *node; u32 flags; u8 node_flags; }; diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index 94e73c97cf85..c445cca490ea 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -468,6 +468,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_SWS", 0, ACPI_RTYPE_INTEGER}}, {{"_TC1", 0, ACPI_RTYPE_INTEGER}}, {{"_TC2", 0, ACPI_RTYPE_INTEGER}}, + {{"_TDL", 0, ACPI_RTYPE_INTEGER}}, {{"_TIP", 1, ACPI_RTYPE_INTEGER}}, {{"_TIV", 1, ACPI_RTYPE_INTEGER}}, {{"_TMP", 0, ACPI_RTYPE_INTEGER}}, diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 9fb03fa8ffde..c845c8089f39 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -193,14 +193,20 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, } /* - * 1) We have a return value, but if one wasn't expected, just exit, this is - * not a problem. For example, if the "Implicit Return" feature is - * enabled, methods will always return a value. + * Return value validation and possible repair. * - * 2) If the return value can be of any type, then we cannot perform any - * validation, exit. + * 1) Don't perform return value validation/repair if this feature + * has been disabled via a global option. + * + * 2) We have a return value, but if one wasn't expected, just exit, + * this is not a problem. For example, if the "Implicit Return" + * feature is enabled, methods will always return a value. + * + * 3) If the return value can be of any type, then we cannot perform + * any validation, just exit. */ - if ((!predefined->info.expected_btypes) || + if (acpi_gbl_disable_auto_repair || + (!predefined->info.expected_btypes) || (predefined->info.expected_btypes == ACPI_RTYPE_ALL)) { goto cleanup; } @@ -212,6 +218,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, goto cleanup; } data->predefined = predefined; + data->node = node; data->node_flags = node->flags; data->pathname = pathname; diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 973883babee1..024c4f263f87 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -503,6 +503,21 @@ acpi_ns_repair_TSS(struct acpi_predefined_data *data, { union acpi_operand_object *return_object = *return_object_ptr; acpi_status status; + struct acpi_namespace_node *node; + + /* + * We can only sort the _TSS return package if there is no _PSS in the + * same scope. This is because if _PSS is present, the ACPI specification + * dictates that the _TSS Power Dissipation field is to be ignored, and + * therefore some BIOSs leave garbage values in the _TSS Power field(s). + * In this case, it is best to just return the _TSS package as-is. + * (May, 2011) + */ + status = + acpi_ns_get_node(data->node, "^_PSS", ACPI_NS_NO_UPSEARCH, &node); + if (ACPI_SUCCESS(status)) { + return (AE_OK); + } status = acpi_ns_check_sorted_list(data, return_object, 5, 1, ACPI_SORT_DESCENDING, diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 48db0944ce4a..62365f6075dd 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -126,12 +126,29 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) } /* - * Originally, we checked the table signature for "SSDT" or "PSDT" here. - * Next, we added support for OEMx tables, signature "OEM". - * Valid tables were encountered with a null signature, so we've just - * given up on validating the signature, since it seems to be a waste - * of code. The original code was removed (05/2008). + * Validate the incoming table signature. + * + * 1) Originally, we checked the table signature for "SSDT" or "PSDT". + * 2) We added support for OEMx tables, signature "OEM". + * 3) Valid tables were encountered with a null signature, so we just + * gave up on validating the signature, (05/2008). + * 4) We encountered non-AML tables such as the MADT, which caused + * interpreter errors and kernel faults. So now, we once again allow + * only "SSDT", "OEMx", and now, also a null signature. (05/2011). */ + if ((table_desc->pointer->signature[0] != 0x00) && + (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)) + && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) { + ACPI_ERROR((AE_INFO, + "Table has invalid signature [%4.4s] (0x%8.8X), must be SSDT or OEMx", + acpi_ut_valid_acpi_name(*(u32 *)table_desc-> + pointer-> + signature) ? table_desc-> + pointer->signature : "????", + *(u32 *)table_desc->pointer->signature)); + + return_ACPI_STATUS(AE_BAD_SIGNATURE); + } (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 2c661353e8f2..87c0a8daa99a 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -55,6 +55,9 @@ #define ACPI_BATTERY_NOTIFY_INFO 0x81 #define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82 +/* Battery power unit: 0 means mW, 1 means mA */ +#define ACPI_BATTERY_POWER_UNIT_MA 1 + #define _COMPONENT ACPI_BATTERY_COMPONENT ACPI_MODULE_NAME("battery"); @@ -91,11 +94,6 @@ MODULE_DEVICE_TABLE(acpi, battery_device_ids); 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, ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, }; @@ -301,7 +299,8 @@ static enum power_supply_property energy_battery_props[] = { #ifdef CONFIG_ACPI_PROCFS_POWER inline char *acpi_battery_units(struct acpi_battery *battery) { - return (battery->power_unit)?"mA":"mW"; + return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ? + "mA" : "mW"; } #endif @@ -461,9 +460,17 @@ static int acpi_battery_get_state(struct acpi_battery *battery) battery->update_time = jiffies; kfree(buffer.pointer); - if (test_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags) && - battery->rate_now != -1) + /* 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. + */ + if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA && + battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN && + (s16)(battery->rate_now) < 0) { battery->rate_now = abs((s16)battery->rate_now); + printk_once(KERN_WARNING FW_BUG "battery: (dis)charge rate" + " invalid.\n"); + } if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) && battery->capacity_now >= 0 && battery->capacity_now <= 100) @@ -544,7 +551,7 @@ static int sysfs_add_battery(struct acpi_battery *battery) { int result; - if (battery->power_unit) { + if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) { battery->bat.properties = charge_battery_props; battery->bat.num_properties = ARRAY_SIZE(charge_battery_props); @@ -566,18 +573,16 @@ static int sysfs_add_battery(struct acpi_battery *battery) static void sysfs_remove_battery(struct acpi_battery *battery) { - if (!battery->bat.dev) + mutex_lock(&battery->lock); + if (!battery->bat.dev) { + mutex_unlock(&battery->lock); return; + } + device_remove_file(battery->bat.dev, &alarm_attr); power_supply_unregister(&battery->bat); battery->bat.dev = NULL; -} - -static void acpi_battery_quirks(struct acpi_battery *battery) -{ - if (dmi_name_in_vendors("Acer") && battery->power_unit) { - set_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags); - } + mutex_unlock(&battery->lock); } /* @@ -592,7 +597,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery) * * Handle this correctly so that they won't break userspace. */ -static void acpi_battery_quirks2(struct acpi_battery *battery) +static void acpi_battery_quirks(struct acpi_battery *battery) { if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) return ; @@ -623,13 +628,15 @@ static int acpi_battery_update(struct acpi_battery *battery) result = acpi_battery_get_info(battery); if (result) return result; - acpi_battery_quirks(battery); acpi_battery_init_alarm(battery); } - if (!battery->bat.dev) - sysfs_add_battery(battery); + if (!battery->bat.dev) { + result = sysfs_add_battery(battery); + if (result) + return result; + } result = acpi_battery_get_state(battery); - acpi_battery_quirks2(battery); + acpi_battery_quirks(battery); return result; } @@ -863,7 +870,7 @@ DECLARE_FILE_FUNCTIONS(alarm); }, \ } -static struct battery_file { +static const struct battery_file { struct file_operations ops; mode_t mode; const char *name; @@ -948,9 +955,12 @@ static int battery_notify(struct notifier_block *nb, struct acpi_battery *battery = container_of(nb, struct acpi_battery, pm_nb); switch (mode) { + case PM_POST_HIBERNATION: case PM_POST_SUSPEND: - sysfs_remove_battery(battery); - sysfs_add_battery(battery); + if (battery->bat.dev) { + sysfs_remove_battery(battery); + sysfs_add_battery(battery); + } break; } @@ -975,25 +985,33 @@ static int acpi_battery_add(struct acpi_device *device) if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, "_BIX", &handle))) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); - acpi_battery_update(battery); + result = acpi_battery_update(battery); + if (result) + goto fail; #ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); #endif - if (!result) { - printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", - ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), - device->status.battery_present ? "present" : "absent"); - } else { + if (result) { #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif - kfree(battery); + goto fail; } + printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", + ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), + device->status.battery_present ? "present" : "absent"); + battery->pm_nb.notifier_call = battery_notify; register_pm_notifier(&battery->pm_nb); return result; + +fail: + sysfs_remove_battery(battery); + mutex_destroy(&battery->lock); + kfree(battery); + return result; } static int acpi_battery_remove(struct acpi_device *device, int type) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 1864ad3cf895..19a61136d848 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -77,7 +77,7 @@ struct dock_dependent_device { struct list_head list; struct list_head hotplug_list; acpi_handle handle; - struct acpi_dock_ops *ops; + const struct acpi_dock_ops *ops; void *context; }; @@ -589,7 +589,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier); * the dock driver after _DCK is executed. */ int -register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops, +register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, void *context) { struct dock_dependent_device *dd; diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 05b44201a614..22f918bacd35 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -92,7 +92,7 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf, return count; } -static struct file_operations acpi_ec_io_ops = { +static const struct file_operations acpi_ec_io_ops = { .owner = THIS_MODULE, .open = acpi_ec_open_io, .read = acpi_ec_read_io, diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 467479f07c1f..0f0356ca1a9e 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -110,7 +110,7 @@ fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) return result; } -static struct thermal_cooling_device_ops fan_cooling_ops = { +static const struct thermal_cooling_device_ops fan_cooling_ops = { .get_max_state = fan_get_max_state, .get_cur_state = fan_get_cur_state, .set_cur_state = fan_set_cur_state, diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 372f9b70f7f4..fa32f584229f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -155,7 +155,7 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported) { if (!strcmp("Linux", interface)) { - printk(KERN_NOTICE FW_BUG PREFIX + printk_once(KERN_NOTICE FW_BUG PREFIX "BIOS _OSI(Linux) query %s%s\n", osi_linux.enable ? "honored" : "ignored", osi_linux.cmdline ? " via cmdline" : @@ -237,8 +237,23 @@ void acpi_os_vprintf(const char *fmt, va_list args) #endif } +#ifdef CONFIG_KEXEC +static unsigned long acpi_rsdp; +static int __init setup_acpi_rsdp(char *arg) +{ + acpi_rsdp = simple_strtoul(arg, NULL, 16); + return 0; +} +early_param("acpi_rsdp", setup_acpi_rsdp); +#endif + acpi_physical_address __init acpi_os_get_root_pointer(void) { +#ifdef CONFIG_KEXEC + if (acpi_rsdp) + return acpi_rsdp; +#endif + if (efi_enabled) { if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) return efi.acpi20; @@ -1083,7 +1098,13 @@ struct osi_setup_entry { bool enable; }; -static struct osi_setup_entry __initdata osi_setup_entries[OSI_STRING_ENTRIES_MAX]; +static struct osi_setup_entry __initdata + osi_setup_entries[OSI_STRING_ENTRIES_MAX] = { + {"Module Device", true}, + {"Processor Device", true}, + {"3.0 _SCP Extensions", true}, + {"Processor Aggregator Device", true}, +}; void __init acpi_osi_setup(char *str) { diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index f907cfbfa13c..7f9eba9a0b02 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -303,6 +303,61 @@ void acpi_pci_irq_del_prt(struct pci_bus *bus) /* -------------------------------------------------------------------------- PCI Interrupt Routing Support -------------------------------------------------------------------------- */ +#ifdef CONFIG_X86_IO_APIC +extern int noioapicquirk; +extern int noioapicreroute; + +static int bridge_has_boot_interrupt_variant(struct pci_bus *bus) +{ + struct pci_bus *bus_it; + + for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) { + if (!bus_it->self) + return 0; + if (bus_it->self->irq_reroute_variant) + return bus_it->self->irq_reroute_variant; + } + return 0; +} + +/* + * Some chipsets (e.g. Intel 6700PXH) generate a legacy INTx when the IRQ + * entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel does + * during interrupt handling). When this INTx generation cannot be disabled, + * we reroute these interrupts to their legacy equivalent to get rid of + * spurious interrupts. + */ +static int acpi_reroute_boot_interrupt(struct pci_dev *dev, + struct acpi_prt_entry *entry) +{ + if (noioapicquirk || noioapicreroute) { + return 0; + } else { + switch (bridge_has_boot_interrupt_variant(dev->bus)) { + case 0: + /* no rerouting necessary */ + return 0; + case INTEL_IRQ_REROUTE_VARIANT: + /* + * Remap according to INTx routing table in 6700PXH + * specs, intel order number 302628-002, section + * 2.15.2. Other chipsets (80332, ...) have the same + * mapping and are handled here as well. + */ + dev_info(&dev->dev, "PCI IRQ %d -> rerouted to legacy " + "IRQ %d\n", entry->index, + (entry->index % 4) + 16); + entry->index = (entry->index % 4) + 16; + return 1; + default: + dev_warn(&dev->dev, "Cannot reroute IRQ %d to legacy " + "IRQ: unknown mapping\n", entry->index); + return -1; + } + } +} +#endif /* CONFIG_X86_IO_APIC */ + static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) { struct acpi_prt_entry *entry; @@ -311,6 +366,9 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) entry = acpi_pci_irq_find_prt_entry(dev, pin); if (entry) { +#ifdef CONFIG_X86_IO_APIC + acpi_reroute_boot_interrupt(dev, entry); +#endif /* CONFIG_X86_IO_APIC */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n", pci_name(dev), pin_name(pin))); return entry; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d06078d660ad..2672c798272f 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -485,7 +485,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) root->secondary.end = 0xFF; printk(KERN_WARNING FW_BUG PREFIX "no secondary bus range in _CRS\n"); - status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus); + status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, + NULL, &bus); if (ACPI_SUCCESS(status)) root->secondary.start = bus; else if (status == AE_NOT_FOUND) diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 79cb65332894..870550d6a4bf 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -244,7 +244,7 @@ processor_set_cur_state(struct thermal_cooling_device *cdev, return result; } -struct thermal_cooling_device_ops processor_cooling_ops = { +const struct thermal_cooling_device_ops processor_cooling_ops = { .get_max_state = processor_get_max_state, .get_cur_state = processor_get_cur_state, .set_cur_state = processor_set_cur_state, diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 50658ff887d9..6e36d0c0057c 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -130,6 +130,9 @@ struct acpi_sbs { #define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger) +static int acpi_sbs_remove(struct acpi_device *device, int type); +static int acpi_battery_get_state(struct acpi_battery *battery); + static inline int battery_scale(int log) { int scale = 1; @@ -195,6 +198,8 @@ static int acpi_sbs_battery_get_property(struct power_supply *psy, if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT) return -ENODEV; + + acpi_battery_get_state(battery); switch (psp) { case POWER_SUPPLY_PROP_STATUS: if (battery->rate_now < 0) @@ -225,11 +230,17 @@ static int acpi_sbs_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_POWER_NOW: val->intval = abs(battery->rate_now) * acpi_battery_ipscale(battery) * 1000; + val->intval *= (acpi_battery_mode(battery)) ? + (battery->voltage_now * + acpi_battery_vscale(battery) / 1000) : 1; break; case POWER_SUPPLY_PROP_CURRENT_AVG: case POWER_SUPPLY_PROP_POWER_AVG: val->intval = abs(battery->rate_avg) * acpi_battery_ipscale(battery) * 1000; + val->intval *= (acpi_battery_mode(battery)) ? + (battery->voltage_now * + acpi_battery_vscale(battery) / 1000) : 1; break; case POWER_SUPPLY_PROP_CAPACITY: val->intval = battery->state_of_charge; @@ -903,8 +914,6 @@ static void acpi_sbs_callback(void *context) } } -static int acpi_sbs_remove(struct acpi_device *device, int type); - static int acpi_sbs_add(struct acpi_device *device) { struct acpi_sbs *sbs; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 6c949602cbd1..3ed80b2ca907 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -428,6 +428,22 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), }, }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus A8N-SLI DELUXE", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus A8N-SLI Premium", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"), + }, + }, {}, }; #endif /* CONFIG_SUSPEND */ diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 77255f250dbb..c538d0ef10ff 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -149,12 +149,12 @@ static int param_get_debug_level(char *buffer, const struct kernel_param *kp) return result; } -static struct kernel_param_ops param_ops_debug_layer = { +static const struct kernel_param_ops param_ops_debug_layer = { .set = param_set_uint, .get = param_get_debug_layer, }; -static struct kernel_param_ops param_ops_debug_level = { +static const struct kernel_param_ops param_ops_debug_level = { .set = param_set_uint, .get = param_get_debug_level, }; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 2607e17b520f..48fbc647b178 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -812,7 +812,7 @@ acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, thermal_zone_unbind_cooling_device); } -static struct thermal_zone_device_ops acpi_thermal_zone_ops = { +static const struct thermal_zone_device_ops acpi_thermal_zone_ops = { .bind = acpi_thermal_bind_cooling_device, .unbind = acpi_thermal_unbind_cooling_device, .get_temp = thermal_get_temp, diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index ada4b4d9bdc8..08a44b532f7c 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -307,7 +307,7 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st return acpi_video_device_lcd_set_level(video, level); } -static struct thermal_cooling_device_ops video_cooling_ops = { +static const struct thermal_cooling_device_ops video_cooling_ops = { .get_max_state = video_get_max_state, .get_cur_state = video_get_cur_state, .set_cur_state = video_set_cur_state, diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index e0a5b555cee1..bb7c5f1085cc 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -218,12 +218,12 @@ static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) ata_acpi_uevent(dev->link->ap, dev, event); } -static struct acpi_dock_ops ata_acpi_dev_dock_ops = { +static const struct acpi_dock_ops ata_acpi_dev_dock_ops = { .handler = ata_acpi_dev_notify_dock, .uevent = ata_acpi_dev_uevent, }; -static struct acpi_dock_ops ata_acpi_ap_dock_ops = { +static const struct acpi_dock_ops ata_acpi_ap_dock_ops = { .handler = ata_acpi_ap_notify_dock, .uevent = ata_acpi_ap_uevent, }; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a70fa89f76fd..220285760b68 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -110,7 +110,7 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, } -static struct acpi_dock_ops acpiphp_dock_ops = { +static const struct acpi_dock_ops acpiphp_dock_ops = { .handler = handle_hotplug_event_func, }; diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index bf7c687519ef..f7f71b2d3101 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -14,11 +14,7 @@ menuconfig THERMAL If you want this support, you should say Y or M here. config THERMAL_HWMON - bool "Hardware monitoring support" + bool depends on THERMAL depends on HWMON=y || HWMON=THERMAL - help - The generic thermal sysfs driver's hardware monitoring support - requires a 2.10.7/3.0.2 or later lm-sensors userspace. - - Say Y if your user-space is new enough. + default y diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 0b1c82ad6805..708f8e92771a 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -420,6 +420,29 @@ thermal_cooling_device_trip_point_show(struct device *dev, /* hwmon sys I/F */ #include <linux/hwmon.h> + +/* thermal zone devices with the same type share one hwmon device */ +struct thermal_hwmon_device { + char type[THERMAL_NAME_LENGTH]; + struct device *device; + int count; + struct list_head tz_list; + struct list_head node; +}; + +struct thermal_hwmon_attr { + struct device_attribute attr; + char name[16]; +}; + +/* one temperature input for each thermal zone */ +struct thermal_hwmon_temp { + struct list_head hwmon_node; + struct thermal_zone_device *tz; + struct thermal_hwmon_attr temp_input; /* hwmon sys attr */ + struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */ +}; + static LIST_HEAD(thermal_hwmon_list); static ssize_t @@ -437,9 +460,10 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) int ret; struct thermal_hwmon_attr *hwmon_attr = container_of(attr, struct thermal_hwmon_attr, attr); - struct thermal_zone_device *tz - = container_of(hwmon_attr, struct thermal_zone_device, + struct thermal_hwmon_temp *temp + = container_of(hwmon_attr, struct thermal_hwmon_temp, temp_input); + struct thermal_zone_device *tz = temp->tz; ret = tz->ops->get_temp(tz, &temperature); @@ -455,9 +479,10 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, { struct thermal_hwmon_attr *hwmon_attr = container_of(attr, struct thermal_hwmon_attr, attr); - struct thermal_zone_device *tz - = container_of(hwmon_attr, struct thermal_zone_device, + struct thermal_hwmon_temp *temp + = container_of(hwmon_attr, struct thermal_hwmon_temp, temp_crit); + struct thermal_zone_device *tz = temp->tz; long temperature; int ret; @@ -469,22 +494,54 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, } -static int -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) +static struct thermal_hwmon_device * +thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz) { struct thermal_hwmon_device *hwmon; - int new_hwmon_device = 1; - int result; mutex_lock(&thermal_list_lock); list_for_each_entry(hwmon, &thermal_hwmon_list, node) if (!strcmp(hwmon->type, tz->type)) { - new_hwmon_device = 0; mutex_unlock(&thermal_list_lock); - goto register_sys_interface; + return hwmon; + } + mutex_unlock(&thermal_list_lock); + + return NULL; +} + +/* Find the temperature input matching a given thermal zone */ +static struct thermal_hwmon_temp * +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon, + const struct thermal_zone_device *tz) +{ + struct thermal_hwmon_temp *temp; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(temp, &hwmon->tz_list, hwmon_node) + if (temp->tz == tz) { + mutex_unlock(&thermal_list_lock); + return temp; } mutex_unlock(&thermal_list_lock); + return NULL; +} + +static int +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) +{ + struct thermal_hwmon_device *hwmon; + struct thermal_hwmon_temp *temp; + int new_hwmon_device = 1; + int result; + + hwmon = thermal_hwmon_lookup_by_type(tz); + if (hwmon) { + new_hwmon_device = 0; + goto register_sys_interface; + } + hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL); if (!hwmon) return -ENOMEM; @@ -502,30 +559,36 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) goto free_mem; register_sys_interface: - tz->hwmon = hwmon; + temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL); + if (!temp) { + result = -ENOMEM; + goto unregister_name; + } + + temp->tz = tz; hwmon->count++; - snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH, + snprintf(temp->temp_input.name, THERMAL_NAME_LENGTH, "temp%d_input", hwmon->count); - tz->temp_input.attr.attr.name = tz->temp_input.name; - tz->temp_input.attr.attr.mode = 0444; - tz->temp_input.attr.show = temp_input_show; - sysfs_attr_init(&tz->temp_input.attr.attr); - result = device_create_file(hwmon->device, &tz->temp_input.attr); + temp->temp_input.attr.attr.name = temp->temp_input.name; + temp->temp_input.attr.attr.mode = 0444; + temp->temp_input.attr.show = temp_input_show; + sysfs_attr_init(&temp->temp_input.attr.attr); + result = device_create_file(hwmon->device, &temp->temp_input.attr); if (result) - goto unregister_name; + goto free_temp_mem; if (tz->ops->get_crit_temp) { unsigned long temperature; if (!tz->ops->get_crit_temp(tz, &temperature)) { - snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH, + snprintf(temp->temp_crit.name, THERMAL_NAME_LENGTH, "temp%d_crit", hwmon->count); - tz->temp_crit.attr.attr.name = tz->temp_crit.name; - tz->temp_crit.attr.attr.mode = 0444; - tz->temp_crit.attr.show = temp_crit_show; - sysfs_attr_init(&tz->temp_crit.attr.attr); + temp->temp_crit.attr.attr.name = temp->temp_crit.name; + temp->temp_crit.attr.attr.mode = 0444; + temp->temp_crit.attr.show = temp_crit_show; + sysfs_attr_init(&temp->temp_crit.attr.attr); result = device_create_file(hwmon->device, - &tz->temp_crit.attr); + &temp->temp_crit.attr); if (result) goto unregister_input; } @@ -534,13 +597,15 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) mutex_lock(&thermal_list_lock); if (new_hwmon_device) list_add_tail(&hwmon->node, &thermal_hwmon_list); - list_add_tail(&tz->hwmon_node, &hwmon->tz_list); + list_add_tail(&temp->hwmon_node, &hwmon->tz_list); mutex_unlock(&thermal_list_lock); return 0; unregister_input: - device_remove_file(hwmon->device, &tz->temp_input.attr); + device_remove_file(hwmon->device, &temp->temp_input.attr); + free_temp_mem: + kfree(temp); unregister_name: if (new_hwmon_device) { device_remove_file(hwmon->device, &dev_attr_name); @@ -556,15 +621,30 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) static void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) { - struct thermal_hwmon_device *hwmon = tz->hwmon; + struct thermal_hwmon_device *hwmon; + struct thermal_hwmon_temp *temp; + + hwmon = thermal_hwmon_lookup_by_type(tz); + if (unlikely(!hwmon)) { + /* Should never happen... */ + dev_dbg(&tz->device, "hwmon device lookup failed!\n"); + return; + } + + temp = thermal_hwmon_lookup_temp(hwmon, tz); + if (unlikely(!temp)) { + /* Should never happen... */ + dev_dbg(&tz->device, "temperature input lookup failed!\n"); + return; + } - tz->hwmon = NULL; - device_remove_file(hwmon->device, &tz->temp_input.attr); + device_remove_file(hwmon->device, &temp->temp_input.attr); if (tz->ops->get_crit_temp) - device_remove_file(hwmon->device, &tz->temp_crit.attr); + device_remove_file(hwmon->device, &temp->temp_crit.attr); mutex_lock(&thermal_list_lock); - list_del(&tz->hwmon_node); + list_del(&temp->hwmon_node); + kfree(temp); if (!list_empty(&hwmon->tz_list)) { mutex_unlock(&thermal_list_lock); return; |