From cf450136bfde77c7f95065c91bffded4aa7fa731 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 31 Jul 2011 13:23:49 -0400 Subject: ACPI: ignore FADT reset-reg-sup flag we check that the address is non-zero later anyway. https://bugzilla.kernel.org/show_bug.cgi?id=11533 Signed-off-by: Len Brown --- drivers/acpi/acpica/hwxface.c | 3 +-- drivers/acpi/reboot.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 9d38eb6c0d0..fe1fb6366aa 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -74,8 +74,7 @@ acpi_status acpi_reset(void) /* Check if the reset register is supported */ - if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || - !reset_reg->address) { + if (!reset_reg->address) { return_ACPI_STATUS(AE_NOT_EXIST); } diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index a6c77e8b37b..c1d61243593 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -23,8 +23,7 @@ void acpi_reboot(void) /* Is the reset register supported? The spec says we should be * checking the bit width and bit offset, but Windows ignores * these fields */ - if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)) - return; + /* Ignore also acpi_gbl_FADT.flags.ACPI_FADT_RESET_REGISTER */ reset_value = acpi_gbl_FADT.reset_value; -- cgit v1.2.3-18-g5258 From 3e80acd1af40fcd91a200b0416a7616b20c5d647 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Thu, 23 Feb 2012 22:40:43 +0200 Subject: ACPICA: Fix regression in FADT revision checks commit 64b3db22c04586997ab4be46dd5a5b99f8a2d390 (2.6.39), "Remove use of unreliable FADT revision field" causes regression for old P4 systems because now cst_control and other fields are not reset to 0. The effect is that acpi_processor_power_init will notice cst_control != 0 and a write to CST_CNT register is performed that should not happen. As result, the system oopses after the "No _CST, giving up" message, sometimes in acpi_ns_internalize_name, sometimes in acpi_ns_get_type, usually at random places. May be during migration to CPU 1 in acpi_processor_get_throttling. Every one of these settings help to avoid this problem: - acpi=off - processor.nocst=1 - maxcpus=1 The fix is to update acpi_gbl_FADT.header.length after the original value is used to check for old revisions. https://bugzilla.kernel.org/show_bug.cgi?id=42700 https://bugzilla.redhat.com/show_bug.cgi?id=727865 Signed-off-by: Julian Anastasov Acked-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/acpica/tbfadt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index c5d870406f4..4c9c760db4a 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -363,10 +363,6 @@ static void acpi_tb_convert_fadt(void) u32 address32; u32 i; - /* Update the local FADT table header length */ - - acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); - /* * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. * Later code will always use the X 64-bit field. Also, check for an @@ -408,6 +404,10 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_FADT.boot_flags = 0; } + /* Update the local FADT table header length */ + + acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); + /* * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" * generic address structures as necessary. Later code will always use -- cgit v1.2.3-18-g5258 From e1689795a784a7c41ac4cf9032794986b095a133 Mon Sep 17 00:00:00 2001 From: Robert Lee Date: Tue, 20 Mar 2012 15:22:42 -0500 Subject: cpuidle: Add common time keeping and irq enabling Make necessary changes to implement time keeping and irq enabling in the core cpuidle code. This will allow the removal of these functionalities from various platform cpuidle implementations whose timekeeping and irq enabling follows the form in this common code. Signed-off-by: Robert Lee Tested-by: Jean Pihet Tested-by: Amit Daniel Tested-by: Robert Lee Reviewed-by: Kevin Hilman Reviewed-by: Daniel Lezcano Reviewed-by: Deepthi Dharwar Acked-by: Jean Pihet Signed-off-by: Len Brown --- drivers/cpuidle/cpuidle.c | 66 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 59f4261c753..4869b550023 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -53,6 +53,24 @@ static void cpuidle_kick_cpus(void) {} static int __cpuidle_register_device(struct cpuidle_device *dev); +static inline int cpuidle_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + struct cpuidle_state *target_state = &drv->states[index]; + return target_state->enter(dev, drv, index); +} + +static inline int cpuidle_enter_tk(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter); +} + +typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index); + +static cpuidle_enter_t cpuidle_enter_ops; + /** * cpuidle_idle_call - the main idle loop * @@ -63,7 +81,6 @@ int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_driver *drv = cpuidle_get_driver(); - struct cpuidle_state *target_state; int next_state, entered_state; if (off) @@ -92,12 +109,10 @@ int cpuidle_idle_call(void) return 0; } - target_state = &drv->states[next_state]; - trace_power_start(POWER_CSTATE, next_state, dev->cpu); trace_cpu_idle(next_state, dev->cpu); - entered_state = target_state->enter(dev, drv, next_state); + entered_state = cpuidle_enter_ops(dev, drv, next_state); trace_power_end(dev->cpu); trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); @@ -110,6 +125,8 @@ int cpuidle_idle_call(void) dev->states_usage[entered_state].time += (unsigned long long)dev->last_residency; dev->states_usage[entered_state].usage++; + } else { + dev->last_residency = 0; } /* give the governor an opportunity to reflect on the outcome */ @@ -164,6 +181,37 @@ void cpuidle_resume_and_unlock(void) EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); +/** + * cpuidle_wrap_enter - performs timekeeping and irqen around enter function + * @dev: pointer to a valid cpuidle_device object + * @drv: pointer to a valid cpuidle_driver object + * @index: index of the target cpuidle state. + */ +int cpuidle_wrap_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index, + int (*enter)(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index)) +{ + ktime_t time_start, time_end; + s64 diff; + + time_start = ktime_get(); + + index = enter(dev, drv, index); + + time_end = ktime_get(); + + local_irq_enable(); + + diff = ktime_to_us(ktime_sub(time_end, time_start)); + if (diff > INT_MAX) + diff = INT_MAX; + + dev->last_residency = (int) diff; + + return index; +} + #ifdef CONFIG_ARCH_HAS_CPU_RELAX static int poll_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -212,10 +260,11 @@ static void poll_idle_init(struct cpuidle_driver *drv) {} int cpuidle_enable_device(struct cpuidle_device *dev) { int ret, i; + struct cpuidle_driver *drv = cpuidle_get_driver(); if (dev->enabled) return 0; - if (!cpuidle_get_driver() || !cpuidle_curr_governor) + if (!drv || !cpuidle_curr_governor) return -EIO; if (!dev->state_count) return -EINVAL; @@ -226,13 +275,16 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return ret; } - poll_idle_init(cpuidle_get_driver()); + cpuidle_enter_ops = drv->en_core_tk_irqen ? + cpuidle_enter_tk : cpuidle_enter; + + poll_idle_init(drv); if ((ret = cpuidle_add_state_sysfs(dev))) return ret; if (cpuidle_curr_governor->enable && - (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) + (ret = cpuidle_curr_governor->enable(drv, dev))) goto fail_sysfs; for (i = 0; i < dev->state_count; i++) { -- cgit v1.2.3-18-g5258 From b11de07ce561574b6e03c8192b28bad540da8f79 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 21 Mar 2012 12:55:00 -0700 Subject: drivers/thermal/thermal_sys.c: fix build warning With CONFIG_NET=n: drivers/thermal/thermal_sys.c:63: warning: 'thermal_event_seqnum' defined but not used Move 'thermal_event_seqnum' definition inside the '#ifdef CONFIG_NET' [akpm@linux-foundation.org: make thermal_event_seqnum local to generate_netlink_event()] Signed-off-by: Fabio Estevam Acked-by: Guenter Roeck Acked-by: Durgadoss R Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/thermal/thermal_sys.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 220ce7e31cf..859b80b6d37 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -60,8 +60,6 @@ static LIST_HEAD(thermal_tz_list); static LIST_HEAD(thermal_cdev_list); static DEFINE_MUTEX(thermal_list_lock); -static unsigned int thermal_event_seqnum; - static int get_idr(struct idr *idr, struct mutex *lock, int *id) { int err; @@ -1312,6 +1310,7 @@ int thermal_generate_netlink_event(u32 orig, enum events event) void *msg_header; int size; int result; + static unsigned int thermal_event_seqnum; /* allocate memory */ size = nla_total_size(sizeof(struct thermal_genl_event)) + \ -- cgit v1.2.3-18-g5258 From 886ee5463530036f6171e1376118e7014cf33f7f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 21 Mar 2012 12:55:01 -0700 Subject: thermal_sys: remove unnecessary line continuations Line continations are not necessary in function calls or statements. Remove them. Signed-off-by: Joe Perches Reviewed-by: Jesper Juhl Cc: Len Brown Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/thermal/thermal_sys.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 859b80b6d37..71802caec2c 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -281,8 +281,7 @@ passive_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(type, 0444, type_show, NULL); static DEVICE_ATTR(temp, 0444, temp_show, NULL); static DEVICE_ATTR(mode, 0644, mode_show, mode_store); -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \ - passive_store); +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store); static struct device_attribute trip_point_attrs[] = { __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), @@ -1313,8 +1312,8 @@ int thermal_generate_netlink_event(u32 orig, enum events event) static unsigned int thermal_event_seqnum; /* allocate memory */ - size = nla_total_size(sizeof(struct thermal_genl_event)) + \ - nla_total_size(0); + size = nla_total_size(sizeof(struct thermal_genl_event)) + + nla_total_size(0); skb = genlmsg_new(size, GFP_ATOMIC); if (!skb) @@ -1330,8 +1329,8 @@ int thermal_generate_netlink_event(u32 orig, enum events event) } /* fill the data */ - attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, \ - sizeof(struct thermal_genl_event)); + attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, + sizeof(struct thermal_genl_event)); if (!attr) { nlmsg_free(skb); -- cgit v1.2.3-18-g5258 From ec797685609da142588012d734e85d14cff9c7d2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 21 Mar 2012 12:55:02 -0700 Subject: thermal_sys: remove obfuscating used-once macros These don't add any value as they are used only once and the surrounding code uses similar variable. Signed-off-by: Joe Perches Cc: Jesper Juhl Cc: Len Brown Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/thermal/thermal_sys.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 71802caec2c..11237bc2aa9 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -310,22 +310,6 @@ static struct device_attribute trip_point_attrs[] = { __ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL), }; -#define TRIP_POINT_ATTR_ADD(_dev, _index, result) \ -do { \ - result = device_create_file(_dev, \ - &trip_point_attrs[_index * 2]); \ - if (result) \ - break; \ - result = device_create_file(_dev, \ - &trip_point_attrs[_index * 2 + 1]); \ -} while (0) - -#define TRIP_POINT_ATTR_REMOVE(_dev, _index) \ -do { \ - device_remove_file(_dev, &trip_point_attrs[_index * 2]); \ - device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ -} while (0) - /* sys I/F for cooling device */ #define to_cooling_device(_dev) \ container_of(_dev, struct thermal_cooling_device, device) @@ -1196,7 +1180,12 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, } for (count = 0; count < trips; count++) { - TRIP_POINT_ATTR_ADD(&tz->device, count, result); + result = device_create_file(&tz->device, + &trip_point_attrs[count * 2]); + if (result) + break; + result = device_create_file(&tz->device, + &trip_point_attrs[count * 2 + 1]); if (result) goto unregister; tz->ops->get_trip_type(tz, count, &trip_type); @@ -1276,9 +1265,12 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) if (tz->ops->get_mode) device_remove_file(&tz->device, &dev_attr_mode); - for (count = 0; count < tz->trips; count++) - TRIP_POINT_ATTR_REMOVE(&tz->device, count); - + for (count = 0; count < tz->trips; count++) { + device_remove_file(&tz->device, + &trip_point_attrs[count * 2]); + device_remove_file(&tz->device, + &trip_point_attrs[count * 2 + 1]); + } thermal_remove_hwmon_sysfs(tz); release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); idr_destroy(&tz->idr); -- cgit v1.2.3-18-g5258 From caca8b803520b0694423e2ac0ee3d58650b04a12 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 21 Mar 2012 12:55:02 -0700 Subject: thermal_sys: kernel style cleanups Just a few tidies to make it more like most kernel sources. A couple of long lines still remain. Signed-off-by: Joe Perches Reviewed-by: Jesper Juhl Cc: Len Brown Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/thermal/thermal_sys.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 11237bc2aa9..db5d8f88266 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -64,7 +64,7 @@ static int get_idr(struct idr *idr, struct mutex *lock, int *id) { int err; - again: +again: if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0)) return -ENOMEM; @@ -816,15 +816,14 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, return 0; device_remove_file(&tz->device, &dev->attr); - remove_symbol_link: +remove_symbol_link: sysfs_remove_link(&tz->device.kobj, dev->name); - release_idr: +release_idr: release_idr(&tz->idr, &tz->lock, dev->id); - free_mem: +free_mem: kfree(dev); return result; } - EXPORT_SYMBOL(thermal_zone_bind_cooling_device); /** @@ -854,14 +853,13 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, return -ENODEV; - unbind: +unbind: device_remove_file(&tz->device, &pos->attr); sysfs_remove_link(&tz->device.kobj, pos->name); release_idr(&tz->idr, &tz->lock, pos->id); kfree(pos); return 0; } - EXPORT_SYMBOL(thermal_zone_unbind_cooling_device); static void thermal_release(struct device *dev) @@ -869,7 +867,8 @@ static void thermal_release(struct device *dev) struct thermal_zone_device *tz; struct thermal_cooling_device *cdev; - if (!strncmp(dev_name(dev), "thermal_zone", sizeof "thermal_zone" - 1)) { + if (!strncmp(dev_name(dev), "thermal_zone", + sizeof("thermal_zone") - 1)) { tz = to_thermal_zone(dev); kfree(tz); } else { @@ -889,8 +888,9 @@ static struct class thermal_class = { * @devdata: device private data. * @ops: standard thermal cooling devices callbacks. */ -struct thermal_cooling_device *thermal_cooling_device_register( - char *type, void *devdata, const struct thermal_cooling_device_ops *ops) +struct thermal_cooling_device * +thermal_cooling_device_register(char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) { struct thermal_cooling_device *cdev; struct thermal_zone_device *pos; @@ -955,12 +955,11 @@ struct thermal_cooling_device *thermal_cooling_device_register( if (!result) return cdev; - unregister: +unregister: release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); device_unregister(&cdev->device); return ERR_PTR(result); } - EXPORT_SYMBOL(thermal_cooling_device_register); /** @@ -1005,7 +1004,6 @@ void thermal_cooling_device_unregister(struct device_unregister(&cdev->device); return; } - EXPORT_SYMBOL(thermal_cooling_device_unregister); /** @@ -1081,7 +1079,7 @@ void thermal_zone_device_update(struct thermal_zone_device *tz) tz->last_temperature = temp; - leave: +leave: if (tz->passive) thermal_zone_device_set_polling(tz, tz->passive_delay); else if (tz->polling_delay) @@ -1221,12 +1219,11 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, if (!result) return tz; - unregister: +unregister: release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); device_unregister(&tz->device); return ERR_PTR(result); } - EXPORT_SYMBOL(thermal_zone_device_register); /** @@ -1278,7 +1275,6 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) device_unregister(&tz->device); return; } - EXPORT_SYMBOL(thermal_zone_device_unregister); #ifdef CONFIG_NET -- cgit v1.2.3-18-g5258 From c5a01dd52dc4903772f464ea580895ccc36e911d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 21 Mar 2012 12:55:02 -0700 Subject: thermal_sys: convert printks to pr_ Use the current logging style. Remove PREFIX, add pr_fmt, convert the printks. All dmesg output now prefixed with "thermal_sys: ". Signed-off-by: Joe Perches Cc: Jesper Juhl Cc: Len Brown Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/thermal/thermal_sys.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index db5d8f88266..fab970d9e3e 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -23,6 +23,8 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -39,8 +41,6 @@ MODULE_AUTHOR("Zhang Rui"); MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_LICENSE("GPL"); -#define PREFIX "Thermal: " - struct thermal_cooling_device_instance { int id; char name[THERMAL_NAME_LENGTH]; @@ -1023,8 +1023,7 @@ void thermal_zone_device_update(struct thermal_zone_device *tz) if (tz->ops->get_temp(tz, &temp)) { /* get_temp failed - retry it later */ - printk(KERN_WARNING PREFIX "failed to read out thermal zone " - "%d\n", tz->id); + pr_warn("failed to read out thermal zone %d\n", tz->id); goto leave; } @@ -1039,9 +1038,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz) ret = tz->ops->notify(tz, count, trip_type); if (!ret) { - printk(KERN_EMERG - "Critical temperature reached (%ld C), shutting down.\n", - temp/1000); + pr_emerg("Critical temperature reached (%ld C), shutting down\n", + temp/1000); orderly_poweroff(true); } } @@ -1345,7 +1343,7 @@ int thermal_generate_netlink_event(u32 orig, enum events event) result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC); if (result) - printk(KERN_INFO "failed to send netlink event:%d", result); + pr_info("failed to send netlink event:%d\n", result); return result; } -- cgit v1.2.3-18-g5258 From 6a92c36688bd6d8e68e19ca9b5e41e8197921b59 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Wed, 21 Mar 2012 12:55:03 -0700 Subject: thermal: add support for thermal sensor present on SPEAr13xx machines ST's SPEAr13xx machines are based on CortexA9 ARM processors. These machines contain a thermal sensor for junction temperature monitoring. This patch adds support for this thermal sensor in existing thermal framework. [akpm@linux-foundation.org: little code cleanup] [akpm@linux-foundation.org: print the pointer correctly] [viresh.kumar@st.com: thermal/spear_thermal: add compilation dependency on PLAT_SPEAR] Signed-off-by: Vincenzo Frascino Signed-off-by: Viresh Kumar Signed-off-by: Viresh Kumar Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/thermal/Kconfig | 8 ++ drivers/thermal/Makefile | 1 + drivers/thermal/spear_thermal.c | 206 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 drivers/thermal/spear_thermal.c (limited to 'drivers') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index f7f71b2d310..514a691abea 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -18,3 +18,11 @@ config THERMAL_HWMON depends on THERMAL depends on HWMON=y || HWMON=THERMAL default y + +config SPEAR_THERMAL + bool "SPEAr thermal sensor driver" + depends on THERMAL + depends on PLAT_SPEAR + help + Enable this to plug the SPEAr thermal sensor driver into the Linux + thermal framework diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 31108a01c22..a9fff0bf4b1 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_THERMAL) += thermal_sys.o +obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o \ No newline at end of file diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c new file mode 100644 index 00000000000..880bf289aa6 --- /dev/null +++ b/drivers/thermal/spear_thermal.c @@ -0,0 +1,206 @@ +/* + * SPEAr thermal driver. + * + * Copyright (C) 2011-2012 ST Microelectronics + * Author: Vincenzo Frascino + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MD_FACTOR 1000 + +/* SPEAr Thermal Sensor Dev Structure */ +struct spear_thermal_dev { + /* pointer to base address of the thermal sensor */ + void __iomem *thermal_base; + /* clk structure */ + struct clk *clk; + /* pointer to thermal flags */ + unsigned int flags; +}; + +static inline int thermal_get_temp(struct thermal_zone_device *thermal, + unsigned long *temp) +{ + struct spear_thermal_dev *stdev = thermal->devdata; + + /* + * Data are ready to be read after 628 usec from POWERDOWN signal + * (PDN) = 1 + */ + *temp = (readl(stdev->thermal_base) & 0x7F) * MD_FACTOR; + return 0; +} + +static struct thermal_zone_device_ops ops = { + .get_temp = thermal_get_temp, +}; + +#ifdef CONFIG_PM +static int spear_thermal_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev); + struct spear_thermal_dev *stdev = spear_thermal->devdata; + unsigned int actual_mask = 0; + + /* Disable SPEAr Thermal Sensor */ + actual_mask = readl(stdev->thermal_base); + writel(actual_mask & ~stdev->flags, stdev->thermal_base); + + clk_disable(stdev->clk); + dev_info(dev, "Suspended.\n"); + + return 0; +} + +static int spear_thermal_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev); + struct spear_thermal_dev *stdev = spear_thermal->devdata; + unsigned int actual_mask = 0; + int ret = 0; + + ret = clk_enable(stdev->clk); + if (ret) { + dev_err(&pdev->dev, "Can't enable clock\n"); + return ret; + } + + /* Enable SPEAr Thermal Sensor */ + actual_mask = readl(stdev->thermal_base); + writel(actual_mask | stdev->flags, stdev->thermal_base); + + dev_info(dev, "Resumed.\n"); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(spear_thermal_pm_ops, spear_thermal_suspend, + spear_thermal_resume); + +static int spear_thermal_probe(struct platform_device *pdev) +{ + struct thermal_zone_device *spear_thermal = NULL; + struct spear_thermal_dev *stdev; + struct spear_thermal_pdata *pdata; + int ret = 0; + struct resource *stres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!stres) { + dev_err(&pdev->dev, "memory resource missing\n"); + return -ENODEV; + } + + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "platform data is NULL\n"); + return -EINVAL; + } + + stdev = devm_kzalloc(&pdev->dev, sizeof(*stdev), GFP_KERNEL); + if (!stdev) { + dev_err(&pdev->dev, "kzalloc fail\n"); + return -ENOMEM; + } + + /* Enable thermal sensor */ + stdev->thermal_base = devm_ioremap(&pdev->dev, stres->start, + resource_size(stres)); + if (!stdev->thermal_base) { + dev_err(&pdev->dev, "ioremap failed\n"); + return -ENOMEM; + } + + stdev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(stdev->clk)) { + dev_err(&pdev->dev, "Can't get clock\n"); + return PTR_ERR(stdev->clk); + } + + ret = clk_enable(stdev->clk); + if (ret) { + dev_err(&pdev->dev, "Can't enable clock\n"); + goto put_clk; + } + + stdev->flags = pdata->thermal_flags; + writel(stdev->flags, stdev->thermal_base); + + spear_thermal = thermal_zone_device_register("spear_thermal", 0, + stdev, &ops, 0, 0, 0, 0); + if (!spear_thermal) { + dev_err(&pdev->dev, "thermal zone device is NULL\n"); + ret = -EINVAL; + goto disable_clk; + } + + platform_set_drvdata(pdev, spear_thermal); + + dev_info(&spear_thermal->device, "Thermal Sensor Loaded at: 0x%p.\n", + stdev->thermal_base); + + return 0; + +disable_clk: + clk_disable(stdev->clk); +put_clk: + clk_put(stdev->clk); + + return ret; +} + +static int spear_thermal_exit(struct platform_device *pdev) +{ + unsigned int actual_mask = 0; + struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev); + struct spear_thermal_dev *stdev = spear_thermal->devdata; + + thermal_zone_device_unregister(spear_thermal); + platform_set_drvdata(pdev, NULL); + + /* Disable SPEAr Thermal Sensor */ + actual_mask = readl(stdev->thermal_base); + writel(actual_mask & ~stdev->flags, stdev->thermal_base); + + clk_disable(stdev->clk); + clk_put(stdev->clk); + + return 0; +} + +static struct platform_driver spear_thermal_driver = { + .probe = spear_thermal_probe, + .remove = spear_thermal_exit, + .driver = { + .name = "spear_thermal", + .owner = THIS_MODULE, + .pm = &spear_thermal_pm_ops, + }, +}; + +module_platform_driver(spear_thermal_driver); + +MODULE_AUTHOR("Vincenzo Frascino "); +MODULE_DESCRIPTION("SPEAr thermal driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-18-g5258 From de716e32e61fae5d1f0d000008d3f641cec5c9dd Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 21 Mar 2012 12:55:03 -0700 Subject: thermal/spear_thermal: replace readl/writel with lighter _relaxed variants readl/writel versions for ARM contain memory barrier instruction for synchronizing DMA buffers. These are not required at least on this module. So use lighter _relaxed variants. Signed-off-by: Viresh Kumar Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/thermal/spear_thermal.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c index 880bf289aa6..be94413b95a 100644 --- a/drivers/thermal/spear_thermal.c +++ b/drivers/thermal/spear_thermal.c @@ -46,7 +46,7 @@ static inline int thermal_get_temp(struct thermal_zone_device *thermal, * Data are ready to be read after 628 usec from POWERDOWN signal * (PDN) = 1 */ - *temp = (readl(stdev->thermal_base) & 0x7F) * MD_FACTOR; + *temp = (readl_relaxed(stdev->thermal_base) & 0x7F) * MD_FACTOR; return 0; } @@ -63,8 +63,8 @@ static int spear_thermal_suspend(struct device *dev) unsigned int actual_mask = 0; /* Disable SPEAr Thermal Sensor */ - actual_mask = readl(stdev->thermal_base); - writel(actual_mask & ~stdev->flags, stdev->thermal_base); + actual_mask = readl_relaxed(stdev->thermal_base); + writel_relaxed(actual_mask & ~stdev->flags, stdev->thermal_base); clk_disable(stdev->clk); dev_info(dev, "Suspended.\n"); @@ -87,8 +87,8 @@ static int spear_thermal_resume(struct device *dev) } /* Enable SPEAr Thermal Sensor */ - actual_mask = readl(stdev->thermal_base); - writel(actual_mask | stdev->flags, stdev->thermal_base); + actual_mask = readl_relaxed(stdev->thermal_base); + writel_relaxed(actual_mask | stdev->flags, stdev->thermal_base); dev_info(dev, "Resumed.\n"); @@ -145,7 +145,7 @@ static int spear_thermal_probe(struct platform_device *pdev) } stdev->flags = pdata->thermal_flags; - writel(stdev->flags, stdev->thermal_base); + writel_relaxed(stdev->flags, stdev->thermal_base); spear_thermal = thermal_zone_device_register("spear_thermal", 0, stdev, &ops, 0, 0, 0, 0); @@ -180,8 +180,8 @@ static int spear_thermal_exit(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); /* Disable SPEAr Thermal Sensor */ - actual_mask = readl(stdev->thermal_base); - writel(actual_mask & ~stdev->flags, stdev->thermal_base); + actual_mask = readl_relaxed(stdev->thermal_base); + writel_relaxed(actual_mask & ~stdev->flags, stdev->thermal_base); clk_disable(stdev->clk); clk_put(stdev->clk); -- cgit v1.2.3-18-g5258 From 03ee62f0b9919535a1be02f72fe8153255a7fda0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 21 Mar 2012 12:55:04 -0700 Subject: thermal: spear13xx: checking for NULL instead of IS_ERR() thermal_zone_device_register() never returns NULL, on error it returns and ERR_PTR(). Signed-off-by: Dan Carpenter Reviewed-by: Viresh Kumar Reviewed-by: Vincenzo Frascino Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/thermal/spear_thermal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c index be94413b95a..c2e32df3b16 100644 --- a/drivers/thermal/spear_thermal.c +++ b/drivers/thermal/spear_thermal.c @@ -149,9 +149,9 @@ static int spear_thermal_probe(struct platform_device *pdev) spear_thermal = thermal_zone_device_register("spear_thermal", 0, stdev, &ops, 0, 0, 0, 0); - if (!spear_thermal) { + if (IS_ERR(spear_thermal)) { dev_err(&pdev->dev, "thermal zone device is NULL\n"); - ret = -EINVAL; + ret = PTR_ERR(spear_thermal); goto disable_clk; } -- cgit v1.2.3-18-g5258 From f1f0e2ac596f531c15b7b09ebeb8cfd011fffbd2 Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Wed, 21 Mar 2012 16:40:01 +0530 Subject: thermal: Fix for setting the thermal zone mode to enable/disable Basically without this patch changing the mode of thermal zone is not possible as wrong string size is passed to strncmp. Signed-off-by: Amit Daniel Kachhap Acked-by: Jean Delvare Signed-off-by: Len Brown --- drivers/thermal/thermal_sys.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index fab970d9e3e..022bacb71a7 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -150,9 +150,9 @@ mode_store(struct device *dev, struct device_attribute *attr, if (!tz->ops->set_mode) return -EPERM; - if (!strncmp(buf, "enabled", sizeof("enabled"))) + if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED); - else if (!strncmp(buf, "disabled", sizeof("disabled"))) + else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); else result = -EINVAL; -- cgit v1.2.3-18-g5258 From 2815ab92ba3ab27556212cc306288dc95692824b Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 6 Feb 2012 08:17:11 -0800 Subject: ACPI: Do cpufreq clamping for throttling per package v2 On Intel CPUs the processor typically uses the highest frequency set by any logical CPU. When the system overheats Linux first forces the frequency to the lowest available one to lower the temperature. However this was done only per logical CPU, which means all logical CPUs in a package would need to go through this before the frequency is actually lowered. Worse this delay actually prevents real throttling, because the real throttle code only proceeds when the lowest frequency is already reached. So when a throttle event happens force the lowest frequency for all CPUs in the package where it happened. The per CPU state is now kept per package, not per logical CPU. An alternative would be to do it per cpufreq unit, but since we want to bring down the temperature of the complete chip it's better to do it for all. In principle it may even make sense to do it for all CPUs, but I kept it on the package for now. With this change the frequency is actually lowered, which in terms also allows real throttling to proceed. I also removed an unnecessary per cpu variable initialization. v2: Fix package mapping Cc: Signed-off-by: Andi Kleen Signed-off-by: Len Brown --- drivers/acpi/processor_thermal.c | 45 +++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 3b599abf2b4..641b5450a0d 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -57,6 +57,27 @@ ACPI_MODULE_NAME("processor_thermal"); static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg); static unsigned int acpi_thermal_cpufreq_is_init = 0; +#define reduction_pctg(cpu) \ + per_cpu(cpufreq_thermal_reduction_pctg, phys_package_first_cpu(cpu)) + +/* + * Emulate "per package data" using per cpu data (which should really be + * provided elsewhere) + * + * Note we can lose a CPU on cpu hotunplug, in this case we forget the state + * temporarily. Fortunately that's not a big issue here (I hope) + */ +static int phys_package_first_cpu(int cpu) +{ + int i; + int id = topology_physical_package_id(cpu); + + for_each_online_cpu(i) + if (topology_physical_package_id(i) == id) + return i; + return 0; +} + static int cpu_has_cpufreq(unsigned int cpu) { struct cpufreq_policy policy; @@ -76,7 +97,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, max_freq = ( policy->cpuinfo.max_freq * - (100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20) + (100 - reduction_pctg(policy->cpu) * 20) ) / 100; cpufreq_verify_within_limits(policy, 0, max_freq); @@ -102,16 +123,28 @@ static int cpufreq_get_cur_state(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return 0; - return per_cpu(cpufreq_thermal_reduction_pctg, cpu); + return reduction_pctg(cpu); } static int cpufreq_set_cur_state(unsigned int cpu, int state) { + int i; + if (!cpu_has_cpufreq(cpu)) return 0; - per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state; - cpufreq_update_policy(cpu); + reduction_pctg(cpu) = state; + + /* + * Update all the CPUs in the same package because they all + * contribute to the temperature and often share the same + * frequency. + */ + for_each_online_cpu(i) { + if (topology_physical_package_id(i) == + topology_physical_package_id(cpu)) + cpufreq_update_policy(i); + } return 0; } @@ -119,10 +152,6 @@ void acpi_thermal_cpufreq_init(void) { int i; - for (i = 0; i < nr_cpu_ids; i++) - if (cpu_present(i)) - per_cpu(cpufreq_thermal_reduction_pctg, i) = 0; - i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); if (!i) -- cgit v1.2.3-18-g5258 From d6795fe32da13bde39ea483e42799a22daa730b5 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 6 Feb 2012 08:17:08 -0800 Subject: ACPI: ec: Do request_region outside WARN() WARN() is not supposed to have side effects, so move the request_regions outside. Signed-off-by: Andi Kleen Signed-off-by: Len Brown --- drivers/acpi/ec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index b19a18dd994..3268dcfbaa9 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -812,10 +812,10 @@ static int acpi_ec_add(struct acpi_device *device) first_ec = ec; device->driver_data = ec; - WARN(!request_region(ec->data_addr, 1, "EC data"), - "Could not request EC data io port 0x%lx", ec->data_addr); - WARN(!request_region(ec->command_addr, 1, "EC cmd"), - "Could not request EC cmd io port 0x%lx", ec->command_addr); + ret = !!request_region(ec->data_addr, 1, "EC data"); + WARN(!ret, "Could not request EC data io port 0x%lx", ec->data_addr); + ret = !!request_region(ec->command_addr, 1, "EC cmd"); + WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", ec->gpe, ec->command_addr, ec->data_addr); -- cgit v1.2.3-18-g5258 From 6fe0d0628245fdcd6fad8b837c81e8f7ebc3364d Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 6 Feb 2012 08:17:09 -0800 Subject: ACPI: Make ACPI interrupt threaded Some ACPI interrupt actions may need to wait, and it's easiest to have a thread context for this. So turn the ACPI interrupt into a threaded interrupt. Signed-off-by: Andi Kleen Signed-off-by: Len Brown --- drivers/acpi/osl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 412a1e04a92..02367a8a60e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -595,7 +595,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, acpi_irq_handler = handler; acpi_irq_context = context; - if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { + if (request_threaded_irq(irq, NULL, acpi_irq, IRQF_SHARED, "acpi", + acpi_irq)) { printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); acpi_irq_handler = NULL; return AE_NOT_ACQUIRED; -- cgit v1.2.3-18-g5258 From 3a53396b0381ec9d5180fd8fe7a681c8ce95fd9a Mon Sep 17 00:00:00 2001 From: ShuoX Liu Date: Wed, 28 Mar 2012 15:19:11 -0700 Subject: cpuidle: add a sysfs entry to disable specific C state for debug purpose. Some C states of new CPU might be not good. One reason is BIOS might configure them incorrectly. To help developers root cause it quickly, the patch adds a new sysfs entry, so developers could disable specific C state manually. In addition, C state might have much impact on performance tuning, as it takes much time to enter/exit C states, which might delay interrupt processing. With the new debug option, developers could check if a deep C state could impact performance and how much impact it could cause. Also add this option in Documentation/cpuidle/sysfs.txt. [akpm@linux-foundation.org: check kstrtol return value] Signed-off-by: ShuoX Liu Reviewed-by: Yanmin Zhang Reviewed-and-Tested-by: Deepthi Dharwar Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/cpuidle/cpuidle.c | 1 + drivers/cpuidle/governors/menu.c | 5 ++++- drivers/cpuidle/sysfs.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 4869b550023..77304b6b8ae 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -245,6 +245,7 @@ static void poll_idle_init(struct cpuidle_driver *drv) state->power_usage = -1; state->flags = 0; state->enter = poll_idle; + state->disable = 0; } #else static void poll_idle_init(struct cpuidle_driver *drv) {} diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index ad0952601ae..5c17ca112fc 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -280,7 +280,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) * We want to default to C1 (hlt), not to busy polling * unless the timer is happening really really soon. */ - if (data->expected_us > 5) + if (data->expected_us > 5 && + drv->states[CPUIDLE_DRIVER_STATE_START].disable == 0) data->last_state_idx = CPUIDLE_DRIVER_STATE_START; /* @@ -290,6 +291,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { struct cpuidle_state *s = &drv->states[i]; + if (s->disable) + continue; if (s->target_residency > data->predicted_us) continue; if (s->exit_latency > latency_req) diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 3fe41fe4851..88032b4dc6d 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "cpuidle.h" @@ -222,6 +223,9 @@ struct cpuidle_state_attr { #define define_one_state_ro(_name, show) \ static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL) +#define define_one_state_rw(_name, show, store) \ +static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store) + #define define_show_state_function(_name) \ static ssize_t show_state_##_name(struct cpuidle_state *state, \ struct cpuidle_state_usage *state_usage, char *buf) \ @@ -229,6 +233,24 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \ return sprintf(buf, "%u\n", state->_name);\ } +#define define_store_state_function(_name) \ +static ssize_t store_state_##_name(struct cpuidle_state *state, \ + const char *buf, size_t size) \ +{ \ + long value; \ + int err; \ + if (!capable(CAP_SYS_ADMIN)) \ + return -EPERM; \ + err = kstrtol(buf, 0, &value); \ + if (err) \ + return err; \ + if (value) \ + state->disable = 1; \ + else \ + state->disable = 0; \ + return size; \ +} + #define define_show_state_ull_function(_name) \ static ssize_t show_state_##_name(struct cpuidle_state *state, \ struct cpuidle_state_usage *state_usage, char *buf) \ @@ -251,6 +273,8 @@ define_show_state_ull_function(usage) define_show_state_ull_function(time) define_show_state_str_function(name) define_show_state_str_function(desc) +define_show_state_function(disable) +define_store_state_function(disable) define_one_state_ro(name, show_state_name); define_one_state_ro(desc, show_state_desc); @@ -258,6 +282,7 @@ define_one_state_ro(latency, show_state_exit_latency); define_one_state_ro(power, show_state_power_usage); define_one_state_ro(usage, show_state_usage); define_one_state_ro(time, show_state_time); +define_one_state_rw(disable, show_state_disable, store_state_disable); static struct attribute *cpuidle_state_default_attrs[] = { &attr_name.attr, @@ -266,6 +291,7 @@ static struct attribute *cpuidle_state_default_attrs[] = { &attr_power.attr, &attr_usage.attr, &attr_time.attr, + &attr_disable.attr, NULL }; @@ -287,8 +313,22 @@ static ssize_t cpuidle_state_show(struct kobject * kobj, return ret; } +static ssize_t cpuidle_state_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t size) +{ + int ret = -EIO; + struct cpuidle_state *state = kobj_to_state(kobj); + struct cpuidle_state_attr *cattr = attr_to_stateattr(attr); + + if (cattr->store) + ret = cattr->store(state, buf, size); + + return ret; +} + static const struct sysfs_ops cpuidle_state_sysfs_ops = { .show = cpuidle_state_show, + .store = cpuidle_state_store, }; static void cpuidle_state_sysfs_release(struct kobject *kobj) -- cgit v1.2.3-18-g5258 From fc850f39ea54c760ce438a601cfea8ab80c4898e Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 26 Mar 2012 14:51:26 +0200 Subject: cpuidle: use the driver's state_count as default If the state_count is not initialized for the device use the driver's state count as the default. That will prevent to add it manually in the cpuidle driver initialization routine and will save us from duplicate line of code. Signed-off-by: Daniel Lezcano Signed-off-by: Len Brown --- drivers/cpuidle/cpuidle.c | 2 +- drivers/cpuidle/driver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 77304b6b8ae..f7cab5e9c4d 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -268,7 +268,7 @@ int cpuidle_enable_device(struct cpuidle_device *dev) if (!drv || !cpuidle_curr_governor) return -EIO; if (!dev->state_count) - return -EINVAL; + dev->state_count = drv->state_count; if (dev->registered == 0) { ret = __cpuidle_register_device(dev); diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 284d7af5a9c..40cd3f3024d 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -47,7 +47,7 @@ static void __cpuidle_register_driver(struct cpuidle_driver *drv) */ int cpuidle_register_driver(struct cpuidle_driver *drv) { - if (!drv) + if (!drv || !drv->state_count) return -EINVAL; if (cpuidle_disabled()) -- cgit v1.2.3-18-g5258 From 9bcb8118965ab4631a65ee0726e6518f75cda6c5 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 1 Feb 2012 10:26:54 -0500 Subject: ACPI: Evaluate thermal trip points before reading temperature An HP laptop (Pavilion G4-1016tx) has the following code in _TMP: Store (\_SB.PCI0.LPCB.EC0.RTMP, Local0) If (LGreaterEqual (Local0, S4TP)) { Store (One, HTS4) } S4TP is initialised at 0 and not programmed further until either _HOT or _CRT is called. If we evaluate _TMP before the trip points then HTS4 will always be set, causing the firmware to generate a message on boot complaining that the system shut down because of overheating. The simplest solution is just to reverse the checking of trip points and _TMP in thermal init. Signed-off-by: Matthew Garrett Signed-off-by: Len Brown --- drivers/acpi/thermal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 48fbc647b17..7dbebea1ec3 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -941,13 +941,13 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) if (!tz) return -EINVAL; - /* Get temperature [_TMP] (required) */ - result = acpi_thermal_get_temperature(tz); + /* Get trip points [_CRT, _PSV, etc.] (required) */ + result = acpi_thermal_get_trip_points(tz); if (result) return result; - /* Get trip points [_CRT, _PSV, etc.] (required) */ - result = acpi_thermal_get_trip_points(tz); + /* Get temperature [_TMP] (required) */ + result = acpi_thermal_get_temperature(tz); if (result) return result; -- cgit v1.2.3-18-g5258 From c6436f5a395d346e9f4892d7aeed4c3f99261f0f Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 13 Feb 2012 17:04:43 -0700 Subject: ACPI / PM: print physical addresses consistently with other parts of kernel Print physical address info in a style consistent with the %pR style used elsewhere in the kernel. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/nvs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 7a2035fa8c7..266bc58ce0c 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -95,8 +95,8 @@ static int suspend_nvs_register(unsigned long start, unsigned long size) { struct nvs_page *entry, *next; - pr_info("PM: Registering ACPI NVS region at %lx (%ld bytes)\n", - start, size); + pr_info("PM: Registering ACPI NVS region [mem %#010lx-%#010lx] (%ld bytes)\n", + start, start + size - 1, size); while (size > 0) { unsigned int nr_bytes; -- cgit v1.2.3-18-g5258 From 9f324bda970c599ca35f7be89d9d1bcb96d6053c Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Mon, 19 Mar 2012 13:08:02 -0600 Subject: ACPI: Add CPU hotplug support for processor device objects acpi_processor_install_hotplug_notify() registers processor objects to receive ACPI CPU hotplug event notifications. This patch additionally registers processor device objects (ACPI0007) to receive the notifications as well. Signed-off-by: Toshi Kani Reviewed-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/processor_driver.c | 48 ++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 8ae05ce1850..50be27739fe 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -68,6 +68,7 @@ #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 #define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82 +#define ACPI_PROCESSOR_DEVICE_HID "ACPI0007" #define ACPI_PROCESSOR_LIMIT_USER 0 #define ACPI_PROCESSOR_LIMIT_THERMAL 1 @@ -88,7 +89,7 @@ static int acpi_processor_start(struct acpi_processor *pr); static const struct acpi_device_id processor_device_ids[] = { {ACPI_PROCESSOR_OBJECT_HID, 0}, - {"ACPI0007", 0}, + {ACPI_PROCESSOR_DEVICE_HID, 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, processor_device_ids); @@ -741,20 +742,46 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, return; } +static acpi_status is_processor_device(acpi_handle handle) +{ + struct acpi_device_info *info; + char *hid; + acpi_status status; + + status = acpi_get_object_info(handle, &info); + if (ACPI_FAILURE(status)) + return status; + + if (info->type == ACPI_TYPE_PROCESSOR) { + kfree(info); + return AE_OK; /* found a processor object */ + } + + if (!(info->valid & ACPI_VALID_HID)) { + kfree(info); + return AE_ERROR; + } + + hid = info->hardware_id.string; + if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) { + kfree(info); + return AE_ERROR; + } + + kfree(info); + return AE_OK; /* found a processor device object */ +} + 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); + status = is_processor_device(handle); if (ACPI_FAILURE(status)) - return (AE_OK); - - if (type != ACPI_TYPE_PROCESSOR) - return (AE_OK); + return AE_OK; /* not a processor; continue to walk */ switch (*action) { case INSTALL_NOTIFY_HANDLER: @@ -772,7 +799,8 @@ processor_walk_namespace_cb(acpi_handle handle, break; } - return (AE_OK); + /* found a processor; skip walking underneath */ + return AE_CTRL_DEPTH; } static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) @@ -830,7 +858,7 @@ void acpi_processor_install_hotplug_notify(void) { #ifdef CONFIG_ACPI_HOTPLUG_CPU int action = INSTALL_NOTIFY_HANDLER; - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, + acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, processor_walk_namespace_cb, NULL, &action, NULL); @@ -843,7 +871,7 @@ void acpi_processor_uninstall_hotplug_notify(void) { #ifdef CONFIG_ACPI_HOTPLUG_CPU int action = UNINSTALL_NOTIFY_HANDLER; - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, + acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, processor_walk_namespace_cb, NULL, &action, NULL); -- cgit v1.2.3-18-g5258 From 1a022e3f1be11730bd8747b1af96a0274bf6356e Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Tue, 13 Mar 2012 19:55:09 +0100 Subject: idle, x86: Allow off-lined CPU to enter deeper C states Currently when a CPU is off-lined it enters either MWAIT-based idle or, if MWAIT is not desired or supported, HLT-based idle (which places the processor in C1 state). This patch allows processors without MWAIT support to stay in states deeper than C1. Signed-off-by: Boris Ostrovsky Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 31 +++++++++++++++++++++++++++++++ drivers/cpuidle/cpuidle.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0e8e2de2ed3..6b1d32a161a 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -770,6 +770,35 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, return index; } + +/** + * acpi_idle_play_dead - enters an ACPI state for long-term idle (i.e. off-lining) + * @dev: the target CPU + * @index: the index of suggested state + */ +static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) +{ + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); + + ACPI_FLUSH_CPU_CACHE(); + + while (1) { + + if (cx->entry_method == ACPI_CSTATE_HALT) + halt(); + else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) { + inb(cx->address); + /* See comment in acpi_idle_do_entry() */ + inl(acpi_gbl_FADT.xpm_timer_block.address); + } else + return -ENODEV; + } + + /* Never reached */ + return 0; +} + /** * acpi_idle_enter_simple - enters an ACPI state without BM handling * @dev: the target CPU @@ -1077,12 +1106,14 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_c1; + state->enter_dead = acpi_idle_play_dead; drv->safe_state_index = count; break; case ACPI_STATE_C2: state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_simple; + state->enter_dead = acpi_idle_play_dead; drv->safe_state_index = count; break; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index f7cab5e9c4d..3e146b2ada4 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -71,6 +71,34 @@ typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev, static cpuidle_enter_t cpuidle_enter_ops; +/** + * cpuidle_play_dead - cpu off-lining + * + * Only returns in case of an error + */ +int cpuidle_play_dead(void) +{ + struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); + struct cpuidle_driver *drv = cpuidle_get_driver(); + int i, dead_state = -1; + int power_usage = -1; + + /* Find lowest-power state that supports long-term idle */ + for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { + struct cpuidle_state *s = &drv->states[i]; + + if (s->power_usage < power_usage && s->enter_dead) { + power_usage = s->power_usage; + dead_state = i; + } + } + + if (dead_state != -1) + return drv->states[dead_state].enter_dead(dev, dead_state); + + return -ENODEV; +} + /** * cpuidle_idle_call - the main idle loop * -- cgit v1.2.3-18-g5258 From 02401c06b7f6bec65f314e3cec7894502c973501 Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Tue, 13 Mar 2012 19:55:10 +0100 Subject: cpuidle: power_usage should be declared signed integer power_usage is always assigned a negative value and should be declared a signed integer Signed-off-by: Boris Ostrovsky Signed-off-by: Len Brown --- drivers/cpuidle/governors/menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 5c17ca112fc..06335756ea1 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -236,7 +236,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); - unsigned int power_usage = -1; + int power_usage = -1; int i; int multiplier; struct timespec t; -- cgit v1.2.3-18-g5258 From c80f5b31f3c55a197f5323b93d1e3553429a427e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 15 Mar 2012 09:32:05 +0100 Subject: ACPI: processor_driver: add missing kfree The function acpi_processor_add is stored in the ops.add field of a acpi_driver structure. This function is then called in acpi_bus_driver_init. On failure, this function clears the field device->driver_data, but does not free its contents. Thus the free has to be done by the add function. In acpi_processor_add, the corresponding value is pr. This value is currently freed on failure before storing it in device->driver_data, but not after. This free is added in the error handling code at the end of the function. The per_cpu variable processors is also cleared so that it does not refer to a dangling pointer. Signed-off-by: Julia Lawall Reviewed-by: Srivatsa S. Bhat Acked-by: Deepthi Dharwar Signed-off-by: Len Brown --- drivers/acpi/processor_driver.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 8ae05ce1850..fce0066aa4a 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -535,8 +535,8 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) return -ENOMEM; if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { - kfree(pr); - return -ENOMEM; + result = -ENOMEM; + goto err_free_pr; } pr->handle = device->handle; @@ -576,7 +576,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) dev = get_cpu_device(pr->id); if (sysfs_create_link(&device->dev.kobj, &dev->kobj, "sysdev")) { result = -EFAULT; - goto err_free_cpumask; + goto err_clear_processor; } /* @@ -594,9 +594,15 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) err_remove_sysfs: sysfs_remove_link(&device->dev.kobj, "sysdev"); +err_clear_processor: + /* + * processor_device_array is not cleared to allow checks for buggy BIOS + */ + per_cpu(processors, pr->id) = NULL; err_free_cpumask: free_cpumask_var(pr->throttling.shared_cpu_map); - +err_free_pr: + kfree(pr); return result; } -- cgit v1.2.3-18-g5258 From 89e96ada572fb216e582dbe3f64e1a6939a37f74 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sat, 3 Mar 2012 13:29:20 -0800 Subject: PNPACPI: Fix device ref leaking in acpi_pnp_match During testing pci root bus removal, found some root bus bridge is not freed. If booting with pnpacpi=off, those hostbridge could be freed without problem. It turns out that some devices reference are not released during acpi_pnp_match. that match should not hold one device ref during every calling. Add pu_device calling before returning. Signed-off-by: Yinghai Lu Cc: stable@vger.kernel.org Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index b00c17612a8..d21e8f59c84 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -321,9 +321,14 @@ static int __init acpi_pnp_match(struct device *dev, void *_pnp) { struct acpi_device *acpi = to_acpi_device(dev); struct pnp_dev *pnp = _pnp; + struct device *physical_device; + + physical_device = acpi_get_physical_device(acpi->handle); + if (physical_device) + put_device(physical_device); /* true means it matched */ - return !acpi_get_physical_device(acpi->handle) + return !physical_device && compare_pnp_id(pnp->id, acpi_device_hid(acpi)); } -- cgit v1.2.3-18-g5258 From e252675fb722d4a307cc380a06a905f03cf9951c Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 24 Feb 2012 11:41:53 +0000 Subject: ACPI: consistently use should_use_kmap() ... so that acpi_unmap()'s behavior gets in sync with acpi_map()'s. Signed-off-by: Jan Beulich Signed-off-by: Len Brown --- drivers/acpi/osl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 412a1e04a92..5aef087d42d 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -347,7 +347,7 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr) unsigned long pfn; pfn = pg_off >> PAGE_SHIFT; - if (page_is_ram(pfn)) + if (should_use_kmap(pfn)) kunmap(pfn_to_page(pfn)); else iounmap(vaddr); -- cgit v1.2.3-18-g5258 From 9505626d7bfeb5bd4b85acb483831ac640b2a5e8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 28 Feb 2012 13:27:44 -0800 Subject: ACPI: Fix unprotected smp_processor_id() in acpi_processor_cst_has_changed() The acpi_processor_cst_has_changed() function is invoked from a CPU_ONLINE or CPU_DEAD function, which might well execute on CPU 0 even though the CPU being hotplugged is some other CPU. In addition, acpi_processor_cst_has_changed() invokes smp_processor_id() without protection, resulting in splats when onlining CPUs. This commit therefore changes the smp_processor_id() to pr->id, as is used elsewhere in the code, for example, in acpi_processor_add(). Signed-off-by: Paul E. McKenney