* Re: [PATCH v4 1/5] thermal: Add generic cpufreq cooling implementation
From: Rob Lee @ 2012-06-26 3:12 UTC (permalink / raw)
To: Amit Daniel Kachhap
Cc: linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
durgadoss.r-ral2JQCrhuEAvxtiuMwx3w,
patches-QSEj5FYQhm4dnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
rui.zhang-ral2JQCrhuEAvxtiuMwx3w, khali-PUYAD+kWke1g9hUCZPvPmw,
linaro-dev-cunTk1MwBs8s++Sfvej+rw,
linux-pm-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
lenb-DgEjT+Ai2ygdnm+yROfE0A,
akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
guenter.roeck-IzeFyvvaP7pWk0Htik3J/w
In-Reply-To: <1336815645-29625-2-git-send-email-amit.kachhap-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Hey Amit,
I was just re-organizing the imx thermal driver that uses this cpu
cooling interface and noticed a couple of small issues here. If
these suggestions are agreed upon and if it's too late for these
issues be changed with this patchset, I can submit them separately
unless you'd prefer to.
On Sat, May 12, 2012 at 4:40 AM, Amit Daniel Kachhap
<amit.kachhap-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> This patch adds support for generic cpu thermal cooling low level
> implementations using frequency scaling up/down based on the registration
> parameters. Different cpu related cooling devices can be registered by the
> user and the binding of these cooling devices to the corresponding
> trip points can be easily done as the registration APIs return the
> cooling device pointer. The user of these APIs are responsible for
> passing clipping frequency . The drivers can also register to recieve
> notification about any cooling action called.
>
> Signed-off-by: Amit Daniel Kachhap <amit.kachhap-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> Documentation/thermal/cpu-cooling-api.txt | 60 ++++
> drivers/thermal/Kconfig | 11 +
> drivers/thermal/Makefile | 3 +-
> drivers/thermal/cpu_cooling.c | 483 +++++++++++++++++++++++++++++
> include/linux/cpu_cooling.h | 99 ++++++
> 5 files changed, 655 insertions(+), 1 deletions(-)
> create mode 100644 Documentation/thermal/cpu-cooling-api.txt
> create mode 100644 drivers/thermal/cpu_cooling.c
> create mode 100644 include/linux/cpu_cooling.h
>
> diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
> new file mode 100644
> index 0000000..557adb8
> --- /dev/null
> +++ b/Documentation/thermal/cpu-cooling-api.txt
> @@ -0,0 +1,60 @@
> +CPU cooling APIs How To
> +===================================
> +
> +Written by Amit Daniel Kachhap <amit.kachhap-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> +
> +Updated: 12 May 2012
> +
> +Copyright (c) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
> +
> +0. Introduction
> +
> +The generic cpu cooling(freq clipping, cpuhotplug etc) provides
> +registration/unregistration APIs to the caller. The binding of the cooling
> +devices to the trip point is left for the user. The registration APIs returns
> +the cooling device pointer.
> +
> +1. cpu cooling APIs
> +
> +1.1 cpufreq registration/unregistration APIs
> +1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
> + struct freq_clip_table *tab_ptr, unsigned int tab_size)
> +
> + This interface function registers the cpufreq cooling device with the name
> + "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
> + cooling devices.
> +
> + tab_ptr: The table containing the maximum value of frequency to be clipped
> + for each cooling state.
> + .freq_clip_max: Value of frequency to be clipped for each allowed
> + cpus.
> + .temp_level: Temperature level at which the frequency clamping will
> + happen.
> + .mask_val: cpumask of the allowed cpu's
> + tab_size: the total number of cpufreq cooling states.
> +
> +1.1.2 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
> +
> + This interface function unregisters the "thermal-cpufreq-%x" cooling device.
> +
> + cdev: Cooling device pointer which has to be unregistered.
> +
> +
> +1.2 CPU cooling action notifier register/unregister interface
> +1.2.1 int cputherm_register_notifier(struct notifier_block *nb,
> + unsigned int list)
> +
> + This interface registers a driver with cpu cooling layer. The driver will
> + be notified when any cpu cooling action is called.
> +
> + nb: notifier function to register
> + list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
> +
> +1.2.2 int cputherm_unregister_notifier(struct notifier_block *nb,
> + unsigned int list)
> +
> + This interface registers a driver with cpu cooling layer. The driver will
> + be notified when any cpu cooling action is called.
> +
> + nb: notifier function to register
> + list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 514a691..d9c529f 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -19,6 +19,17 @@ config THERMAL_HWMON
> depends on HWMON=y || HWMON=THERMAL
> default y
>
> +config CPU_THERMAL
Perhaps the name CPU_COOLING or CPUFREQ_COOLING would more accurately
describe this functionality? I like the latter since now this
mechanism only supports cooling by using cpufreq.
> + bool "generic cpu cooling support"
If we use CPUFREQ_COOLING, then perhaps this could say:
bool "cpu cooling through cpufreq frequency limiting"
> + depends on THERMAL && CPU_FREQ
> + help
> + This implements the generic cpu cooling mechanism through frequency
> + reduction, cpu hotplug and any other ways of reducing temperature. An
> + ACPI version of this already exists(drivers/acpi/processor_thermal.c).
> + This will be useful for platforms using the generic thermal interface
> + and not the ACPI interface.
> + If you want this support, you should say Y or M here.
> +
Currently, only the "frequency reduction" method exists so perhaps
it's best to remove mention of "cpu hotplug and any other ways of
reducing temperature"? Here'as a version for cpufreq only:
config CPUFREQ_COOLING
bool "cpu cooling through cpufreq frequency limiting"
depends on THERMAL && CPU_FREQ
help
This implements a generic cpu cooling mechanism through cpufreq
frequency limiting. An ACPI version of this already exists
(drivers/acpi/processor_thermal.c). This will be useful for
platforms using the generic thermal interface and not the ACPI
interface.
If you want this support, you should say Y or M here.
> config SPEAR_THERMAL
> bool "SPEAr thermal sensor driver"
> depends on THERMAL
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index a9fff0b..30c456c 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -3,4 +3,5 @@
> #
>
> obj-$(CONFIG_THERMAL) += thermal_sys.o
> -obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
> \ No newline at end of file
> +obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
> +obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
> diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
> new file mode 100644
> index 0000000..c40d9a0
> --- /dev/null
> +++ b/drivers/thermal/cpu_cooling.c
> @@ -0,0 +1,483 @@
> +/*
> + * linux/drivers/thermal/cpu_cooling.c
> + *
> + * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
> + * Copyright (C) 2012 Amit Daniel <amit.kachhap-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + */
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/thermal.h>
> +#include <linux/platform_device.h>
> +#include <linux/cpufreq.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/cpu.h>
> +#include <linux/cpu_cooling.h>
> +
> +/**
> + * struct cpufreq_cooling_device
> + * @id: unique integer value corresponding to each cpufreq_cooling_device
> + * registered.
> + * @cool_dev: thermal_cooling_device pointer to keep track of the the
> + * egistered cooling device.
> + * @tab_ptr: freq_clip_table table containing the maximum value of frequency to
> + * be set for different cooling state.
> + * @tab_size: integer value representing a count of the above table.
> + * @cpufreq_state: integer value representing the current state of cpufreq
> + * cooling devices.
> + * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.
> + * @node: list_head to link all cpufreq_cooling_device together.
> + *
> + * This structure is required for keeping information of each
> + * cpufreq_cooling_device registered as a list whose head is represented by
> + * cooling_cpufreq_list. In order to prevent corruption of this list a
> + * mutex lock cooling_cpufreq_lock is used.
> + */
> +struct cpufreq_cooling_device {
> + int id;
> + struct thermal_cooling_device *cool_dev;
> + struct freq_clip_table *tab_ptr;
> + unsigned int tab_size;
> + unsigned int cpufreq_state;
> + struct cpumask allowed_cpus;
> + struct list_head node;
> +};
> +static LIST_HEAD(cooling_cpufreq_list);
> +static DEFINE_MUTEX(cooling_cpufreq_lock);
> +static DEFINE_IDR(cpufreq_idr);
> +
> +/*per cpu variable to store the previous max frequency allowed*/
> +static DEFINE_PER_CPU(unsigned int, max_policy_freq);
> +
> +/*notify_table passes value to the CPUFREQ_ADJUST callback function.*/
> +#define NOTIFY_INVALID NULL
> +static struct freq_clip_table *notify_table;
> +
> +/*Head of the blocking notifier chain to inform about frequency clamping*/
> +static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
> +
> +/**
> + * get_idr - function to get a unique id.
> + * @idr: struct idr * handle used to create a id.
> + * @id: int * value generated by this function.
> + */
> +static int get_idr(struct idr *idr, int *id)
> +{
> + int err;
> +again:
> + if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
> + return -ENOMEM;
> +
> + mutex_lock(&cooling_cpufreq_lock);
> + err = idr_get_new(idr, NULL, id);
> + mutex_unlock(&cooling_cpufreq_lock);
> +
> + if (unlikely(err == -EAGAIN))
> + goto again;
> + else if (unlikely(err))
> + return err;
> +
> + *id = *id & MAX_ID_MASK;
> + return 0;
> +}
> +
> +/**
> + * release_idr - function to free the unique id.
> + * @idr: struct idr * handle used for creating the id.
> + * @id: int value representing the unique id.
> + */
> +static void release_idr(struct idr *idr, int id)
> +{
> + mutex_lock(&cooling_cpufreq_lock);
> + idr_remove(idr, id);
> + mutex_unlock(&cooling_cpufreq_lock);
> +}
> +
> +/**
> + * cputherm_register_notifier - Register a notifier with cpu cooling interface.
> + * @nb: struct notifier_block * with callback info.
> + * @list: integer value for which notification is needed. possible values are
> + * CPUFREQ_COOLING_START and CPUFREQ_COOLING_STOP.
> + *
> + * This exported function registers a driver with cpu cooling layer. The driver
> + * will be notified when any cpu cooling action is called.
> + */
> +int cputherm_register_notifier(struct notifier_block *nb, unsigned int list)
> +{
> + int ret = 0;
> +
> + switch (list) {
> + case CPUFREQ_COOLING_START:
> + case CPUFREQ_COOLING_STOP:
> + ret = blocking_notifier_chain_register(
> + &cputherm_state_notifier_list, nb);
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + return ret;
> +}
> +EXPORT_SYMBOL(cputherm_register_notifier);
> +
> +/**
> + * cputherm_unregister_notifier - Un-register a notifier.
> + * @nb: struct notifier_block * with callback info.
> + * @list: integer value for which notification is needed. values possible are
> + * CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP.
> + *
> + * This exported function un-registers a driver with cpu cooling layer.
> + */
> +int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list)
> +{
> + int ret = 0;
> +
> + switch (list) {
> + case CPUFREQ_COOLING_START:
> + case CPUFREQ_COOLING_STOP:
> + ret = blocking_notifier_chain_unregister(
> + &cputherm_state_notifier_list, nb);
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + return ret;
> +}
> +EXPORT_SYMBOL(cputherm_unregister_notifier);
> +
> +/*Below codes defines functions to be used for cpufreq as cooling device*/
> +
> +/**
> + * is_cpufreq_valid - function to check if a cpu has frequency transition policy.
> + * @cpu: cpu for which check is needed.
> + */
> +static int is_cpufreq_valid(int cpu)
> +{
> + struct cpufreq_policy policy;
> + return !cpufreq_get_policy(&policy, cpu);
> +}
> +
> +/**
> + * cpufreq_apply_cooling - function to apply frequency clipping.
> + * @cpufreq_device: cpufreq_cooling_device pointer containing frequency
> + * clipping data.
> + * @cooling_state: value of the cooling state.
> + */
> +static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
> + unsigned long cooling_state)
> +{
> + unsigned int event, cpuid, state;
> + struct freq_clip_table *th_table, *table_ptr;
> + const struct cpumask *maskPtr = &cpufreq_device->allowed_cpus;
> + struct cpufreq_cooling_device *cpufreq_ptr;
> +
> + if (cooling_state > cpufreq_device->tab_size)
> + return -EINVAL;
> +
> + /*Check if the old cooling action is same as new cooling action*/
> + if (cpufreq_device->cpufreq_state == cooling_state)
> + return 0;
> +
> + /*pass cooling table info to the cpufreq_thermal_notifier callback*/
> + notify_table = NOTIFY_INVALID;
> +
> + if (cooling_state > 0) {
> + th_table = &(cpufreq_device->tab_ptr[cooling_state - 1]);
> + notify_table = th_table;
> + }
> +
> + /*check if any lower clip frequency active in other cpufreq_device's*/
> + list_for_each_entry(cpufreq_ptr, &cooling_cpufreq_list, node) {
> +
> + state = cpufreq_ptr->cpufreq_state;
> + if (state == 0 || cpufreq_ptr == cpufreq_device)
> + continue;
> +
> + if (!cpumask_equal(&cpufreq_ptr->allowed_cpus,
> + &cpufreq_device->allowed_cpus))
> + continue;
> +
> + table_ptr = &(cpufreq_ptr->tab_ptr[state - 1]);
> + if (notify_table == NULL ||
> + (table_ptr->freq_clip_max <
> + notify_table->freq_clip_max))
> + notify_table = table_ptr;
> + }
> +
> + cpufreq_device->cpufreq_state = cooling_state;
> +
> + if (notify_table != NOTIFY_INVALID) {
> + event = CPUFREQ_COOLING_START;
> + maskPtr = notify_table->mask_val;
> + } else {
> + event = CPUFREQ_COOLING_STOP;
> + }
> +
> + blocking_notifier_call_chain(&cputherm_state_notifier_list,
> + event, notify_table);
> +
> + for_each_cpu(cpuid, maskPtr) {
> + if (is_cpufreq_valid(cpuid))
> + cpufreq_update_policy(cpuid);
> + }
> +
> + notify_table = NOTIFY_INVALID;
> +
> + return 0;
> +}
> +
> +/**
> + * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
> + * @nb: struct notifier_block * with callback info.
> + * @event: value showing cpufreq event for which this function invoked.
> + * @data: callback-specific data
> + */
> +static int cpufreq_thermal_notifier(struct notifier_block *nb,
> + unsigned long event, void *data)
> +{
> + struct cpufreq_policy *policy = data;
> + unsigned long max_freq = 0;
> +
> + if (event != CPUFREQ_ADJUST)
> + return 0;
> +
> + if (notify_table != NOTIFY_INVALID) {
> + max_freq = notify_table->freq_clip_max;
> +
> + if (!per_cpu(max_policy_freq, policy->cpu))
> + per_cpu(max_policy_freq, policy->cpu) = policy->max;
> + } else {
> + if (per_cpu(max_policy_freq, policy->cpu)) {
> + max_freq = per_cpu(max_policy_freq, policy->cpu);
> + per_cpu(max_policy_freq, policy->cpu) = 0;
> + } else {
> + max_freq = policy->max;
> + }
> + }
> +
> + /* Never exceed user_policy.max*/
> + if (max_freq > policy->user_policy.max)
> + max_freq = policy->user_policy.max;
> +
> + if (policy->max != max_freq)
> + cpufreq_verify_within_limits(policy, 0, max_freq);
> +
> + return 0;
> +}
> +
> +/*
> + * cpufreq cooling device callback functions are defined below
> + */
> +
> +/**
> + * cpufreq_get_max_state - callback function to get the max cooling state.
> + * @cdev: thermal cooling device pointer.
> + * @state: fill this variable with the max cooling state.
> + */
> +static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + int ret = -EINVAL;
> + struct cpufreq_cooling_device *cpufreq_device;
> +
> + mutex_lock(&cooling_cpufreq_lock);
> + list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
> + if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
> + *state = cpufreq_device->tab_size;
> + ret = 0;
> + break;
> + }
> + }
> + mutex_unlock(&cooling_cpufreq_lock);
> + return ret;
> +}
> +
> +/**
> + * cpufreq_get_cur_state - callback function to get the current cooling state.
> + * @cdev: thermal cooling device pointer.
> + * @state: fill this variable with the current cooling state.
> + */
> +static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + int ret = -EINVAL;
> + struct cpufreq_cooling_device *cpufreq_device;
> +
> + mutex_lock(&cooling_cpufreq_lock);
> + list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
> + if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
> + *state = cpufreq_device->cpufreq_state;
> + ret = 0;
> + break;
> + }
> + }
> + mutex_unlock(&cooling_cpufreq_lock);
> + return ret;
> +}
> +
> +/**
> + * cpufreq_set_cur_state - callback function to set the current cooling state.
> + * @cdev: thermal cooling device pointer.
> + * @state: set this variable to the current cooling state.
> + */
> +static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> +{
> + int ret = -EINVAL;
> + struct cpufreq_cooling_device *cpufreq_device;
> +
> + mutex_lock(&cooling_cpufreq_lock);
> + list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
> + if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
> + ret = 0;
> + break;
> + }
> + }
> + if (!ret)
> + ret = cpufreq_apply_cooling(cpufreq_device, state);
> +
> + mutex_unlock(&cooling_cpufreq_lock);
> +
> + return ret;
> +}
> +
> +/*Bind cpufreq callbacks to thermal cooling device ops*/
> +static struct thermal_cooling_device_ops const cpufreq_cooling_ops = {
> + .get_max_state = cpufreq_get_max_state,
> + .get_cur_state = cpufreq_get_cur_state,
> + .set_cur_state = cpufreq_set_cur_state,
> +};
> +
> +/*Notifier for cpufreq policy change*/
> +static struct notifier_block thermal_cpufreq_notifier_block = {
> + .notifier_call = cpufreq_thermal_notifier,
> +};
> +
> +/**
> + * cpufreq_cooling_register - function to create cpufreq cooling device.
> + * @tab_ptr: table ptr containing the maximum value of frequency to be clipped
> + * for each cooling state.
> + * @tab_size: count of entries in the above table.
> + * happen.
> + */
> +struct thermal_cooling_device *cpufreq_cooling_register(
> + struct freq_clip_table *tab_ptr, unsigned int tab_size)
> +{
> + struct thermal_cooling_device *cool_dev;
> + struct cpufreq_cooling_device *cpufreq_dev = NULL;
> + struct freq_clip_table *clip_tab;
> + unsigned int cpufreq_dev_count = 0;
> + char dev_name[THERMAL_NAME_LENGTH];
> + int ret = 0, id = 0, i;
> +
> + if (tab_ptr == NULL || tab_size == 0)
> + return ERR_PTR(-EINVAL);
> +
> + list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
> + cpufreq_dev_count++;
> +
> + cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device),
> + GFP_KERNEL);
> + if (!cpufreq_dev)
> + return ERR_PTR(-ENOMEM);
> +
> + /*Verify that all the entries of freq_clip_table are present*/
> + for (i = 0; i < tab_size; i++) {
> + clip_tab = ((struct freq_clip_table *)&tab_ptr[i]);
> + if (!clip_tab->freq_clip_max || !clip_tab->mask_val
> + || !clip_tab->temp_level) {
> + kfree(cpufreq_dev);
> + return ERR_PTR(-EINVAL);
> + }
> + /*
> + *Consolidate all the cpumask for all the individual entries
> + *of the trip table. This is useful in resetting all the
> + *clipped frequencies to the normal level for each cpufreq
> + *cooling device.
> + */
> + cpumask_or(&cpufreq_dev->allowed_cpus,
> + &cpufreq_dev->allowed_cpus, clip_tab->mask_val);
> + }
> +
> + cpufreq_dev->tab_ptr = tab_ptr;
> + cpufreq_dev->tab_size = tab_size;
> +
> + ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
> + if (ret) {
> + kfree(cpufreq_dev);
> + return ERR_PTR(-EINVAL);
> + }
> +
> + sprintf(dev_name, "thermal-cpufreq-%d", cpufreq_dev->id);
> +
> + cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev,
> + &cpufreq_cooling_ops);
> + if (!cool_dev) {
> + release_idr(&cpufreq_idr, cpufreq_dev->id);
> + kfree(cpufreq_dev);
> + return ERR_PTR(-EINVAL);
> + }
> + cpufreq_dev->id = id;
> + cpufreq_dev->cool_dev = cool_dev;
> + mutex_lock(&cooling_cpufreq_lock);
> + list_add_tail(&cpufreq_dev->node, &cooling_cpufreq_list);
> +
> + /*Register the notifier for first cpufreq cooling device*/
> + if (cpufreq_dev_count == 0)
> + cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
> + CPUFREQ_POLICY_NOTIFIER);
> +
> + mutex_unlock(&cooling_cpufreq_lock);
> + return cool_dev;
> +}
> +EXPORT_SYMBOL(cpufreq_cooling_register);
> +
> +/**
> + * cpufreq_cooling_unregister - function to remove cpufreq cooling device.
> + * @cdev: thermal cooling device pointer.
> + */
> +void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
> +{
> + struct cpufreq_cooling_device *cpufreq_dev = NULL;
> + unsigned int cpufreq_dev_count = 0;
> +
> + mutex_lock(&cooling_cpufreq_lock);
> + list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node) {
> + if (cpufreq_dev && cpufreq_dev->cool_dev == cdev)
> + break;
> + cpufreq_dev_count++;
> + }
> +
> + if (!cpufreq_dev || cpufreq_dev->cool_dev != cdev) {
> + mutex_unlock(&cooling_cpufreq_lock);
> + return;
> + }
> +
> + list_del(&cpufreq_dev->node);
> +
> + /*Unregister the notifier for the last cpufreq cooling device*/
> + if (cpufreq_dev_count == 1) {
> + cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
> + CPUFREQ_POLICY_NOTIFIER);
> + }
> + mutex_unlock(&cooling_cpufreq_lock);
> + thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
> + release_idr(&cpufreq_idr, cpufreq_dev->id);
> + kfree(cpufreq_dev);
> +}
> +EXPORT_SYMBOL(cpufreq_cooling_unregister);
> diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
> new file mode 100644
> index 0000000..ed6c096
> --- /dev/null
> +++ b/include/linux/cpu_cooling.h
> @@ -0,0 +1,99 @@
> +/*
> + * linux/include/linux/cpu_cooling.h
> + *
> + * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
> + * Copyright (C) 2012 Amit Daniel <amit.kachhap-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + */
> +
> +#ifndef __CPU_COOLING_H__
> +#define __CPU_COOLING_H__
> +
> +#include <linux/thermal.h>
> +
> +#define CPUFREQ_COOLING_START 0
> +#define CPUFREQ_COOLING_STOP 1
> +
> +/**
> + * struct freq_clip_table
> + * @freq_clip_max: maximum frequency allowed for this cooling state.
> + * @temp_level: Temperature level at which the temperature clipping will
> + * happen.
> + * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
> + *
> + * This structure is required to be filled and passed to the
> + * cpufreq_cooling_unregister function.
> + */
> +struct freq_clip_table {
> + unsigned int freq_clip_max;
> + unsigned int temp_level;
> + const struct cpumask *mask_val;
> +};
> +
> +/**
> + * cputherm_register_notifier - Register a notifier with cpu cooling interface.
> + * @nb: struct notifier_block * with callback info.
> + * @list: integer value for which notification is needed. possible values are
> + * CPUFREQ_COOLING_TYPE and CPUHOTPLUG_COOLING_TYPE.
CPUFREQ_COOLING_TYPE and CPUHOTPLUG_COOLING_TYPE should be changed to
CPUFREQ_COOLING_START CPUFREQ_COOLING_STOP, right?
> + *
> + * This exported function registers a driver with cpu cooling layer. The driver
> + * will be notified when any cpu cooling action is called.
> + */
> +int cputherm_register_notifier(struct notifier_block *nb, unsigned int list);
> +
> +/**
> + * cputherm_unregister_notifier - Un-register a notifier.
> + * @nb: struct notifier_block * with callback info.
> + * @list: integer value for which notification is needed. values possible are
> + * CPUFREQ_COOLING_TYPE.
Should be changed to CPUFREQ_COOLING_START, CPUFREQ_COOLING_STOP, right?
> + *
> + * This exported function un-registers a driver with cpu cooling layer.
> + */
> +int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list);
> +
> +#ifdef CONFIG_CPU_FREQ
Consider changing this to "#ifdef CPU_THERMAL" A platform thermal
driver may want to always call this function as its cpu cooling
mechanism but it should still function without the cpu_cooling being
enabled. In this case, the platform thermal driver would only provide
temperature readings and critical trip point handling. But if the
platform happened may have CONFIG_CPU_FREQ enabled, a build error
would occur in the current implementation.
(the CONFIG_CPU_FREQ requirement will be met by CPU_THERMAL being
enabled since it also implies CONFIG_CPU_FREQ being enabled per the
Kconfig dependency)
> +/**
> + * cpufreq_cooling_register - function to create cpufreq cooling device.
> + * @tab_ptr: table ptr containing the maximum value of frequency to be clipped
> + * for each cooling state.
> + * @tab_size: count of entries in the above table.
> + * @mask_val: cpumask containing the allowed cpu's where frequency clipping can
> + * happen.
> + */
> +struct thermal_cooling_device *cpufreq_cooling_register(
> + struct freq_clip_table *tab_ptr, unsigned int tab_size);
> +
> +/**
> + * cpufreq_cooling_unregister - function to remove cpufreq cooling device.
> + * @cdev: thermal cooling device pointer.
> + */
> +void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
> +#else /*!CONFIG_CPU_FREQ*/
Modify comment if above suggestion is taken.
> +static inline struct thermal_cooling_device *cpufreq_cooling_register(
> + struct freq_clip_table *tab_ptr, unsigned int tab_size);
> +{
> + return NULL;
> +}
> +static inline void cpufreq_cooling_unregister(
> + struct thermal_cooling_device *cdev)
> +{
> + return;
> +}
> +#endif /*CONFIG_CPU_FREQ*/
Modify comment if above suggestion is taken.
> +
> +#endif /* __CPU_COOLING_H__ */
> --
> 1.7.1
>
>
> _______________________________________________
> linaro-dev mailing list
> linaro-dev-cunTk1MwBs8s++Sfvej+rw@public.gmane.org
> http://lists.linaro.org/mailman/listinfo/linaro-dev
^ permalink raw reply
* Re: linux-next : cpuidle - could you add my tree please
From: Stephen Rothwell @ 2012-06-25 22:53 UTC (permalink / raw)
To: Daniel Lezcano
Cc: linux-acpi, linux-pm, Lists Linaro-dev, Linux Kernel Mailing List,
Kevin Hilman, Peter De Schrijver, Amit Kucheria, linux-next,
Colin Cross, Andrew Morton, Linus Torvalds, Rob Lee
In-Reply-To: <4FE86727.5010400@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 1939 bytes --]
Hi Daniel,
On Mon, 25 Jun 2012 15:27:03 +0200 Daniel Lezcano <daniel.lezcano@linaro.org> wrote:
>
> we discussed last week to put in place a tree grouping the cpuidle
> modifications [1]. Is it possible to add the tree ?
>
> git://git.linaro.org/people/dlezcano/cpuidle-next.git #cpuidle-next
>
> It contains for the moment Colin Cross's cpuidle coupled states.
Added from today.
Thanks for adding your subsystem tree as a participant of linux-next. As
you may know, this is not a judgment of your code. The purpose of
linux-next is for integration testing and to lower the impact of
conflicts between subsystems in the next merge window.
You will need to ensure that the patches/commits in your tree/series have
been:
* submitted under GPL v2 (or later) and include the Contributor's
Signed-off-by,
* posted to the relevant mailing list,
* reviewed by you (or another maintainer of your subsystem tree),
* successfully unit tested, and
* destined for the current or next Linux merge window.
Basically, this should be just what you would send to Linus (or ask him
to fetch). It is allowed to be rebased if you deem it necessary.
--
Cheers,
Stephen Rothwell
sfr@canb.auug.org.au
Legal Stuff:
By participating in linux-next, your subsystem tree contributions are
public and will be included in the linux-next trees. You may be sent
e-mail messages indicating errors or other issues when the
patches/commits from your subsystem tree are merged and tested in
linux-next. These messages may also be cross-posted to the linux-next
mailing list, the linux-kernel mailing list, etc. The linux-next tree
project and IBM (my employer) make no warranties regarding the linux-next
project, the testing procedures, the results, the e-mails, etc. If you
don't agree to these ground rules, let me know and I'll remove your tree
from participation in linux-next.
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] acpi, cpuidle: Register with cpuidle even if cpu is onlined after boot (beyond maxcpus)
From: Srivatsa S. Bhat @ 2012-06-25 16:03 UTC (permalink / raw)
To: Thomas Renninger
Cc: x86, Linux PM mailing list, linux-kernel, linux-acpi, linux-pm
In-Reply-To: <201206251553.55867.trenn@suse.de>
On 06/25/2012 07:23 PM, Thomas Renninger wrote:
> On Monday, June 25, 2012 01:25:43 PM Srivatsa S. Bhat wrote:
>>
>> Daniel Lezcano noticed that after booting with maxcpus=X, if we online the
>> remaining cpus by writing: echo 1 > /sys/devices/system/cpu/cpuY/online, then
>> for the newly onlined cpus, the cpuidle directory is not found under
>> /sys/devices/system/cpu/cpuY.
>>
>> Partly, the reason for this is that acpi restricts the initialization to cpus
>> within the maxcpus limit. (See commit 75cbfb9 "ACPI: Do not try to set up acpi
>> processor stuff on cores exceeding maxcpus="). The maxcpus= kernel parameter is
>> used to restrict the number of cpus brought up during boot. That doesn't mean
>> that we should hard restrict the bring up of the remaining cpus later on.
>
> Sorry, but IMO it exaclty does mean that (adding more general lists for
> further comments).
>
> If you can online more cores than maxcpus= via sysfs, this sounds like a bug.
> Not the other way around.
>
> Compare with Documentation/kernel-parameters.txt:
> maxcpus= [SMP] Maximum number of processors that an SMP kernel
> should make use of. maxcpus=n : n >= 0 limits the
> kernel to using 'n' processors. n=0 is a special case,
> it is equivalent to "nosmp", which also disables
> the IO APIC.
>
> Chances that you run into more problems are high.
Right, I agree on that. So, IMHO, maxcpus=X doesn't mean that the kernel must and
should forbid any new cpus from coming online, but in the interest of avoiding
problems/complications in some obscure paths, I guess it makes sense to avoid
onlining new cpus beyond maxcpus.
In any case, I was just trying to see why the simple removal of the setup_max_cpus
check in acpi_processor_add() wasn't enough to expose the cpuidle directories under
the new cpus.. and while debugging that, I came up with this patch. I don't mind
if this doesn't get picked up.
> It would help if it is explained why at all this would be needed.
>
Right, the usecase of why somebody would like to online new cpus beyond maxcpus
doesn't look all that solid anyway. So I am OK with leaving the code as it is now.
> If there really is a valid use-case, possibly a bootcpus= param could get
> defined or above documentation is adjusted. But this would need thorough
> double checking, because I expect maxcpus=X was never intended to bring up
> more than X cores later via sysfs and I expect there are more
> places where things have to get ajusted.
>
Yep, that sounds reasonable.
Regards,
Srivatsa S. Bhat
>
>> So
>> teach acpi to play nice with maxcpus= parameter, and perform the initialization
>> for all present cpus, but defer their startup to the point when they are
>> actually onlined later.
>>
>> But that alone won't suffice as a fix, because there is one more thing that
>> the present but !online cpus lack - the need_hotplug_init flag.
>> The need_hotplug_init flag is set only for physically hotplugged cpus and not
>> for cpus which were already present but not brought online during boot (due to
>> the maxcpus= parameter). For cpus with this flag set, during the online
>> operation, acpi_cpu_soft_notify() takes care of the registration with cpuidle.
>> So, in order to allow the present but !online cpus to be onlined later with
>> full features (by making use of acpi_cpu_soft_notify()), set their
>> need_hotplug_init flag.
>>
>> Reported-by: Daniel Lezcano <daniel.lezcano@linaro.org>
>> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
>>
>> ---
>>
>> Daniel, this patch works for me. Does it work for you as well?
>>
>> drivers/acpi/processor_driver.c | 16 +++++++++++-----
>> 1 files changed, 11 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
>> index 0734086..f29d30f 100644
>> --- a/drivers/acpi/processor_driver.c
>> +++ b/drivers/acpi/processor_driver.c
>> @@ -551,11 +551,6 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
>> return 0;
>> }
>>
>> -#ifdef CONFIG_SMP
>> - if (pr->id >= setup_max_cpus && pr->id != 0)
>> - return 0;
>> -#endif
>> -
>> BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
>>
>> /*
>> @@ -580,6 +575,17 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
>> goto err_clear_processor;
>> }
>>
>> +#ifdef CONFIG_SMP
>> + if (pr->id >= setup_max_cpus && pr->id != 0) {
>> + /*
>> + * Don't start cpus beyond maxcpus now. But allow them to
>> + * to be brought online later.
>> + */
>> + pr->flags.need_hotplug_init = 1;
>> + return 0;
>> + }
>> +#endif
>> +
>> /*
>> * Do not start hotplugged CPUs now, but when they
>> * are onlined the first time
>>
>>
>>
^ permalink raw reply
* Re: [PATCH] acpi, cpuidle: Register with cpuidle even if cpu is onlined after boot (beyond maxcpus)
From: Thomas Renninger @ 2012-06-25 13:53 UTC (permalink / raw)
To: Srivatsa S. Bhat
Cc: x86, Linux PM mailing list, linux-kernel, linux-acpi, linux-pm
In-Reply-To: <4FE84AB7.6020305@linux.vnet.ibm.com>
On Monday, June 25, 2012 01:25:43 PM Srivatsa S. Bhat wrote:
>
> Daniel Lezcano noticed that after booting with maxcpus=X, if we online the
> remaining cpus by writing: echo 1 > /sys/devices/system/cpu/cpuY/online, then
> for the newly onlined cpus, the cpuidle directory is not found under
> /sys/devices/system/cpu/cpuY.
>
> Partly, the reason for this is that acpi restricts the initialization to cpus
> within the maxcpus limit. (See commit 75cbfb9 "ACPI: Do not try to set up acpi
> processor stuff on cores exceeding maxcpus="). The maxcpus= kernel parameter is
> used to restrict the number of cpus brought up during boot. That doesn't mean
> that we should hard restrict the bring up of the remaining cpus later on.
Sorry, but IMO it exaclty does mean that (adding more general lists for
further comments).
If you can online more cores than maxcpus= via sysfs, this sounds like a bug.
Not the other way around.
Compare with Documentation/kernel-parameters.txt:
maxcpus= [SMP] Maximum number of processors that an SMP kernel
should make use of. maxcpus=n : n >= 0 limits the
kernel to using 'n' processors. n=0 is a special case,
it is equivalent to "nosmp", which also disables
the IO APIC.
Chances that you run into more problems are high.
It would help if it is explained why at all this would be needed.
If there really is a valid use-case, possibly a bootcpus= param could get
defined or above documentation is adjusted. But this would need thorough
double checking, because I expect maxcpus=X was never intended to bring up
more than X cores later via sysfs and I expect there are more
places where things have to get ajusted.
Thomas
> So
> teach acpi to play nice with maxcpus= parameter, and perform the initialization
> for all present cpus, but defer their startup to the point when they are
> actually onlined later.
>
> But that alone won't suffice as a fix, because there is one more thing that
> the present but !online cpus lack - the need_hotplug_init flag.
> The need_hotplug_init flag is set only for physically hotplugged cpus and not
> for cpus which were already present but not brought online during boot (due to
> the maxcpus= parameter). For cpus with this flag set, during the online
> operation, acpi_cpu_soft_notify() takes care of the registration with cpuidle.
> So, in order to allow the present but !online cpus to be onlined later with
> full features (by making use of acpi_cpu_soft_notify()), set their
> need_hotplug_init flag.
>
> Reported-by: Daniel Lezcano <daniel.lezcano@linaro.org>
> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
>
> ---
>
> Daniel, this patch works for me. Does it work for you as well?
>
> drivers/acpi/processor_driver.c | 16 +++++++++++-----
> 1 files changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
> index 0734086..f29d30f 100644
> --- a/drivers/acpi/processor_driver.c
> +++ b/drivers/acpi/processor_driver.c
> @@ -551,11 +551,6 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
> return 0;
> }
>
> -#ifdef CONFIG_SMP
> - if (pr->id >= setup_max_cpus && pr->id != 0)
> - return 0;
> -#endif
> -
> BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
>
> /*
> @@ -580,6 +575,17 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
> goto err_clear_processor;
> }
>
> +#ifdef CONFIG_SMP
> + if (pr->id >= setup_max_cpus && pr->id != 0) {
> + /*
> + * Don't start cpus beyond maxcpus now. But allow them to
> + * to be brought online later.
> + */
> + pr->flags.need_hotplug_init = 1;
> + return 0;
> + }
> +#endif
> +
> /*
> * Do not start hotplugged CPUs now, but when they
> * are onlined the first time
>
>
>
^ permalink raw reply
* linux-next : cpuidle - could you add my tree please
From: Daniel Lezcano @ 2012-06-25 13:27 UTC (permalink / raw)
To: Stephen Rothwell
Cc: linux-acpi, linux-pm, Lists Linaro-dev, Linux Kernel Mailing List,
Kevin Hilman, Peter De Schrijver, Amit Kucheria, linux-next,
Colin Cross, Andrew Morton, Linus Torvalds, Rob Lee
In-Reply-To: <4FDF2D58.9010006@ti.com>
Hi Stephen,
we discussed last week to put in place a tree grouping the cpuidle
modifications [1]. Is it possible to add the tree ?
git://git.linaro.org/people/dlezcano/cpuidle-next.git #cpuidle-next
It contains for the moment Colin Cross's cpuidle coupled states.
Thanks in advance
-- Daniel
[1] https://lkml.org/lkml/2012/6/18/113
^ permalink raw reply
* Re: [linux-pm] cpuidle future and improvements
From: Shilimkar, Santosh @ 2012-06-25 13:17 UTC (permalink / raw)
To: Daniel Lezcano
Cc: linux-acpi, linux-pm, Lists Linaro-dev, Linux Kernel Mailing List,
Kevin Hilman, Peter De Schrijver, Amit Kucheria, linux-next,
Colin Cross, Andrew Morton, Linus Torvalds, Rob Lee
In-Reply-To: <4FE86361.3050603@linaro.org>
On Mon, Jun 25, 2012 at 6:40 PM, Daniel Lezcano
<daniel.lezcano@linaro.org> wrote:
> On 06/25/2012 02:58 PM, Shilimkar, Santosh wrote:
>> On Mon, Jun 18, 2012 at 7:00 PM, a0393909 <santosh.shilimkar@ti.com> wrote:
>>> Daniel,
>>>
>>>
>>> On 06/18/2012 02:10 PM, Daniel Lezcano wrote:
>>>>
>>>>
>>>> Dear all,
>>>>
>>>> A few weeks ago, Peter De Schrijver proposed a patch [1] to allow per
>>>> cpu latencies. We had a discussion about this patchset because it
>>>> reverse the modifications Deepthi did some months ago [2] and we may
>>>> want to provide a different implementation.
>>>>
>>>> The Linaro Connect [3] event bring us the opportunity to meet people
>>>> involved in the power management and the cpuidle area for different SoC.
>>>>
>>>> With the Tegra3 and big.LITTLE architecture, making per cpu latencies
>>>> for cpuidle is vital.
>>>>
>>>> Also, the SoC vendors would like to have the ability to tune their cpu
>>>> latencies through the device tree.
>>>>
>>>> We agreed in the following steps:
>>>>
>>>> 1. factor out / cleanup the cpuidle code as much as possible
>>>> 2. better sharing of code amongst SoC idle drivers by moving common bits
>>>> to core code
>>>> 3. make the cpuidle_state structure contain only data
>>>> 4. add a API to register latencies per cpu
>>>>
>>>> These four steps impacts all the architecture. I began the factor out
>>>> code / cleanup [4] and that has been accepted upstream and I proposed
>>>> some modifications [5] but I had a very few answers.
>>>>
>>> Another thing which we discussed is bringing the CPU cluster/package
>>> notion in the core idle code. Couple idle did bring that idea to some
>>> extent but in can be further extended and abstracted. Atm, most of
>>> the work is done in back-end cpuidle drivers which can be easily
>>> abstracted if the "cluster idle" notion is supported in the core layer.
>>>
>> Are you considering the "cluster idle" as one of the topic ?
>
> Yes, absolutely. ATM, I am looking for refactoring the cpuidle code and
> cleanup whenever is possible.
>
Cool !!
regards
Santosh
^ permalink raw reply
* Re: [linux-pm] cpuidle future and improvements
From: Daniel Lezcano @ 2012-06-25 13:10 UTC (permalink / raw)
To: Shilimkar, Santosh
Cc: linux-acpi, linux-pm, Lists Linaro-dev, Linux Kernel Mailing List,
Kevin Hilman, Peter De Schrijver, Amit Kucheria, linux-next,
Colin Cross, Andrew Morton, Linus Torvalds, Rob Lee
In-Reply-To: <CAMQu2gz8aGC1DeOvWNNPaaMD9eJLuiJ5HGoKe98EDtV73_QRTQ@mail.gmail.com>
On 06/25/2012 02:58 PM, Shilimkar, Santosh wrote:
> On Mon, Jun 18, 2012 at 7:00 PM, a0393909 <santosh.shilimkar@ti.com> wrote:
>> Daniel,
>>
>>
>> On 06/18/2012 02:10 PM, Daniel Lezcano wrote:
>>>
>>>
>>> Dear all,
>>>
>>> A few weeks ago, Peter De Schrijver proposed a patch [1] to allow per
>>> cpu latencies. We had a discussion about this patchset because it
>>> reverse the modifications Deepthi did some months ago [2] and we may
>>> want to provide a different implementation.
>>>
>>> The Linaro Connect [3] event bring us the opportunity to meet people
>>> involved in the power management and the cpuidle area for different SoC.
>>>
>>> With the Tegra3 and big.LITTLE architecture, making per cpu latencies
>>> for cpuidle is vital.
>>>
>>> Also, the SoC vendors would like to have the ability to tune their cpu
>>> latencies through the device tree.
>>>
>>> We agreed in the following steps:
>>>
>>> 1. factor out / cleanup the cpuidle code as much as possible
>>> 2. better sharing of code amongst SoC idle drivers by moving common bits
>>> to core code
>>> 3. make the cpuidle_state structure contain only data
>>> 4. add a API to register latencies per cpu
>>>
>>> These four steps impacts all the architecture. I began the factor out
>>> code / cleanup [4] and that has been accepted upstream and I proposed
>>> some modifications [5] but I had a very few answers.
>>>
>> Another thing which we discussed is bringing the CPU cluster/package
>> notion in the core idle code. Couple idle did bring that idea to some
>> extent but in can be further extended and abstracted. Atm, most of
>> the work is done in back-end cpuidle drivers which can be easily
>> abstracted if the "cluster idle" notion is supported in the core layer.
>>
> Are you considering the "cluster idle" as one of the topic ?
Yes, absolutely. ATM, I am looking for refactoring the cpuidle code and
cleanup whenever is possible.
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [linux-pm] cpuidle future and improvements
From: Shilimkar, Santosh @ 2012-06-25 12:58 UTC (permalink / raw)
To: Daniel Lezcano
Cc: linux-acpi, linux-pm, Lists Linaro-dev, Linux Kernel Mailing List,
Kevin Hilman, Peter De Schrijver, Amit Kucheria, linux-next,
Colin Cross, Andrew Morton, Linus Torvalds, Rob Lee
In-Reply-To: <4FDF2D58.9010006@ti.com>
On Mon, Jun 18, 2012 at 7:00 PM, a0393909 <santosh.shilimkar@ti.com> wrote:
> Daniel,
>
>
> On 06/18/2012 02:10 PM, Daniel Lezcano wrote:
>>
>>
>> Dear all,
>>
>> A few weeks ago, Peter De Schrijver proposed a patch [1] to allow per
>> cpu latencies. We had a discussion about this patchset because it
>> reverse the modifications Deepthi did some months ago [2] and we may
>> want to provide a different implementation.
>>
>> The Linaro Connect [3] event bring us the opportunity to meet people
>> involved in the power management and the cpuidle area for different SoC.
>>
>> With the Tegra3 and big.LITTLE architecture, making per cpu latencies
>> for cpuidle is vital.
>>
>> Also, the SoC vendors would like to have the ability to tune their cpu
>> latencies through the device tree.
>>
>> We agreed in the following steps:
>>
>> 1. factor out / cleanup the cpuidle code as much as possible
>> 2. better sharing of code amongst SoC idle drivers by moving common bits
>> to core code
>> 3. make the cpuidle_state structure contain only data
>> 4. add a API to register latencies per cpu
>>
>> These four steps impacts all the architecture. I began the factor out
>> code / cleanup [4] and that has been accepted upstream and I proposed
>> some modifications [5] but I had a very few answers.
>>
> Another thing which we discussed is bringing the CPU cluster/package
> notion in the core idle code. Couple idle did bring that idea to some
> extent but in can be further extended and abstracted. Atm, most of
> the work is done in back-end cpuidle drivers which can be easily
> abstracted if the "cluster idle" notion is supported in the core layer.
>
Are you considering the "cluster idle" as one of the topic ?
Regards
Santosh
^ permalink raw reply
* Re: cpuidle future and improvements
From: Daniel Lezcano @ 2012-06-25 12:54 UTC (permalink / raw)
To: Colin Cross
Cc: linux-acpi, linux-pm, Lists Linaro-dev, Linux Kernel Mailing List,
Amit Kucheria, Deepthi Dharwar, lenb@kernel.org, Andrew Morton,
Linus Torvalds, Peter De Schrijver, Rob Lee, rjw, Kevin Hilman,
linux-next
In-Reply-To: <CAMbhsRQRFXcayyWjM1RirgFppVAK23z2+3EbYOCw-qmzuY9_2g@mail.gmail.com>
On 06/18/2012 08:15 PM, Colin Cross wrote:
> On Mon, Jun 18, 2012 at 1:40 AM, Daniel Lezcano
> <daniel.lezcano@linaro.org> wrote:
>> I propose to host a cpuidle-next tree where all these modifications will
>> be and where people can send patches against, preventing last minutes
>> conflicts and perhaps Lenb will agree to pull from this tree. In the
>> meantime, the tree will be part of the linux-next, the patches will be
>> more widely tested and could be fixed earlier.
>
> My coupled cpuidle patches were acked and temporarily in Len's
> next/Linus pull branch, but were later dropped when the first pull
> request to Linus was rejected. I asked Len to either put the coupled
> cpuidle patches into his next branch, or let me host them so people
> could base SoC branches off of them and let Len pull them later, but
> got no response. If you do start a cpuidle for-next branch, can you
> pull my coupled-cpuidle branch:
>
> The following changes since commit 76e10d158efb6d4516018846f60c2ab5501900bc:
>
> Linux 3.4 (2012-05-20 15:29:13 -0700)
>
> are available in the git repository at:
> https://android.googlesource.com/kernel/common.git coupled-cpuidle
>
> Colin Cross (4):
> cpuidle: refactor out cpuidle_enter_state
> cpuidle: fix error handling in __cpuidle_register_device
> cpuidle: add support for states that affect multiple cpus
> cpuidle: coupled: add parallel barrier function
>
> drivers/cpuidle/Kconfig | 3 +
> drivers/cpuidle/Makefile | 1 +
> drivers/cpuidle/coupled.c | 715 +++++++++++++++++++++++++++++++++++++++++++++
> drivers/cpuidle/cpuidle.c | 68 ++++-
> drivers/cpuidle/cpuidle.h | 32 ++
> include/linux/cpuidle.h | 11 +
> 6 files changed, 813 insertions(+), 17 deletions(-)
> create mode 100644 drivers/cpuidle/coupled.c
Done.
http://git.linaro.org/gitweb?p=people/dlezcano/cpuidle-next.git;a=shortlog;h=refs/heads/cpuidle-next
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* [PATCH] acpi, cpuidle: Register with cpuidle even if cpu is onlined after boot (beyond maxcpus)
From: Srivatsa S. Bhat @ 2012-06-25 11:25 UTC (permalink / raw)
To: Daniel Lezcano
Cc: Deepthi Dharwar, linux-acpi, linux-pm, trenn,
Linux PM mailing list, lenb, Rafael J. Wysocki
In-Reply-To: <4FE027AC.8010607@linaro.org>
Daniel Lezcano noticed that after booting with maxcpus=X, if we online the
remaining cpus by writing: echo 1 > /sys/devices/system/cpu/cpuY/online, then
for the newly onlined cpus, the cpuidle directory is not found under
/sys/devices/system/cpu/cpuY.
Partly, the reason for this is that acpi restricts the initialization to cpus
within the maxcpus limit. (See commit 75cbfb9 "ACPI: Do not try to set up acpi
processor stuff on cores exceeding maxcpus="). The maxcpus= kernel parameter is
used to restrict the number of cpus brought up during boot. That doesn't mean
that we should hard restrict the bring up of the remaining cpus later on. So
teach acpi to play nice with maxcpus= parameter, and perform the initialization
for all present cpus, but defer their startup to the point when they are
actually onlined later.
But that alone won't suffice as a fix, because there is one more thing that
the present but !online cpus lack - the need_hotplug_init flag.
The need_hotplug_init flag is set only for physically hotplugged cpus and not
for cpus which were already present but not brought online during boot (due to
the maxcpus= parameter). For cpus with this flag set, during the online
operation, acpi_cpu_soft_notify() takes care of the registration with cpuidle.
So, in order to allow the present but !online cpus to be onlined later with
full features (by making use of acpi_cpu_soft_notify()), set their
need_hotplug_init flag.
Reported-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---
Daniel, this patch works for me. Does it work for you as well?
drivers/acpi/processor_driver.c | 16 +++++++++++-----
1 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 0734086..f29d30f 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -551,11 +551,6 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
return 0;
}
-#ifdef CONFIG_SMP
- if (pr->id >= setup_max_cpus && pr->id != 0)
- return 0;
-#endif
-
BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
/*
@@ -580,6 +575,17 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
goto err_clear_processor;
}
+#ifdef CONFIG_SMP
+ if (pr->id >= setup_max_cpus && pr->id != 0) {
+ /*
+ * Don't start cpus beyond maxcpus now. But allow them to
+ * to be brought online later.
+ */
+ pr->flags.need_hotplug_init = 1;
+ return 0;
+ }
+#endif
+
/*
* Do not start hotplugged CPUs now, but when they
* are onlined the first time
^ permalink raw reply related
* Re: [RFC PATCH 11/12] thermal: introduce cooling state arbitrator
From: Valentin, Eduardo @ 2012-06-24 15:19 UTC (permalink / raw)
To: Zhang Rui; +Cc: linux-acpi@vger.kernel.org, linux-pm
In-Reply-To: <1340174859.1682.21.camel@rui.sh.intel.com>
Hello Rui,
On Wed, Jun 20, 2012 at 9:47 AM, Zhang Rui <rui.zhang@intel.com> wrote:
> On 三, 2012-06-13 at 17:23 +0300, Eduardo Valentin wrote:
>> Hello Rui,
>>
>> On Mon, Jun 11, 2012 at 11:20:39AM +0800, Zhang Rui wrote:
>> >
>> > Introduce simple arbitrator for setting device cooling state,
>> > to fix the problem that a cooling device may be referenced by
>> > by multiple trip points in multiple thermal zones.
>> >
>> >
>> > With this patch, we have two stages for updating a thermal zone,
>> > 1. check if a thermal_instance needs to be updated or not
>> > 2. update the cooling device, based on the target cooling state
>> > of all its instances.
>> >
>> > Note that, currently, the cooling device is set to the deepest
>> > cooling state required.
>> >
>> > Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>> > ---
>> > drivers/thermal/thermal_sys.c | 41 ++++++++++++++++++++++++++++++++++++++---
>> > include/linux/thermal.h | 1 +
>> > 2 files changed, 39 insertions(+), 3 deletions(-)
>> >
>> > Index: rtd3/drivers/thermal/thermal_sys.c
>> > ===================================================================
>> > --- rtd3.orig/drivers/thermal/thermal_sys.c
>> > +++ rtd3/drivers/thermal/thermal_sys.c
>> > @@ -54,6 +54,7 @@ struct thermal_instance {
>> > int trip;
>> > unsigned long upper; /* Highest cooling state for this trip point */
>> > unsigned long lower; /* Lowest cooling state for this trip point */
>> > + unsigned long target; /* expected cooling state */
>> > char attr_name[THERMAL_NAME_LENGTH];
>> > struct device_attribute attr;
>> > struct list_head tz_node; /* node in tz->instances */
>> > @@ -812,6 +813,7 @@ int thermal_zone_bind_cooling_device(str
>> > dev->trip = trip;
>> > dev->upper = upper;
>> > dev->lower = lower;
>> > + dev->target = -1;
>> >
>> > result = get_idr(&tz->idr, &tz->lock, &dev->id);
>> > if (result)
>> > @@ -949,6 +951,7 @@ thermal_cooling_device_register(char *ty
>> > strcpy(cdev->type, type);
>> > INIT_LIST_HEAD(&cdev->instances);
>> > cdev->ops = ops;
>> > + cdev->updated = 1;
>> > cdev->device.class = &thermal_class;
>> > cdev->devdata = devdata;
>> > dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
>> > @@ -1040,6 +1043,32 @@ void thermal_cooling_device_unregister(s
>> > }
>> > EXPORT_SYMBOL(thermal_cooling_device_unregister);
>> >
>> > +static void thermal_zone_do_update(struct thermal_zone_device *tz)
>> > +{
>> > + struct thermal_instance *instance1, *instance2;
>> > + struct thermal_cooling_device *cdev;
>> > + int target;
>> > +
>> > + list_for_each_entry(instance1, &tz->instances, tz_node) {
>> > + cdev = instance1->cdev;
>> > +
>> > + /* cooling device has already been updated*/
>> > + if (cdev->updated)
>> > + continue;
>> > +
>> > + target = 0;
>> > + /* Make sure cdev enters the deepest cooling state */
>> > + list_for_each_entry(instance2, &cdev->instances, cdev_node) {
>> > + if (instance2->target == -1)
>> > + continue;
>> > + if (instance2->target > target)
>> > + target = instance2->target;
>> > + }
>> > + cdev->ops->set_cur_state(cdev, target);
>> > + cdev->updated = 1;
>> > + }
>> > +}
>>
>> I think the above arbitrator solution does not escalate. As I can see,
>> the arbitrator takes care of cooling device instances in the same thermal zone.
>>
> why?
> It parses the thermal instances in one thermal zone to find the cooling
> devices, and then parse all the thermal instances for the cooling
> devices, no matter which thermal zone it belongs to.
I think I got confused with the nomenclature change. So, yes, it does
go through all zones and cooling devices. But still, ideally it should
be a plist per device, don't you think? This way your search space is
reduced.
>
>> What if you have a device which expose cooling device instances in different
>> thermal zones?
>>
>> Besides, the thermal constraint might collide with pm QoS or with settings
>> coming from user space interfaces.
>>
>
>> That's actually why I was suggesting to have this 'arbitrator' or constraint
>> management outside the thermal framework. And managed per device at some
>> other abstraction layer.
>>
> Yeah, but I think we can have an incremental patch to handle the pm Qos
> constrains. Especially Durga already has the governor patches to move
> this out of the thermal framework.
> what do you think?
I think it sounds like a plan. I also like incremental approach.
>
> thanks,
> rui
>
>> > +
>> > /*
>> > * Cooling algorithm for active trip points
>> > *
>> > @@ -1086,19 +1115,24 @@ static void thermal_zone_trip_update(str
>> > cur_state = cur_state > instance->lower ?
>> > (cur_state - 1) : instance->lower;
>> > }
>> > - cdev->ops->set_cur_state(cdev, cur_state);
>> > + instance->target = cur_state;
>> > + cdev->updated = 0; /* cooling device needs update */
>> > }
>> > } else { /* below trip */
>> > list_for_each_entry(instance, &tz->instances, tz_node) {
>> > if (instance->trip != trip)
>> > continue;
>> >
>> > + /* Do not use the deacitve thermal instance */
>> > + if (instance->target == -1)
>> > + continue;
>> > cdev = instance->cdev;
>> > cdev->ops->get_cur_state(cdev, &cur_state);
>> >
>> > cur_state = cur_state > instance->lower ?
>> > - (cur_state - 1) : instance->lower;
>> > - cdev->ops->set_cur_state(cdev, cur_state);
>> > + (cur_state - 1) : -1;
>> > + instance->target = cur_state;
>> > + cdev->updated = 0; /* cooling device needs update */
>> > }
>> > }
>> >
>> > @@ -1159,6 +1193,7 @@ void thermal_zone_device_update(struct t
>> > }
>> > }
>> >
>> > + thermal_zone_do_update(tz);
>> > if (tz->forced_passive)
>> > thermal_zone_device_passive(tz, temp, tz->forced_passive,
>> > THERMAL_TRIPS_NONE);
>> > Index: rtd3/include/linux/thermal.h
>> > ===================================================================
>> > --- rtd3.orig/include/linux/thermal.h
>> > +++ rtd3/include/linux/thermal.h
>> > @@ -86,6 +86,7 @@ struct thermal_cooling_device {
>> > struct device device;
>> > void *devdata;
>> > const struct thermal_cooling_device_ops *ops;
>> > + int updated; /* 1 if the cooling device does not need update */
>> > struct list_head instances;
>> > struct list_head node;
>> > };
>> >
>> >
>
>
--
Eduardo Valentin
^ permalink raw reply
* Re: [PATCH] PCI: add NO_D3_DURING_SLEEP flag and revert 151b61284776be2
From: Pavel Pisa @ 2012-06-24 7:00 UTC (permalink / raw)
To: Alan Stern
Cc: linux-pm-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Greg KH,
USB list
In-Reply-To: <Pine.LNX.4.44L0.1206232147420.4446-100000-pYrvlCTfrz9XsRXLowluHWD2FQJk+8+b@public.gmane.org>
Hello Alan,
On Sunday 24 June 2012 03:52:23 Alan Stern wrote:
> > Index: linux-3.4/drivers/pci/quirks.c
> > ===================================================================
> > --- linux-3.4.orig/drivers/pci/quirks.c 2012-06-23 16:37:14.582568585
> > +0200 +++ linux-3.4/drivers/pci/quirks.c 2012-06-23
> > 16:38:38.378571372 +0200 @@ -2942,6 +2942,8 @@
> > }
> > DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3);
> > DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3);
> > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x3b3c, asus_ehci_no_d3);
> > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x3b34, asus_ehci_no_d3);
> >
> > static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
> > struct pci_fixup *end)
> >
> > This quirk allows laptop suspend and resume correctly when nothing
> > is connected to the USB or even when mounted FLASH disk is connected.
> > The USB drive works correctly after resume.
>
> Do you want to submit your patch for inclusion in the kernel? If you
> do, you should follow the instructions in
> Documentation/SubmittingPatches.
>
> Also, you should modify the comment before the asus_ehci_no_d3()
> routine. Mention the 5 Series/3400 Series chipset in addition to the 6
> Series/C200 Series chipset.
>
> Or if you prefer, I could submit a modified version of your patch.
I know formal patch procedure but I expect, that it would be much
faster and simpler if you collect the list and add them yourself.
I expect, that there is potential to solve problems of many
other (at least ASUS) laptop configurations.
By the way, I have similar problem with my MSI laptop. So I try
to check if EHCI unbind does not help there as well.
Best wishes,
Pavel
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] PCI: add NO_D3_DURING_SLEEP flag and revert 151b61284776be2
From: Alan Stern @ 2012-06-24 1:52 UTC (permalink / raw)
To: Pavel Pisa
Cc: linux-pm-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Greg KH,
USB list
In-Reply-To: <201206232320.15186.pisa-/N2ztlQkxE7Ub/6JBqosbQ@public.gmane.org>
On Sat, 23 Jun 2012, Pavel Pisa wrote:
> Hello Alan and all others,
>
> I have observed similar lock during suspend to RAM on ASUS K52F
>
> Handle 0x0002, DMI type 2, 15 bytes
> Base Board Information
> Manufacturer: ASUSTeK Computer Inc.
> Product Name: K52F
>
> BIOS Information
> Vendor: American Megatrends Inc.
> Version: K52F.218
> Release Date: 07/12/2011
>
> 00:00.0 Host bridge [0600]: Intel Corporation Core Processor DRAM Controller [8086:0044] (rev 18)
> 00:02.0 VGA compatible controller [0300]: Intel Corporation Core Processor Integrated Graphics Controller [8086:0046] (rev 18)
> 00:16.0 Communication controller [0780]: Intel Corporation 5 Series/3400 Series Chipset HECI Controller [8086:3b64] (rev 06)
> ...
> 00:1a.0 USB Controller [0c03]: Intel Corporation 5 Series/3400 Series Chipset USB2 Enhanced Host Controller [8086:3b3c] (rev 06)
> 00:1d.0 USB Controller [0c03]: Intel Corporation 5 Series/3400 Series Chipset USB2 Enhanced Host Controller [8086:3b34] (rev 06)
>
> When I unbind EHCI controllers
> # Unbind ehci_hcd for first device 0000:00:1a.0:
> echo -n "0000:00:1a.0" >/sys/bus/pci/drivers/ehci_hcd/unbind
> # Unbind ehci_hcd for second device 0000:00:1d.0:
> echo -n "0000:00:1d.0" >/sys/bus/pci/drivers/ehci_hcd/unbind
> then laptop goes to suspend after
> echo mem >/sys/power/state
> and when power button is pressed it restores to functional state.
> It works quite stable repeatedly.
>
> This is similar to the problem solved by your patch.
>
> I have tried 3.4.4 with kernel and added quirk
>
> ---
> drivers/pci/quirks.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> Index: linux-3.4/drivers/pci/quirks.c
> ===================================================================
> --- linux-3.4.orig/drivers/pci/quirks.c 2012-06-23 16:37:14.582568585 +0200
> +++ linux-3.4/drivers/pci/quirks.c 2012-06-23 16:38:38.378571372 +0200
> @@ -2942,6 +2942,8 @@
> }
> DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3);
> DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3);
> +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x3b3c, asus_ehci_no_d3);
> +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x3b34, asus_ehci_no_d3);
>
> static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
> struct pci_fixup *end)
>
> This quirk allows laptop suspend and resume correctly when nothing
> is connected to the USB or even when mounted FLASH disk is connected.
> The USB drive works correctly after resume.
Do you want to submit your patch for inclusion in the kernel? If you
do, you should follow the instructions in
Documentation/SubmittingPatches.
Also, you should modify the comment before the asus_ehci_no_d3()
routine. Mention the 5 Series/3400 Series chipset in addition to the 6
Series/C200 Series chipset.
Or if you prefer, I could submit a modified version of your patch.
> DVB tuner is connected
>
> Bus 002 Device 003: ID 0b48:300d TechnoTrend AG TT-connect CT-3650 CI
>
> then suspend proceeds correctly but resume locks hard again.
>
> This seems to be problem in dvb_usb_ttusb2 driver.
>
> But anyway I think, that adding 0x3b3c and 0x3b34 to the quirk list
> could help more people.
Alan Stern
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] PCI: add NO_D3_DURING_SLEEP flag and revert 151b61284776be2
From: Pavel Pisa @ 2012-06-23 21:20 UTC (permalink / raw)
To: linux-pm-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Alan Stern
Cc: Greg KH, USB list
In-Reply-To: <Pine.LNX.4.44L0.1206131117260.1401-100000-IYeN2dnnYyZXsRXLowluHWD2FQJk+8+b@public.gmane.org>
Hello Alan and all others,
I have observed similar lock during suspend to RAM on ASUS K52F
Handle 0x0002, DMI type 2, 15 bytes
Base Board Information
Manufacturer: ASUSTeK Computer Inc.
Product Name: K52F
BIOS Information
Vendor: American Megatrends Inc.
Version: K52F.218
Release Date: 07/12/2011
00:00.0 Host bridge [0600]: Intel Corporation Core Processor DRAM Controller [8086:0044] (rev 18)
00:02.0 VGA compatible controller [0300]: Intel Corporation Core Processor Integrated Graphics Controller [8086:0046] (rev 18)
00:16.0 Communication controller [0780]: Intel Corporation 5 Series/3400 Series Chipset HECI Controller [8086:3b64] (rev 06)
...
00:1a.0 USB Controller [0c03]: Intel Corporation 5 Series/3400 Series Chipset USB2 Enhanced Host Controller [8086:3b3c] (rev 06)
00:1d.0 USB Controller [0c03]: Intel Corporation 5 Series/3400 Series Chipset USB2 Enhanced Host Controller [8086:3b34] (rev 06)
When I unbind EHCI controllers
# Unbind ehci_hcd for first device 0000:00:1a.0:
echo -n "0000:00:1a.0" >/sys/bus/pci/drivers/ehci_hcd/unbind
# Unbind ehci_hcd for second device 0000:00:1d.0:
echo -n "0000:00:1d.0" >/sys/bus/pci/drivers/ehci_hcd/unbind
then laptop goes to suspend after
echo mem >/sys/power/state
and when power button is pressed it restores to functional state.
It works quite stable repeatedly.
This is similar to the problem solved by your patch.
I have tried 3.4.4 with kernel and added quirk
---
drivers/pci/quirks.c | 2 ++
1 file changed, 2 insertions(+)
Index: linux-3.4/drivers/pci/quirks.c
===================================================================
--- linux-3.4.orig/drivers/pci/quirks.c 2012-06-23 16:37:14.582568585 +0200
+++ linux-3.4/drivers/pci/quirks.c 2012-06-23 16:38:38.378571372 +0200
@@ -2942,6 +2942,8 @@
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x3b3c, asus_ehci_no_d3);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x3b34, asus_ehci_no_d3);
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
struct pci_fixup *end)
This quirk allows laptop suspend and resume correctly when nothing
is connected to the USB or even when mounted FLASH disk is connected.
The USB drive works correctly after resume.
DVB tuner is connected
Bus 002 Device 003: ID 0b48:300d TechnoTrend AG TT-connect CT-3650 CI
then suspend proceeds correctly but resume locks hard again.
This seems to be problem in dvb_usb_ttusb2 driver.
But anyway I think, that adding 0x3b3c and 0x3b34 to the quirk list
could help more people.
Best wishes
Pavel Pisa
e-mail: pisa-/N2ztlQkxE7Ub/6JBqosbQ@public.gmane.org
www: http://cmp.felk.cvut.cz/~pisa
university: http://dce.fel.cvut.cz/
company: http://www.pikron.com/
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH -v4 6/6] fault-injection: add notifier error injection testing scripts
From: Akinobu Mita @ 2012-06-23 14:58 UTC (permalink / raw)
To: linux-kernel, akpm
Cc: Akinobu Mita, Pavel Machek, Rafael J. Wysocki, linux-pm, Greg KH,
linux-mm, Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev,
Américo Wang
In-Reply-To: <1340463502-15341-1-git-send-email-akinobu.mita@gmail.com>
This adds two testing scripts with notifier error injection
* tools/testing/fault-injection/cpu-notifier.sh is testing script for
CPU notifier error handling by using cpu-notifier-error-inject.ko.
1. Offline all hot-pluggable CPUs in preparation for testing
2. Test CPU hot-add error handling by injecting notifier errors
3. Online all hot-pluggable CPUs in preparation for testing
4. Test CPU hot-remove error handling by injecting notifier errors
* tools/testing/fault-injection/memory-notifier.sh is doing the similar
thing for memory hotplug notifier.
1. Offline 10% of hot-pluggable memory in preparation for testing
2. Test memory hot-add error handling by injecting notifier errors
3. Online all hot-pluggable memory in preparation for testing
4. Test memory hot-remove error handling by injecting notifier errors
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Suggested-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: linux-pm@lists.linux-foundation.org
Cc: Greg KH <greg@kroah.com>
Cc: linux-mm@kvack.org
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: Américo Wang <xiyou.wangcong@gmail.com>
---
* v4
- add -r option for memory-notifier.sh to specify percent of offlining
memory blocks
tools/testing/fault-injection/cpu-notifier.sh | 169 +++++++++++++++++++++
tools/testing/fault-injection/memory-notifier.sh | 176 ++++++++++++++++++++++
2 files changed, 345 insertions(+)
create mode 100755 tools/testing/fault-injection/cpu-notifier.sh
create mode 100755 tools/testing/fault-injection/memory-notifier.sh
diff --git a/tools/testing/fault-injection/cpu-notifier.sh b/tools/testing/fault-injection/cpu-notifier.sh
new file mode 100755
index 0000000..af93630
--- /dev/null
+++ b/tools/testing/fault-injection/cpu-notifier.sh
@@ -0,0 +1,169 @@
+#!/bin/bash
+
+#
+# list all hot-pluggable CPUs
+#
+hotpluggable_cpus()
+{
+ local state=${1:-.\*}
+
+ for cpu in /sys/devices/system/cpu/cpu*; do
+ if [ -f $cpu/online ] && grep -q $state $cpu/online; then
+ echo ${cpu##/*/cpu}
+ fi
+ done
+}
+
+hotplaggable_offline_cpus()
+{
+ hotpluggable_cpus 0
+}
+
+hotpluggable_online_cpus()
+{
+ hotpluggable_cpus 1
+}
+
+cpu_is_online()
+{
+ grep -q 1 /sys/devices/system/cpu/cpu$1/online
+}
+
+cpu_is_offline()
+{
+ grep -q 0 /sys/devices/system/cpu/cpu$1/online
+}
+
+add_cpu()
+{
+ echo 1 > /sys/devices/system/cpu/cpu$1/online
+}
+
+remove_cpu()
+{
+ echo 0 > /sys/devices/system/cpu/cpu$1/online
+}
+
+add_cpu_expect_success()
+{
+ local cpu=$1
+
+ if ! add_cpu $cpu; then
+ echo $FUNCNAME $cpu: unexpected fail >&2
+ elif ! cpu_is_online $cpu; then
+ echo $FUNCNAME $cpu: unexpected offline >&2
+ fi
+}
+
+add_cpu_expect_fail()
+{
+ local cpu=$1
+
+ if add_cpu $cpu 2> /dev/null; then
+ echo $FUNCNAME $cpu: unexpected success >&2
+ elif ! cpu_is_offline $cpu; then
+ echo $FUNCNAME $cpu: unexpected online >&2
+ fi
+}
+
+remove_cpu_expect_success()
+{
+ local cpu=$1
+
+ if ! remove_cpu $cpu; then
+ echo $FUNCNAME $cpu: unexpected fail >&2
+ elif ! cpu_is_offline $cpu; then
+ echo $FUNCNAME $cpu: unexpected offline >&2
+ fi
+}
+
+remove_cpu_expect_fail()
+{
+ local cpu=$1
+
+ if remove_cpu $cpu 2> /dev/null; then
+ echo $FUNCNAME $cpu: unexpected success >&2
+ elif ! cpu_is_online $cpu; then
+ echo $FUNCNAME $cpu: unexpected offline >&2
+ fi
+}
+
+if [ $UID != 0 ]; then
+ echo must be run as root >&2
+ exit 1
+fi
+
+error=-12
+priority=0
+
+while getopts e:hp: opt; do
+ case $opt in
+ e)
+ error=$OPTARG
+ ;;
+ h)
+ echo "Usage $0 [ -e errno ] [ -p notifier-priority ]"
+ exit
+ ;;
+ p)
+ priority=$OPTARG
+ ;;
+ esac
+done
+
+if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
+ echo "error code must be -4095 <= errno < 0" >&2
+ exit 1
+fi
+
+DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
+
+if [ ! -d "$DEBUGFS" ]; then
+ echo debugfs is not mounted >&2
+ exit 1
+fi
+
+/sbin/modprobe -r cpu-notifier-error-inject
+/sbin/modprobe -q cpu-notifier-error-inject priority=$priority
+
+NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/cpu
+
+if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
+ echo cpu-notifier-error-inject module is not available >&2
+ exit 1
+fi
+
+#
+# Offline all hot-pluggable CPUs
+#
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
+for cpu in `hotpluggable_online_cpus`; do
+ remove_cpu_expect_success $cpu
+done
+
+#
+# Test CPU hot-add error handling (offline => online)
+#
+echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
+for cpu in `hotplaggable_offline_cpus`; do
+ add_cpu_expect_fail $cpu
+done
+
+#
+# Online all hot-pluggable CPUs
+#
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
+for cpu in `hotplaggable_offline_cpus`; do
+ add_cpu_expect_success $cpu
+done
+
+#
+# Test CPU hot-remove error handling (online => offline)
+#
+echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
+for cpu in `hotpluggable_online_cpus`; do
+ remove_cpu_expect_fail $cpu
+done
+
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
+/sbin/modprobe -r cpu-notifier-error-inject
diff --git a/tools/testing/fault-injection/memory-notifier.sh b/tools/testing/fault-injection/memory-notifier.sh
new file mode 100755
index 0000000..843cba7
--- /dev/null
+++ b/tools/testing/fault-injection/memory-notifier.sh
@@ -0,0 +1,176 @@
+#!/bin/bash
+
+#
+# list all hot-pluggable memory
+#
+hotpluggable_memory()
+{
+ local state=${1:-.\*}
+
+ for memory in /sys/devices/system/memory/memory*; do
+ if grep -q 1 $memory/removable &&
+ grep -q $state $memory/state; then
+ echo ${memory##/*/memory}
+ fi
+ done
+}
+
+hotplaggable_offline_memory()
+{
+ hotpluggable_memory offline
+}
+
+hotpluggable_online_memory()
+{
+ hotpluggable_memory online
+}
+
+memory_is_online()
+{
+ grep -q online /sys/devices/system/memory/memory$1/state
+}
+
+memory_is_offline()
+{
+ grep -q offline /sys/devices/system/memory/memory$1/state
+}
+
+add_memory()
+{
+ echo online > /sys/devices/system/memory/memory$1/state
+}
+
+remove_memory()
+{
+ echo offline > /sys/devices/system/memory/memory$1/state
+}
+
+add_memory_expect_success()
+{
+ local memory=$1
+
+ if ! add_memory $memory; then
+ echo $FUNCNAME $memory: unexpected fail >&2
+ elif ! memory_is_online $memory; then
+ echo $FUNCNAME $memory: unexpected offline >&2
+ fi
+}
+
+add_memory_expect_fail()
+{
+ local memory=$1
+
+ if add_memory $memory 2> /dev/null; then
+ echo $FUNCNAME $memory: unexpected success >&2
+ elif ! memory_is_offline $memory; then
+ echo $FUNCNAME $memory: unexpected online >&2
+ fi
+}
+
+remove_memory_expect_success()
+{
+ local memory=$1
+
+ if ! remove_memory $memory; then
+ echo $FUNCNAME $memory: unexpected fail >&2
+ elif ! memory_is_offline $memory; then
+ echo $FUNCNAME $memory: unexpected offline >&2
+ fi
+}
+
+remove_memory_expect_fail()
+{
+ local memory=$1
+
+ if remove_memory $memory 2> /dev/null; then
+ echo $FUNCNAME $memory: unexpected success >&2
+ elif ! memory_is_online $memory; then
+ echo $FUNCNAME $memory: unexpected offline >&2
+ fi
+}
+
+if [ $UID != 0 ]; then
+ echo must be run as root >&2
+ exit 1
+fi
+
+error=-12
+priority=0
+ratio=10
+
+while getopts e:hp:r: opt; do
+ case $opt in
+ e)
+ error=$OPTARG
+ ;;
+ h)
+ echo "Usage $0 [ -e errno ] [ -p notifier-priority ] [ -r percent-of-memory-to-offline ]"
+ exit
+ ;;
+ p)
+ priority=$OPTARG
+ ;;
+ r)
+ ratio=$OPTARG
+ ;;
+ esac
+done
+
+if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
+ echo "error code must be -4095 <= errno < 0" >&2
+ exit 1
+fi
+
+DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
+
+if [ ! -d "$DEBUGFS" ]; then
+ echo debugfs is not mounted >&2
+ exit 1
+fi
+
+/sbin/modprobe -r memory-notifier-error-inject
+/sbin/modprobe -q memory-notifier-error-inject priority=$priority
+
+NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/memory
+
+if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
+ echo memory-notifier-error-inject module is not available >&2
+ exit 1
+fi
+
+#
+# Offline $ratio percent of hot-pluggable memory
+#
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
+for memory in `hotpluggable_online_memory`; do
+ if [ $((RANDOM % 100)) -lt $ratio ]; then
+ remove_memory_expect_success $memory
+ fi
+done
+
+#
+# Test memory hot-add error handling (offline => online)
+#
+echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
+for memory in `hotplaggable_offline_memory`; do
+ add_memory_expect_fail $memory
+done
+
+#
+# Online all hot-pluggable memory
+#
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
+for memory in `hotplaggable_offline_memory`; do
+ add_memory_expect_success $memory
+done
+
+#
+# Test memory hot-remove error handling (online => offline)
+#
+echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
+for memory in `hotpluggable_online_memory`; do
+ remove_memory_expect_fail $memory
+done
+
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
+/sbin/modprobe -r memory-notifier-error-inject
--
1.7.10.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH -v4 3/6] PM: PM notifier error injection module
From: Akinobu Mita @ 2012-06-23 14:58 UTC (permalink / raw)
To: linux-kernel, akpm; +Cc: linux-pm, Akinobu Mita
In-Reply-To: <1340463502-15341-1-git-send-email-akinobu.mita@gmail.com>
This provides the ability to inject artifical errors to PM notifier chain
callbacks. It is controlled through debugfs interface under
/sys/kernel/debug/notifier-error-inject/pm
Each of the files in "error" directory represents an event which can be
failed and contains the error code. If the notifier call chain should
be failed with some events notified, write the error code to the files.
If the notifier call chain should be failed with some events notified,
write the error code to "actions/<notifier event>/error".
Example: Inject PM suspend error (-12 = -ENOMEM)
# cd /sys/kernel/debug/notifier-error-inject/pm
# echo -12 > actions/PM_SUSPEND_PREPARE/error
# echo mem > /sys/power/state
bash: echo: write error: Cannot allocate memory
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: linux-pm@lists.linux-foundation.org
---
* v4
- update modules to follow new interface
lib/Kconfig.debug | 24 ++++++++++++++++++++
lib/Makefile | 1 +
lib/pm-notifier-error-inject.c | 49 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+)
create mode 100644 lib/pm-notifier-error-inject.c
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index be0c197..246cea6 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1119,6 +1119,30 @@ config CPU_NOTIFIER_ERROR_INJECT
If unsure, say N.
+config PM_NOTIFIER_ERROR_INJECT
+ tristate "PM notifier error injection module"
+ depends on PM && NOTIFIER_ERROR_INJECTION
+ default m if PM_DEBUG
+ help
+ This option provides the ability to inject artifical errors to
+ PM notifier chain callbacks. It is controlled through debugfs
+ interface /sys/kernel/debug/notifier-error-inject/pm
+
+ If the notifier call chain should be failed with some events
+ notified, write the error code to "actions/<notifier event>/error".
+
+ Example: Inject PM suspend error (-12 = -ENOMEM)
+
+ # cd /sys/kernel/debug/notifier-error-inject/pm/
+ # echo -12 > actions/PM_SUSPEND_PREPARE/error
+ # echo mem > /sys/power/state
+ bash: echo: write error: Cannot allocate memory
+
+ To compile this code as a module, choose M here: the module will
+ be called pm-notifier-error-inject.
+
+ If unsure, say N.
+
config FAULT_INJECTION
bool "Fault-injection framework"
depends on DEBUG_KERNEL
diff --git a/lib/Makefile b/lib/Makefile
index 23fba9e..230a949 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -92,6 +92,7 @@ obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o
obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o
+obj-$(CONFIG_PM_NOTIFIER_ERROR_INJECT) += pm-notifier-error-inject.o
lib-$(CONFIG_GENERIC_BUG) += bug.o
diff --git a/lib/pm-notifier-error-inject.c b/lib/pm-notifier-error-inject.c
new file mode 100644
index 0000000..c094b2d
--- /dev/null
+++ b/lib/pm-notifier-error-inject.c
@@ -0,0 +1,49 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/suspend.h>
+
+#include "notifier-error-inject.h"
+
+static int priority;
+module_param(priority, int, 0);
+MODULE_PARM_DESC(priority, "specify PM notifier priority");
+
+static struct notifier_err_inject pm_notifier_err_inject = {
+ .actions = {
+ { NOTIFIER_ERR_INJECT_ACTION(PM_HIBERNATION_PREPARE) },
+ { NOTIFIER_ERR_INJECT_ACTION(PM_SUSPEND_PREPARE) },
+ { NOTIFIER_ERR_INJECT_ACTION(PM_RESTORE_PREPARE) },
+ {}
+ }
+};
+
+static struct dentry *dir;
+
+static int err_inject_init(void)
+{
+ int err;
+
+ dir = notifier_err_inject_init("pm", notifier_err_inject_dir,
+ &pm_notifier_err_inject, priority);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ err = register_pm_notifier(&pm_notifier_err_inject.nb);
+ if (err)
+ debugfs_remove_recursive(dir);
+
+ return err;
+}
+
+static void err_inject_exit(void)
+{
+ unregister_pm_notifier(&pm_notifier_err_inject.nb);
+ debugfs_remove_recursive(dir);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_DESCRIPTION("PM notifier error injection module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
--
1.7.10.2
^ permalink raw reply related
* [PATCH -v4 1/6] fault-injection: notifier error injection
From: Akinobu Mita @ 2012-06-23 14:58 UTC (permalink / raw)
To: linux-kernel, akpm
Cc: Akinobu Mita, Pavel Machek, Rafael J. Wysocki, linux-pm, Greg KH,
linux-mm, Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev,
Michael Ellerman
In-Reply-To: <1340463502-15341-1-git-send-email-akinobu.mita@gmail.com>
The notifier error injection provides the ability to inject artifical
errors to specified notifier chain callbacks. It is useful to test the
error handling of notifier call chain failures.
This adds common basic functions to define which type of events can be
fail and to initialize the debugfs interface to control what error code
should be returned and which event should be failed.
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: linux-pm@lists.linux-foundation.org
Cc: Greg KH <greg@kroah.com>
Cc: linux-mm@kvack.org
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: Michael Ellerman <michael@ellerman.id.au>
---
* v4
- prefix all APIs with notifier_err_inject_*
- rearrange debugfs interface
(e.g. $DEBUGFS/cpu-notifier-error-inject/CPU_DOWN_PREPARE -->
$DEBUGFS/notifier-error-inject/cpu/actions/CPU_DOWN_PREPARE/error)
lib/Kconfig.debug | 11 +++++
lib/Makefile | 1 +
lib/notifier-error-inject.c | 112 +++++++++++++++++++++++++++++++++++++++++++
lib/notifier-error-inject.h | 24 ++++++++++
4 files changed, 148 insertions(+)
create mode 100644 lib/notifier-error-inject.c
create mode 100644 lib/notifier-error-inject.h
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ff5bdee..c848758 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1084,6 +1084,17 @@ config LKDTM
Documentation on how to use the module can be found in
Documentation/fault-injection/provoke-crashes.txt
+config NOTIFIER_ERROR_INJECTION
+ tristate "Notifier error injection"
+ depends on DEBUG_KERNEL
+ select DEBUG_FS
+ help
+ This option provides the ability to inject artifical errors to
+ specified notifier chain callbacks. It is useful to test the error
+ handling of notifier call chain failures.
+
+ Say N if unsure.
+
config CPU_NOTIFIER_ERROR_INJECT
tristate "CPU notifier error injection module"
depends on HOTPLUG_CPU && DEBUG_KERNEL
diff --git a/lib/Makefile b/lib/Makefile
index 8c31a0c..23fba9e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -90,6 +90,7 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
+obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o
obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o
lib-$(CONFIG_GENERIC_BUG) += bug.o
diff --git a/lib/notifier-error-inject.c b/lib/notifier-error-inject.c
new file mode 100644
index 0000000..44b92cb
--- /dev/null
+++ b/lib/notifier-error-inject.c
@@ -0,0 +1,112 @@
+#include <linux/module.h>
+
+#include "notifier-error-inject.h"
+
+static int debugfs_errno_set(void *data, u64 val)
+{
+ *(int *)data = clamp_t(int, val, -MAX_ERRNO, 0);
+ return 0;
+}
+
+static int debugfs_errno_get(void *data, u64 *val)
+{
+ *val = *(int *)data;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_errno, debugfs_errno_get, debugfs_errno_set,
+ "%lld\n");
+
+static struct dentry *debugfs_create_errno(const char *name, mode_t mode,
+ struct dentry *parent, int *value)
+{
+ return debugfs_create_file(name, mode, parent, value, &fops_errno);
+}
+
+static int notifier_err_inject_callback(struct notifier_block *nb,
+ unsigned long val, void *p)
+{
+ int err = 0;
+ struct notifier_err_inject *err_inject =
+ container_of(nb, struct notifier_err_inject, nb);
+ struct notifier_err_inject_action *action;
+
+ for (action = err_inject->actions; action->name; action++) {
+ if (action->val == val) {
+ err = action->error;
+ break;
+ }
+ }
+ if (err)
+ pr_info("Injecting error (%d) to %s\n", err, action->name);
+
+ return notifier_from_errno(err);
+}
+
+struct dentry *notifier_err_inject_dir;
+EXPORT_SYMBOL_GPL(notifier_err_inject_dir);
+
+struct dentry *notifier_err_inject_init(const char *name, struct dentry *parent,
+ struct notifier_err_inject *err_inject, int priority)
+{
+ struct notifier_err_inject_action *action;
+ mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+ struct dentry *dir;
+ struct dentry *actions_dir;
+
+ err_inject->nb.notifier_call = notifier_err_inject_callback;
+ err_inject->nb.priority = priority;
+
+ dir = debugfs_create_dir(name, parent);
+ if (!dir)
+ return ERR_PTR(-ENOMEM);
+
+ actions_dir = debugfs_create_dir("actions", dir);
+ if (!actions_dir)
+ goto fail;
+
+ for (action = err_inject->actions; action->name; action++) {
+ struct dentry *action_dir;
+
+ action_dir = debugfs_create_dir(action->name, actions_dir);
+ if (!action_dir)
+ goto fail;
+
+ /*
+ * Create debugfs r/w file containing action->error. If
+ * notifier call chain is called with action->val, it will
+ * fail with the error code
+ */
+ if (!debugfs_create_errno("error", mode, action_dir,
+ &action->error))
+ goto fail;
+ }
+ return dir;
+fail:
+ debugfs_remove_recursive(dir);
+ return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL_GPL(notifier_err_inject_init);
+
+static int __init err_inject_init(void)
+{
+ notifier_err_inject_dir =
+ debugfs_create_dir("notifier-error-inject", NULL);
+
+ if (!notifier_err_inject_dir)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void __exit err_inject_exit(void)
+{
+ debugfs_remove_recursive(notifier_err_inject_dir);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_DESCRIPTION("Notifier error injection module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
diff --git a/lib/notifier-error-inject.h b/lib/notifier-error-inject.h
new file mode 100644
index 0000000..99b3b6f
--- /dev/null
+++ b/lib/notifier-error-inject.h
@@ -0,0 +1,24 @@
+#include <linux/atomic.h>
+#include <linux/debugfs.h>
+#include <linux/notifier.h>
+
+struct notifier_err_inject_action {
+ unsigned long val;
+ int error;
+ const char *name;
+};
+
+#define NOTIFIER_ERR_INJECT_ACTION(action) \
+ .name = #action, .val = (action),
+
+struct notifier_err_inject {
+ struct notifier_block nb;
+ struct notifier_err_inject_action actions[];
+ /* The last slot must be terminated with zero sentinel */
+};
+
+extern struct dentry *notifier_err_inject_dir;
+
+extern struct dentry *notifier_err_inject_init(const char *name,
+ struct dentry *parent, struct notifier_err_inject *err_inject,
+ int priority);
--
1.7.10.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH -v4 0/6] notifier error injection
From: Akinobu Mita @ 2012-06-23 14:58 UTC (permalink / raw)
To: linux-kernel, akpm
Cc: Michael Ellerman, Greg KH, Akinobu Mita, linux-mm, Paul Mackerras,
Américo Wang, linux-pm, linuxppc-dev
This provides kernel modules that can be used to test the error handling
of notifier call chain failures by injecting artifical errors to the
following notifier chain callbacks.
* CPU notifier
* PM notifier
* memory hotplug notifier
* powerpc pSeries reconfig notifier
Example: Inject CPU offline error (-1 == -EPERM)
# cd /sys/kernel/debug/notifier-error-inject/cpu
# echo -1 > actions/CPU_DOWN_PREPARE/error
# echo 0 > /sys/devices/system/cpu/cpu1/online
bash: echo: write error: Operation not permitted
There are also handy shell scripts to test CPU and memory hotplug notifier.
Note that these tests didn't detect error handling bugs on my machine but
I still think this feature is usefull to test the code path which is rarely
executed.
Changelog:
* v4 (It is about 11 months since v3)
- prefix all APIs with notifier_err_inject_*
- rearrange debugfs interface
(e.g. $DEBUGFS/cpu-notifier-error-inject/CPU_DOWN_PREPARE -->
$DEBUGFS/notifier-error-inject/cpu/actions/CPU_DOWN_PREPARE/error)
- update modules to follow new interface
- add -r option for memory-notifier.sh to specify percent of offlining
memory blocks
* v3
- rewrite to be kernel modules instead of initializing at late_initcall()s
(it makes the diffstat look different but most code remains unchanged)
- export err_inject_notifier_block_{init,cleanup} for modules
- export pSeries_reconfig_notifier_{,un}register symbols for a module
- notifier priority can be specified as a module parameter
- add testing scripts in tools/testing/fault-injection
* v2
- "PM: Improve error code of pm_notifier_call_chain()" is now in -next
- "debugfs: add debugfs_create_int" is dropped
- put a comment in err_inject_notifier_block_init()
- only allow valid errno to be injected (-MAX_ERRNO <= errno <= 0)
- improve Kconfig help text
- make CONFIG_PM_NOTIFIER_ERROR_INJECTION visible even if PM_DEBUG is disabled
- make CONFIG_PM_NOTIFIER_ERROR_INJECTION default if PM_DEBUG is enabled
Akinobu Mita (6):
fault-injection: notifier error injection
cpu: rewrite cpu-notifier-error-inject module
PM: PM notifier error injection module
memory: memory notifier error injection module
powerpc: pSeries reconfig notifier error injection module
fault-injection: add notifier error injection testing scripts
lib/Kconfig.debug | 91 ++++++++++-
lib/Makefile | 5 +
lib/cpu-notifier-error-inject.c | 63 +++-----
lib/memory-notifier-error-inject.c | 48 ++++++
lib/notifier-error-inject.c | 112 ++++++++++++++
lib/notifier-error-inject.h | 24 +++
lib/pSeries-reconfig-notifier-error-inject.c | 51 +++++++
lib/pm-notifier-error-inject.c | 49 ++++++
tools/testing/fault-injection/cpu-notifier.sh | 169 +++++++++++++++++++++
tools/testing/fault-injection/memory-notifier.sh | 176 ++++++++++++++++++++++
10 files changed, 748 insertions(+), 40 deletions(-)
create mode 100644 lib/memory-notifier-error-inject.c
create mode 100644 lib/notifier-error-inject.c
create mode 100644 lib/notifier-error-inject.h
create mode 100644 lib/pSeries-reconfig-notifier-error-inject.c
create mode 100644 lib/pm-notifier-error-inject.c
create mode 100755 tools/testing/fault-injection/cpu-notifier.sh
create mode 100755 tools/testing/fault-injection/memory-notifier.sh
Cc: Pavel Machek <pavel@ucw.cz>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: linux-pm@lists.linux-foundation.org
Cc: Greg KH <greg@kroah.com>
Cc: linux-mm@kvack.org
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: Américo Wang <xiyou.wangcong@gmail.com>
Cc: Michael Ellerman <michael@ellerman.id.au>
--
1.7.10.2
^ permalink raw reply
* Re: [RFC PATCH v2 03/11] mfd: omap: control: core system control driver
From: Konstantin Baydarov @ 2012-06-20 14:13 UTC (permalink / raw)
To: Tony Lindgren
Cc: b-cousson, kishon, santosh.shilimkar, paul, balbi, amit.kucheria,
linux-pm, linux-arm-kernel, linux-omap, amit.kachhap,
Eduardo Valentin, J Keerthy
In-Reply-To: <20120620102224.GZ12766@atomide.com>
Hi, Tony.
On 06/20/2012 02:22 PM, Tony Lindgren wrote:
> * Konstantin Baydarov <kbaidarov@dev.rtsoft.ru> [120618 04:36]:
>> This patch introduces a MFD core device driver for
>> OMAP system control module.
>>
>> The control module allows software control of
>> various static modes supported by the device. It is
>> composed of two control submodules: general control
>> module and device (padconfiguration) control
>> module.
>> +++ linux-2.6/drivers/mfd/omap-control-core.c
> ...
>
>
>> +u32 omap_control_readl(u16 offset)
>> +{
>> + return __raw_readl(omap_control_base + (offset));
>> +}
>> +
>> +void omap_control_writel(u32 val, u16 offset)
>> +{
>> + __raw_writel(val, omap_control_base + (offset));
>> +}
> There should not be any need to have the individual drivers use
> these. Please instead just set up something where individual drivers
> register with the control module core, and get their own iobase
> returned so they can use readl/writel and behave like normal device
> drivers.
IIUC one of the reasons drivers/mfd/omap-control-core.c introduction is replacement of arch/arm/mach-omap2/control.c. control.c provides omap_ctrl_readl/omap_ctrl_writel API which are heavily used in arch/arm/mach-omap2/:
arch/arm/mach-omap2/hsmmc.c
arch/arm/mach-omap2/usb-fs.c
arch/arm/mach-omap2/sr_device.c
arch/arm/mach-omap2/id.c
...
So,the same API set (omap_control_readl/omap_control_writel) was added to omap-control-core.c.
If omap-control-core.c should only service users from driver/ directory, than I agree - we can remove
omap_control_readl/omap_control_writel from omap-control-core.c.
But IIUC you are agree to "switch" arch/arm/mach-omap2/id.c from control.c to omap-control-core.c. If arch/arm/mach-omap2/id.c is switched to control.c, then I guess all arch/arm/mach-omap2/*.c should be "switched" to omap-control-core.c as well. But this means that omap-control-core.c should provide omap_control_readl/omap_control_writel API.
BR,
Konstantin Baydarov.
>
> Regards,
>
> Tony
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC PATCH v2 06/11] ARM: OMAP4+: Adding the temperature sensor register set bit fields
From: Tony Lindgren @ 2012-06-20 10:25 UTC (permalink / raw)
To: Konstantin Baydarov
Cc: Keerthy, amit.kucheria, kishon, balbi, linux-pm, linux-omap,
linux-arm-kernel
In-Reply-To: <4FDF11CD.2090101@dev.rtsoft.ru>
* Konstantin Baydarov <kbaidarov@dev.rtsoft.ru> [120618 04:36]:
> OMAP4460 specific temperature sensor register bit fields are added.
> Existing OMAP4 entries are renamed to OMAP4430.
>
> Signed-off-by: Keerthy <j-keerthy@ti.com>
> Signed-off-by: Eduardo Valentin <eduardo.valentin@ti.com>
> ---
> arch/arm/mach-omap2/include/mach/control.h | 116 ++++++++++++++++++++++++++++
> 1 files changed, 116 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/include/mach/control.h b/arch/arm/mach-omap2/include/mach/control.h
> index cf42764..171b504 100644
> --- a/arch/arm/mach-omap2/include/mach/control.h
> +++ b/arch/arm/mach-omap2/include/mach/control.h
> @@ -230,6 +230,122 @@
> /* OMAP44xx control McBSP padconf */
> #define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP 0x061c
>
> +/* TEMP_SENSOR OMAP4430 */
> +#define OMAP4430_BGAP_TEMPSOFF_SHIFT 12
> +#define OMAP4430_BGAP_TEMPSOFF_MASK (1 << 12)
> +#define OMAP4430_BGAP_TSHUT_SHIFT 11
> +#define OMAP4430_BGAP_TSHUT_MASK (1 << 11)
> +#define OMAP4430_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 10
> +#define OMAP4430_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 10)
> +#define OMAP4430_BGAP_TEMP_SENSOR_SOC_SHIFT 9
> +#define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9)
> +#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8
> +#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8)
> +#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
> +#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0)
> +
> +/* TEMP_SENSOR OMAP4460 */
> +#define OMAP4460_BGAP_TEMPSOFF_SHIFT 13
> +#define OMAP4460_BGAP_TEMPSOFF_MASK (1 << 13)
> +#define OMAP4460_BGAP_TEMP_SENSOR_SOC_SHIFT 11
> +#define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK (1 << 11)
> +#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_SHIFT 10
> +#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 10)
> +#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
> +#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
> +
> +/* BANDGAP_CTRL */
> +#define OMAP4460_SINGLE_MODE_SHIFT 31
> +#define OMAP4460_SINGLE_MODE_MASK (1 << 31)
> +#define OMAP4460_MASK_HOT_SHIFT 1
> +#define OMAP4460_MASK_HOT_MASK (1 << 1)
> +#define OMAP4460_MASK_COLD_SHIFT 0
> +#define OMAP4460_MASK_COLD_MASK (1 << 0)
> +
> +/* BANDGAP_COUNTER */
> +#define OMAP4460_COUNTER_SHIFT 0
> +#define OMAP4460_COUNTER_MASK (0xffffff << 0)
> +
> +/* BANDGAP_THRESHOLD */
> +#define OMAP4460_T_HOT_SHIFT 16
> +#define OMAP4460_T_HOT_MASK (0x3ff << 16)
> +#define OMAP4460_T_COLD_SHIFT 0
> +#define OMAP4460_T_COLD_MASK (0x3ff << 0)
These should be all private to the bandgap driver. The same applies
for other driver specific registers for other drivers.
Tony
^ permalink raw reply
* Re: [RFC PATCH v2 04/11] OMAP2+: use control module mfd driver in omap_type
From: Tony Lindgren @ 2012-06-20 10:24 UTC (permalink / raw)
To: Konstantin Baydarov
Cc: b-cousson, kishon, santosh.shilimkar, paul, balbi, amit.kucheria,
linux-pm, linux-arm-kernel, linux-omap, amit.kachhap,
Eduardo Valentin
In-Reply-To: <4FDF11C6.6000400@dev.rtsoft.ru>
* Konstantin Baydarov <kbaidarov@dev.rtsoft.ru> [120618 04:36]:
> OMAP system control module can be probed early, then
> omap_type is safe to use its APIs.
>
> TODO: add support for other omap versions
>
> Signed-off-by: Konstantin Baydarov <kbaidarov@dev.rtsoft.ru>
>
> ---
> arch/arm/mach-omap2/id.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> Index: linux-2.6/arch/arm/mach-omap2/id.c
> ===================================================================
> --- linux-2.6.orig/arch/arm/mach-omap2/id.c
> +++ linux-2.6/arch/arm/mach-omap2/id.c
> @@ -18,6 +18,7 @@
> #include <linux/kernel.h>
> #include <linux/init.h>
> #include <linux/io.h>
> +#include <linux/mfd/omap_control.h>
>
> #include <asm/cputype.h>
>
> @@ -38,6 +39,8 @@ unsigned int omap_rev(void)
> }
> EXPORT_SYMBOL(omap_rev);
>
> +u32 omap_control_readl(u16 offset);
> +
> int omap_type(void)
> {
> u32 val = 0;
> @@ -49,7 +52,7 @@ int omap_type(void)
> } else if (cpu_is_omap34xx()) {
> val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
> } else if (cpu_is_omap44xx()) {
> - val = omap_ctrl_readl(OMAP4_CTRL_MODULE_CORE_STATUS);
> + val = omap_control_readl(OMAP4_CTRL_MODULE_CORE_STATUS);
Please just set up a function in the ctrl module core to return the
status so you can get rid of omap_control_readl here.
Tony
^ permalink raw reply
* Re: [RFC PATCH v2 03/11] mfd: omap: control: core system control driver
From: Tony Lindgren @ 2012-06-20 10:22 UTC (permalink / raw)
To: Konstantin Baydarov
Cc: J Keerthy, amit.kucheria, kishon, balbi, linux-pm, linux-omap,
linux-arm-kernel
In-Reply-To: <4FDF11C3.4010701@dev.rtsoft.ru>
* Konstantin Baydarov <kbaidarov@dev.rtsoft.ru> [120618 04:36]:
> This patch introduces a MFD core device driver for
> OMAP system control module.
>
> The control module allows software control of
> various static modes supported by the device. It is
> composed of two control submodules: general control
> module and device (padconfiguration) control
> module.
> +++ linux-2.6/drivers/mfd/omap-control-core.c
...
> +u32 omap_control_readl(u16 offset)
> +{
> + return __raw_readl(omap_control_base + (offset));
> +}
> +
> +void omap_control_writel(u32 val, u16 offset)
> +{
> + __raw_writel(val, omap_control_base + (offset));
> +}
There should not be any need to have the individual drivers use
these. Please instead just set up something where individual drivers
register with the control module core, and get their own iobase
returned so they can use readl/writel and behave like normal device
drivers.
Regards,
Tony
^ permalink raw reply
* Re: [RFC PATCH v2 02/11] ARM: OMAP: expose control.h to mach area
From: Tony Lindgren @ 2012-06-20 10:17 UTC (permalink / raw)
To: Konstantin Baydarov
Cc: b-cousson, kishon, santosh.shilimkar, paul, balbi, amit.kucheria,
linux-pm, linux-arm-kernel, linux-omap, amit.kachhap,
Eduardo Valentin
In-Reply-To: <4FDF11C0.4090908@dev.rtsoft.ru>
* Konstantin Baydarov <kbaidarov@dev.rtsoft.ru> [120618 04:36]:
> This patch exposes the definitions under control.h to
> drivers outside the machine code.
As discussed earlier, this will likely lead into misuse of these
registers that will be a big mess to clean up.
Can't you make these private to the driver(s)?
Tony
^ permalink raw reply
* Re: [RFC PATCH 11/12] thermal: introduce cooling state arbitrator
From: Zhang Rui @ 2012-06-20 6:47 UTC (permalink / raw)
To: eduardo.valentin; +Cc: linux-acpi@vger.kernel.org, linux-pm
In-Reply-To: <20120613142316.GB16714@besouro>
On 三, 2012-06-13 at 17:23 +0300, Eduardo Valentin wrote:
> Hello Rui,
>
> On Mon, Jun 11, 2012 at 11:20:39AM +0800, Zhang Rui wrote:
> >
> > Introduce simple arbitrator for setting device cooling state,
> > to fix the problem that a cooling device may be referenced by
> > by multiple trip points in multiple thermal zones.
> >
> >
> > With this patch, we have two stages for updating a thermal zone,
> > 1. check if a thermal_instance needs to be updated or not
> > 2. update the cooling device, based on the target cooling state
> > of all its instances.
> >
> > Note that, currently, the cooling device is set to the deepest
> > cooling state required.
> >
> > Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> > ---
> > drivers/thermal/thermal_sys.c | 41 ++++++++++++++++++++++++++++++++++++++---
> > include/linux/thermal.h | 1 +
> > 2 files changed, 39 insertions(+), 3 deletions(-)
> >
> > Index: rtd3/drivers/thermal/thermal_sys.c
> > ===================================================================
> > --- rtd3.orig/drivers/thermal/thermal_sys.c
> > +++ rtd3/drivers/thermal/thermal_sys.c
> > @@ -54,6 +54,7 @@ struct thermal_instance {
> > int trip;
> > unsigned long upper; /* Highest cooling state for this trip point */
> > unsigned long lower; /* Lowest cooling state for this trip point */
> > + unsigned long target; /* expected cooling state */
> > char attr_name[THERMAL_NAME_LENGTH];
> > struct device_attribute attr;
> > struct list_head tz_node; /* node in tz->instances */
> > @@ -812,6 +813,7 @@ int thermal_zone_bind_cooling_device(str
> > dev->trip = trip;
> > dev->upper = upper;
> > dev->lower = lower;
> > + dev->target = -1;
> >
> > result = get_idr(&tz->idr, &tz->lock, &dev->id);
> > if (result)
> > @@ -949,6 +951,7 @@ thermal_cooling_device_register(char *ty
> > strcpy(cdev->type, type);
> > INIT_LIST_HEAD(&cdev->instances);
> > cdev->ops = ops;
> > + cdev->updated = 1;
> > cdev->device.class = &thermal_class;
> > cdev->devdata = devdata;
> > dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> > @@ -1040,6 +1043,32 @@ void thermal_cooling_device_unregister(s
> > }
> > EXPORT_SYMBOL(thermal_cooling_device_unregister);
> >
> > +static void thermal_zone_do_update(struct thermal_zone_device *tz)
> > +{
> > + struct thermal_instance *instance1, *instance2;
> > + struct thermal_cooling_device *cdev;
> > + int target;
> > +
> > + list_for_each_entry(instance1, &tz->instances, tz_node) {
> > + cdev = instance1->cdev;
> > +
> > + /* cooling device has already been updated*/
> > + if (cdev->updated)
> > + continue;
> > +
> > + target = 0;
> > + /* Make sure cdev enters the deepest cooling state */
> > + list_for_each_entry(instance2, &cdev->instances, cdev_node) {
> > + if (instance2->target == -1)
> > + continue;
> > + if (instance2->target > target)
> > + target = instance2->target;
> > + }
> > + cdev->ops->set_cur_state(cdev, target);
> > + cdev->updated = 1;
> > + }
> > +}
>
> I think the above arbitrator solution does not escalate. As I can see,
> the arbitrator takes care of cooling device instances in the same thermal zone.
>
why?
It parses the thermal instances in one thermal zone to find the cooling
devices, and then parse all the thermal instances for the cooling
devices, no matter which thermal zone it belongs to.
> What if you have a device which expose cooling device instances in different
> thermal zones?
>
> Besides, the thermal constraint might collide with pm QoS or with settings
> coming from user space interfaces.
>
> That's actually why I was suggesting to have this 'arbitrator' or constraint
> management outside the thermal framework. And managed per device at some
> other abstraction layer.
>
Yeah, but I think we can have an incremental patch to handle the pm Qos
constrains. Especially Durga already has the governor patches to move
this out of the thermal framework.
what do you think?
thanks,
rui
> > +
> > /*
> > * Cooling algorithm for active trip points
> > *
> > @@ -1086,19 +1115,24 @@ static void thermal_zone_trip_update(str
> > cur_state = cur_state > instance->lower ?
> > (cur_state - 1) : instance->lower;
> > }
> > - cdev->ops->set_cur_state(cdev, cur_state);
> > + instance->target = cur_state;
> > + cdev->updated = 0; /* cooling device needs update */
> > }
> > } else { /* below trip */
> > list_for_each_entry(instance, &tz->instances, tz_node) {
> > if (instance->trip != trip)
> > continue;
> >
> > + /* Do not use the deacitve thermal instance */
> > + if (instance->target == -1)
> > + continue;
> > cdev = instance->cdev;
> > cdev->ops->get_cur_state(cdev, &cur_state);
> >
> > cur_state = cur_state > instance->lower ?
> > - (cur_state - 1) : instance->lower;
> > - cdev->ops->set_cur_state(cdev, cur_state);
> > + (cur_state - 1) : -1;
> > + instance->target = cur_state;
> > + cdev->updated = 0; /* cooling device needs update */
> > }
> > }
> >
> > @@ -1159,6 +1193,7 @@ void thermal_zone_device_update(struct t
> > }
> > }
> >
> > + thermal_zone_do_update(tz);
> > if (tz->forced_passive)
> > thermal_zone_device_passive(tz, temp, tz->forced_passive,
> > THERMAL_TRIPS_NONE);
> > Index: rtd3/include/linux/thermal.h
> > ===================================================================
> > --- rtd3.orig/include/linux/thermal.h
> > +++ rtd3/include/linux/thermal.h
> > @@ -86,6 +86,7 @@ struct thermal_cooling_device {
> > struct device device;
> > void *devdata;
> > const struct thermal_cooling_device_ops *ops;
> > + int updated; /* 1 if the cooling device does not need update */
> > struct list_head instances;
> > struct list_head node;
> > };
> >
> >
^ permalink raw reply
* Re: [PATCH] ACPI, cpuidle: Fix suspend/resume regression caused by cpuidle cleanup.
From: Rafael J. Wysocki @ 2012-06-19 20:35 UTC (permalink / raw)
To: Deepthi Dharwar
Cc: Dave Hansen, Linux PM mailing list, linux-pm, linux-acpi,
Len Brown, Jean Pihet, Arjan van de Ven, Kevin Hilman,
Arnd Bergmann, Ferenc Wagner, Tomas M., Srivatsa S. Bhat, preeti
In-Reply-To: <4FD87249.6010302@linux.vnet.ibm.com>
On Wednesday, June 13, 2012, Deepthi Dharwar wrote:
>
> From: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
>
> Fix suspend/resume regression caused by cpuidle cleanup.
>
> Commit e978aa7d7d57d04eb5f88a7507c4fb98577def77 ( cpuidle: Move
> dev->last_residency update to driver enter routine; remove dev->last_state)
> was breaking suspend on laptops, as reported in the below link
> - https://lkml.org/lkml/2011/11/11/164
>
> This was fixed in commit 3439a8da16bcad6b0982ece938c9f8299bb53584
> (ACPI / cpuidle: Remove acpi_idle_suspend (to fix suspend regression)
> by removing acpi_idle_suspend flag.
> - https://lkml.org/lkml/2011/11/14/74
>
> But this fix did not work on all systems
> as Suspend/resume regression was reported on Lenovo S10-3
> recently by Dave.
> - https://lkml.org/lkml/2012/5/27/115
> It looked like with commit e978aa7d broke suspend and
> with commit 3439a8da resume was not working with acpi_idle driver.
>
> This patch fixes the regression that caused this issue
> in the first place. acpi_idle_suspend flag is essential on
> some x86 systems to prevent the cpus from going to deeper C-states
> when suspend is triggered ( commit b04e7bdb984 )
> So reverting the commit 3439a8da is essential.
>
> By default, irqs are disabled in cpu_idle arch specific call
> and re-enabled in idle state return path . As the acpi_idle_suspend
> flag was being set during suspend, which prevented the cpus
> going to deeper idle states, it is essential to
> enabling the irqs in its return path too.
>
> To address the suspend issue,
> we were not re-enabling the interrupts while returning from
> acpi_idle_enter_bm() routine if acpi_idle_suspend flag is set.
> and this was causing suspend failure.
>
> In addition to the above fix, a sanity check has also been added
> in x86 arch specific cpu_idle call to ensure that the idle call
> always returns with IRQs enabled.
>
> This patch applies on 3.5-rc2
> ---
>
> Reported-and-Tested-by: Dav Hansen <dave@linux.vnet.ibm.com>
> Tested-by: Preeti Murthy <preeti@linux.vnet.ibm.com>
> Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
> Reviewed-by: Srivatsa S Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Applied to linux-pm/linux-next, will be pushed to Linus later this week.
Thanks,
Rafael
> ---
> arch/x86/kernel/process.c | 6 ++++++
> drivers/acpi/processor_idle.c | 28 ++++++++++++++++++++++++++++
> 2 files changed, 34 insertions(+), 0 deletions(-)
>
> diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
> index 735279e..8ab76ad 100644
> --- a/arch/x86/kernel/process.c
> +++ b/arch/x86/kernel/process.c
> @@ -460,6 +460,12 @@ void cpu_idle(void)
> pm_idle();
>
> rcu_idle_exit();
> +
> + /*
> + * Sanity check to ensure that idle call returns
> + * with IRQs enabled
> + */
> + WARN_ON(irqs_disabled());
> start_critical_timings();
>
> /* In many cases the interrupt that ended idle
> diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
> index f3decb3..c2ffd84 100644
> --- a/drivers/acpi/processor_idle.c
> +++ b/drivers/acpi/processor_idle.c
> @@ -224,6 +224,7 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
> /*
> * Suspend / resume control
> */
> +static int acpi_idle_suspend;
> static u32 saved_bm_rld;
>
> static void acpi_idle_bm_rld_save(void)
> @@ -242,13 +243,21 @@ static void acpi_idle_bm_rld_restore(void)
>
> int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
> {
> + if (acpi_idle_suspend == 1)
> + return 0;
> +
> acpi_idle_bm_rld_save();
> + acpi_idle_suspend = 1;
> return 0;
> }
>
> int acpi_processor_resume(struct acpi_device * device)
> {
> + if (acpi_idle_suspend == 0)
> + return 0;
> +
> acpi_idle_bm_rld_restore();
> + acpi_idle_suspend = 0;
> return 0;
> }
>
> @@ -754,6 +763,12 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
>
> local_irq_disable();
>
> + if (acpi_idle_suspend) {
> + local_irq_enable();
> + cpu_relax();
> + return -EINVAL;
> + }
> +
> lapic_timer_state_broadcast(pr, cx, 1);
> kt1 = ktime_get_real();
> acpi_idle_do_entry(cx);
> @@ -823,6 +838,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
>
> local_irq_disable();
>
> + if (acpi_idle_suspend) {
> + local_irq_enable();
> + cpu_relax();
> + return -EINVAL;
> + }
> +
> if (cx->entry_method != ACPI_CSTATE_FFH) {
> current_thread_info()->status &= ~TS_POLLING;
> /*
> @@ -901,6 +922,13 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
> if (unlikely(!pr))
> return -EINVAL;
>
> + if (acpi_idle_suspend) {
> + if (irqs_disabled())
> + local_irq_enable();
> + cpu_relax();
> + return -EINVAL;
> + }
> +
> if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
> if (drv->safe_state_index >= 0) {
> return drv->states[drv->safe_state_index].enter(dev,
>
> Regards,
> Deepthi
>
>
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox