Linux Power Management development
 help / color / mirror / Atom feed
* Re: [PATCH] PM / OPP: Export symbols for module usage.
From: Rafael J. Wysocki @ 2012-10-24 21:55 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: Nishanth Menon, linux-pm, Liam Girdwood, linux-kernel
In-Reply-To: <87k3uwagby.fsf@deeprootsystems.com>

On Thursday 11 of October 2012 13:45:05 Kevin Hilman wrote:
> Nishanth Menon <nm@ti.com> writes:
> 
> > From: Liam Girdwood <lrg@ti.com>
> >
> > Export the OPP functions for use by driver modules.
> >
> > Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
> > Cc: Kevin Hilman <khilman@ti.com>
> > Cc: linux-pm@vger.kernel.org
> > Cc: linux-kernel@vger.kernel.org
> >
> > [nm@ti.com: expansion of functions exported]
> > Signed-off-by: Nishanth Menon <nm@ti.com>
> > Signed-off-by: Liam Girdwood <lrg@ti.com>
> 
> Acked-by: Kevin Hilman <khilman@ti.com>

Applied to linux-pm.git/linux-next as v3.8 material.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [PATCH] cpufreq: fix jiffies/cputime mixup in conservative/ondemand governors
From: Rafael J. Wysocki @ 2012-10-24 21:16 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: cpufreq, linux-pm
In-Reply-To: <m21ugq1vfi.fsf@igel.home>

On Monday 22 of October 2012 15:35:29 Andreas Schwab wrote:
> The function get_cpu_idle_time_jiffy in both the conservative and
> ondemand governors use jiffies_to_usecs to convert a cputime value to
> usecs which gives the wrong value on architectures where cputime and
> jiffies use different units.  Only matters if NO_HZ is disabled, since
> otherwise get_cpu_idle_time_us should already return a valid value, and
> get_cpu_idle_time_jiffy isn't actually called.
> 
> Signed-off-by: Andreas Schwab <schwab@linux-m68k.org>

I have rebased your patch on top of some other changes in linux-pm.git/linux-next.

Please have a look at

http://git.kernel.org/?p=linux/kernel/git/rafael/linux-pm.git;a=shortlog;h=refs/heads/linux-next

and let me know if that's what you meant.

Thanks,
Rafael


> ---
>  drivers/cpufreq/cpufreq_conservative.c | 4 ++--
>  drivers/cpufreq/cpufreq_ondemand.c     | 4 ++--
>  2 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
> index a152af7..96af7d5 100644
> --- a/drivers/cpufreq/cpufreq_conservative.c
> +++ b/drivers/cpufreq/cpufreq_conservative.c
> @@ -112,9 +112,9 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
>  
>  	idle_time = cur_wall_time - busy_time;
>  	if (wall)
> -		*wall = jiffies_to_usecs(cur_wall_time);
> +		*wall = cputime_to_usecs(cur_wall_time);
>  
> -	return jiffies_to_usecs(idle_time);
> +	return cputime_to_usecs(idle_time);
>  }
>  
>  static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
> diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
> index 396322f..6c19a66 100644
> --- a/drivers/cpufreq/cpufreq_ondemand.c
> +++ b/drivers/cpufreq/cpufreq_ondemand.c
> @@ -136,9 +136,9 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
>  
>  	idle_time = cur_wall_time - busy_time;
>  	if (wall)
> -		*wall = jiffies_to_usecs(cur_wall_time);
> +		*wall = cputime_to_usecs(cur_wall_time);
>  
> -	return jiffies_to_usecs(idle_time);
> +	return cputime_to_usecs(idle_time);
>  }
>  
>  static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [PATCH 2/2] cpufreq: governors: remove redundant code
From: Rafael J. Wysocki @ 2012-10-24 21:12 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: cpufreq, linux-pm, linux-kernel, linux-arm-kernel, linaro-dev,
	patches, pdsw-power-team, arvind.chauhan
In-Reply-To: <1597360.JT7plJlUsZ@vostro.rjw.lan>

On Wednesday 24 of October 2012 21:43:46 Rafael J. Wysocki wrote:
> On Wednesday 24 of October 2012 11:37:13 Viresh Kumar wrote:
> > On 22 October 2012 14:16, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > > On 20 October 2012 01:42, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > >> Initially ondemand governor was written and then using its code conservative
> > >> governor is written. It used a lot of code from ondemand governor, but copy of
> > >> code was created instead of using the same routines from both governors. Which
> > >> increased code redundancy, which is difficult to manage.
> > >>
> > >> This patch is an attempt to move common part of both the governors to
> > >> cpufreq_governor.c file to come over above mentioned issues.
> > >>
> > >> This shouldn't change anything from functionality point of view.
> > >>
> > >> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> > 
> > For everybody else, this patch is already pushed by Rafael in his linux-next
> > branch.
> 
> Well, not yet, although I'm going to do that.

Or I would if it still applied.  Unfortunately, though, it doesn't apply any
more to my linux-next branch due to some previous changes in it.

Care to rebase?

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [PATCH 1/2] cpufreq: Fix sparse warnings by updating cputime64_t to u64
From: Rafael J. Wysocki @ 2012-10-24 21:14 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: cpufreq, linux-pm, linaro-dev, patches, pdsw-power-team,
	arvind.chauhan, fengguang.wu
In-Reply-To: <93ed702aba4c33d9a477c7296c59cc2882e16f82.1351064553.git.viresh.kumar@linaro.org>

On Wednesday 24 of October 2012 13:15:58 Viresh Kumar wrote:
> There were few sparse warnings due to mismatch of type on function arguments.
> Two types were used u64 and cputime64_t. Both are actually u64, so use u64 only.
> 
> Reported-by: Fengguang Wu <fengguang.wu@intel.com>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>

This series appears to be based on your "cpufreq: governors: remove
redundant code" patch that hasn't been applied yet.

Please rebase it on top of linux-pm/linux-next or on top of v3.7-rc2,
whichever is more convenient, and resend.

Thanks,
Rafael


> ---
> 
> This solution was discussed here:
> 
> http://www.mail-archive.com/linaro-dev@lists.linaro.org/msg13744.html
> 
>  drivers/cpufreq/cpufreq_governor.c |  4 ++--
>  drivers/cpufreq/cpufreq_governor.h | 11 +++++------
>  drivers/cpufreq/cpufreq_stats.c    |  4 ++--
>  3 files changed, 9 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
> index cd5fe57..e39bf81 100644
> --- a/drivers/cpufreq/cpufreq_governor.c
> +++ b/drivers/cpufreq/cpufreq_governor.c
> @@ -49,7 +49,7 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
>  	return jiffies_to_usecs(idle_time);
>  }
>  
> -cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
> +u64 get_cpu_idle_time(unsigned int cpu, u64 *wall)
>  {
>  	u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
>  
> @@ -81,7 +81,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
>  	/* Get Absolute Load (in terms of freq for ondemand gov) */
>  	for_each_cpu(j, policy->cpus) {
>  		struct cpu_dbs_common_info *j_cdbs;
> -		cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time;
> +		u64 cur_wall_time, cur_idle_time, cur_iowait_time;
>  		unsigned int idle_time, wall_time, iowait_time;
>  		unsigned int load;
>  
> diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
> index 34e14ad..f661654 100644
> --- a/drivers/cpufreq/cpufreq_governor.h
> +++ b/drivers/cpufreq/cpufreq_governor.h
> @@ -17,7 +17,6 @@
>  #ifndef _CPUFREQ_GOVERNER_H
>  #define _CPUFREQ_GOVERNER_H
>  
> -#include <asm/cputime.h>
>  #include <linux/cpufreq.h>
>  #include <linux/kobject.h>
>  #include <linux/mutex.h>
> @@ -72,9 +71,9 @@ static void *get_cpu_dbs_info_s(int cpu)				\
>  /* Per cpu structures */
>  struct cpu_dbs_common_info {
>  	int cpu;
> -	cputime64_t prev_cpu_idle;
> -	cputime64_t prev_cpu_wall;
> -	cputime64_t prev_cpu_nice;
> +	u64 prev_cpu_idle;
> +	u64 prev_cpu_wall;
> +	u64 prev_cpu_nice;
>  	struct cpufreq_policy *cur_policy;
>  	struct delayed_work work;
>  	/*
> @@ -87,7 +86,7 @@ struct cpu_dbs_common_info {
>  
>  struct od_cpu_dbs_info_s {
>  	struct cpu_dbs_common_info cdbs;
> -	cputime64_t prev_cpu_iowait;
> +	u64 prev_cpu_iowait;
>  	struct cpufreq_frequency_table *freq_table;
>  	unsigned int freq_lo;
>  	unsigned int freq_lo_jiffies;
> @@ -170,7 +169,7 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate)
>  	return delay;
>  }
>  
> -cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall);
> +u64 get_cpu_idle_time(unsigned int cpu, u64 *wall);
>  void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
>  int cpufreq_governor_dbs(struct dbs_data *dbs_data,
>  		struct cpufreq_policy *policy, unsigned int event);
> diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
> index b40ee14..683a48f 100644
> --- a/drivers/cpufreq/cpufreq_stats.c
> +++ b/drivers/cpufreq/cpufreq_stats.c
> @@ -37,7 +37,7 @@ struct cpufreq_stats {
>  	unsigned int max_state;
>  	unsigned int state_num;
>  	unsigned int last_index;
> -	cputime64_t *time_in_state;
> +	u64 *time_in_state;
>  	unsigned int *freq_table;
>  #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
>  	unsigned int *trans_table;
> @@ -223,7 +223,7 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
>  		count++;
>  	}
>  
> -	alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
> +	alloc_size = count * sizeof(int) + count * sizeof(u64);
>  
>  #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
>  	alloc_size += count * count * sizeof(int);
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [BUGFIX 1/2] PCI/PM: Fix deadlock when unbind device if its parent in D3cold
From: Rafael J. Wysocki @ 2012-10-24 21:01 UTC (permalink / raw)
  To: Huang Ying; +Cc: Bjorn Helgaas, linux-kernel, linux-pci, linux-pm, Zhang Yanmin
In-Reply-To: <1351061654-8339-1-git-send-email-ying.huang@intel.com>

On Wednesday 24 of October 2012 14:54:13 Huang Ying wrote:
> If a PCI device and its parents are put into D3cold, unbinding the
> device will trigger deadlock as follow:
> 
> - driver_unbind
>   - device_release_driver
>     - device_lock(dev)				<--- previous lock here
>     - __device_release_driver
>       - pm_runtime_get_sync
>         ...
>           - rpm_resume(dev)
>             - rpm_resume(dev->parent)
>               ...
>                 - pci_pm_runtime_resume
>                   ...
>                   - pci_set_power_state
>                     - __pci_start_power_transition
>                       - pci_wakeup_bus(dev->parent->subordinate)
>                         - pci_walk_bus
>                           - device_lock(dev)	<--- dead lock here
> 
> 
> If we do not do device_lock in pci_walk_bus, we can avoid dead lock.
> Device_lock in pci_walk_bus is introduced in commit:
> d71374dafbba7ec3f67371d3b7e9f6310a588808, corresponding email thread
> is: https://lkml.org/lkml/2006/5/26/38.  The patch author Zhang Yanmin
> said device_lock is added to pci_walk_bus because:
> 
>   Some error handling functions call pci_walk_bus. For example, PCIe
>   aer. Here we lock the device, so the driver wouldn't detach from the
>   device, as the cb might call driver's callback function.
> 
> So I fixed the dead lock as follow:
> 
> - remove device_lock from pci_walk_bus
> - add device_lock into callback if callback will call driver's callback
> 
> I checked pci_walk_bus users one by one, and found only PCIe aer needs
> device lock.
> 
> Signed-off-by: Huang Ying <ying.huang@intel.com>
> Cc: Zhang Yanmin <yanmin.zhang@intel.com>

Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

> ---
>  drivers/pci/bus.c                  |    3 ---
>  drivers/pci/pcie/aer/aerdrv_core.c |   20 ++++++++++++++++----
>  2 files changed, 16 insertions(+), 7 deletions(-)
> 
> --- a/drivers/pci/bus.c
> +++ b/drivers/pci/bus.c
> @@ -320,10 +320,7 @@ void pci_walk_bus(struct pci_bus *top, i
>  		} else
>  			next = dev->bus_list.next;
>  
> -		/* Run device routines with the device locked */
> -		device_lock(&dev->dev);
>  		retval = cb(dev, userdata);
> -		device_unlock(&dev->dev);
>  		if (retval)
>  			break;
>  	}
> --- a/drivers/pci/pcie/aer/aerdrv_core.c
> +++ b/drivers/pci/pcie/aer/aerdrv_core.c
> @@ -213,6 +213,7 @@ static int report_error_detected(struct
>  	struct aer_broadcast_data *result_data;
>  	result_data = (struct aer_broadcast_data *) data;
>  
> +	device_lock(&dev->dev);
>  	dev->error_state = result_data->state;
>  
>  	if (!dev->driver ||
> @@ -231,12 +232,14 @@ static int report_error_detected(struct
>  				   dev->driver ?
>  				   "no AER-aware driver" : "no driver");
>  		}
> -		return 0;
> +		goto out;
>  	}
>  
>  	err_handler = dev->driver->err_handler;
>  	vote = err_handler->error_detected(dev, result_data->state);
>  	result_data->result = merge_result(result_data->result, vote);
> +out:
> +	device_unlock(&dev->dev);
>  	return 0;
>  }
>  
> @@ -247,14 +250,17 @@ static int report_mmio_enabled(struct pc
>  	struct aer_broadcast_data *result_data;
>  	result_data = (struct aer_broadcast_data *) data;
>  
> +	device_lock(&dev->dev);
>  	if (!dev->driver ||
>  		!dev->driver->err_handler ||
>  		!dev->driver->err_handler->mmio_enabled)
> -		return 0;
> +		goto out;
>  
>  	err_handler = dev->driver->err_handler;
>  	vote = err_handler->mmio_enabled(dev);
>  	result_data->result = merge_result(result_data->result, vote);
> +out:
> +	device_unlock(&dev->dev);
>  	return 0;
>  }
>  
> @@ -265,14 +271,17 @@ static int report_slot_reset(struct pci_
>  	struct aer_broadcast_data *result_data;
>  	result_data = (struct aer_broadcast_data *) data;
>  
> +	device_lock(&dev->dev);
>  	if (!dev->driver ||
>  		!dev->driver->err_handler ||
>  		!dev->driver->err_handler->slot_reset)
> -		return 0;
> +		goto out;
>  
>  	err_handler = dev->driver->err_handler;
>  	vote = err_handler->slot_reset(dev);
>  	result_data->result = merge_result(result_data->result, vote);
> +out:
> +	device_unlock(&dev->dev);
>  	return 0;
>  }
>  
> @@ -280,15 +289,18 @@ static int report_resume(struct pci_dev
>  {
>  	const struct pci_error_handlers *err_handler;
>  
> +	device_lock(&dev->dev);
>  	dev->error_state = pci_channel_io_normal;
>  
>  	if (!dev->driver ||
>  		!dev->driver->err_handler ||
>  		!dev->driver->err_handler->resume)
> -		return 0;
> +		goto out;
>  
>  	err_handler = dev->driver->err_handler;
>  	err_handler->resume(dev);
> +out:
> +	device_unlock(&dev->dev);
>  	return 0;
>  }
>  
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [PATCH] cpuidle: fix warning when compile
From: Rafael J. Wysocki @ 2012-10-24 21:03 UTC (permalink / raw)
  To: Song, Youquan
  Cc: Wu, Fengguang, yuanhan.liu@linux.intel.com, Rik van Riel,
	linux-pm@vger.kernel.org, Youquan Song
In-Reply-To: <70A3B115BE79814398B8E4E7C4AE18EE13A10B@SHSMSX101.ccr.corp.intel.com>

On Wednesday 24 of October 2012 02:14:13 Song, Youquan wrote:
> >>  	int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */
> 
> >Shouldn't this one be uint64_t too?
> 
> Thanks Rafael!  Fenggung also asked me the similar question. 
> But I think, the compile only complains about do_div() at SH 32bit
> architecture, the above int64_t definition should be OK and I do not
> find any issue without changing it to uint64_t. 

OK

I fixed up the original patch.

Thanks,
Rafael


> -----Original Message-----
> From: Rafael J. Wysocki [mailto:rjw@sisk.pl] 
> Sent: Wednesday, October 24, 2012 8:28 AM
> To: Song, Youquan
> Cc: Wu, Fengguang; yuanhan.liu@linux.intel.com; Rik van Riel; linux-pm@vger.kernel.org; Youquan Song
> Subject: Re: [PATCH] cpuidle: fix warning when compile
> 
> On Tuesday 23 of October 2012 22:45:28 Youquan Song wrote:
> > Fix the warning complain when compile the kernel.
> > 
> > drivers/cpuidle/governors/menu.c: In function 'get_typical_interval':
> > drivers/cpuidle/governors/menu.c:268:2: warning: comparison of 
> > distinct pointer types lacks a cast [enabled by default]
> > drivers/cpuidle/governors/menu.c:277:2: warning: comparison of 
> > distinct pointer types lacks a cast [enabled by default]
> > 
> > Signed-off-by: Youquan Song <youquan.song@intel.com>
> > ---
> >  drivers/cpuidle/governors/menu.c |    2 +-
> >  1 files changed, 1 insertions(+), 1 deletions(-)
> > 
> > diff --git a/drivers/cpuidle/governors/menu.c 
> > b/drivers/cpuidle/governors/menu.c
> > index 26d5667..2efee27 100644
> > --- a/drivers/cpuidle/governors/menu.c
> > +++ b/drivers/cpuidle/governors/menu.c
> > @@ -248,7 +248,7 @@ static enum hrtimer_restart 
> > menu_hrtimer_notify(struct hrtimer *hrtimer)  static u32 
> > get_typical_interval(struct menu_device *data)  {
> >  	int i = 0, divisor = 0;
> > -	int64_t max = 0, avg = 0, stddev = 0;
> > +	uint64_t max = 0, avg = 0, stddev = 0;
> >  	int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */
> 
> Shouldn't this one be uint64_t too?
> 
> >  	unsigned int ret = 0;

-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [BUGFIX 2/2] PCI/PM: Resume device before shutdown
From: Rafael J. Wysocki @ 2012-10-24 21:01 UTC (permalink / raw)
  To: Huang Ying; +Cc: Bjorn Helgaas, linux-kernel, linux-pci, linux-pm
In-Reply-To: <1351061654-8339-2-git-send-email-ying.huang@intel.com>

On Wednesday 24 of October 2012 14:54:14 Huang Ying wrote:
> Some actions during shutdown need device to be in D0 state, such as
> MSI shutdown etc, so resume device before shutdown.
> 
> Signed-off-by: Huang Ying <ying.huang@intel.com>

Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

> ---
>  drivers/pci/pci-driver.c |   12 ++----------
>  1 file changed, 2 insertions(+), 10 deletions(-)
> 
> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -398,6 +398,8 @@ static void pci_device_shutdown(struct d
>  	struct pci_dev *pci_dev = to_pci_dev(dev);
>  	struct pci_driver *drv = pci_dev->driver;
>  
> +	pm_runtime_resume(dev);
> +
>  	if (drv && drv->shutdown)
>  		drv->shutdown(pci_dev);
>  	pci_msi_shutdown(pci_dev);
> @@ -408,16 +410,6 @@ static void pci_device_shutdown(struct d
>  	 * continue to do DMA
>  	 */
>  	pci_disable_device(pci_dev);
> -
> -	/*
> -	 * Devices may be enabled to wake up by runtime PM, but they need not
> -	 * be supposed to wake up the system from its "power off" state (e.g.
> -	 * ACPI S5).  Therefore disable wakeup for all devices that aren't
> -	 * supposed to wake up the system at this point.  The state argument
> -	 * will be ignored by pci_enable_wake().
> -	 */
> -	if (!device_may_wakeup(dev))
> -		pci_enable_wake(pci_dev, PCI_UNKNOWN, false);
>  }
>  
>  #ifdef CONFIG_PM
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [PATCH 2/2] cpufreq: governors: remove redundant code
From: Rafael J. Wysocki @ 2012-10-24 19:43 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: cpufreq, linux-pm, linux-kernel, linux-arm-kernel, linaro-dev,
	patches, pdsw-power-team, arvind.chauhan
In-Reply-To: <CAKohpomUD-JQbkyEom+_BaRqJSvw8P_hBUsrjTU3vH6bM1+scQ@mail.gmail.com>

On Wednesday 24 of October 2012 11:37:13 Viresh Kumar wrote:
> On 22 October 2012 14:16, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > On 20 October 2012 01:42, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> >> Initially ondemand governor was written and then using its code conservative
> >> governor is written. It used a lot of code from ondemand governor, but copy of
> >> code was created instead of using the same routines from both governors. Which
> >> increased code redundancy, which is difficult to manage.
> >>
> >> This patch is an attempt to move common part of both the governors to
> >> cpufreq_governor.c file to come over above mentioned issues.
> >>
> >> This shouldn't change anything from functionality point of view.
> >>
> >> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> 
> For everybody else, this patch is already pushed by Rafael in his linux-next
> branch.

Well, not yet, although I'm going to do that.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [PATCH V2 6/6] Thermal: Add ST-Ericsson DB8500 thermal properties and platform data.
From: Viresh Kumar @ 2012-10-24 14:47 UTC (permalink / raw)
  To: hongbo.zhang
  Cc: linaro-kernel-cunTk1MwBs8s++Sfvej+rw,
	linaro-dev-cunTk1MwBs8s++Sfvej+rw,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, patches-QSEj5FYQhm4dnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	STEricsson_nomadik_linux-nkJGhpqTU55BDgjK7y7TUQ,
	kernel-vMlcbD5RyM6HZuj8yyL1ah2eb7JE58TQ, hongbo.zhang
In-Reply-To: <1351079900-32236-7-git-send-email-hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>

On 24 October 2012 17:28, hongbo.zhang <hongbo.zhang-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> From: "hongbo.zhang" <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>
>
> This patch adds device tree properties for ST-Ericsson DB8500 thermal driver,
> also adds the platform data to support the old fashion.
>
> Signed-off-by: hongbo.zhang <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>
> ---
>  .../devicetree/bindings/thermal/db8500-thermal.txt | 40 ++++++++++++++

It must be included in patch 5/6

>  arch/arm/boot/dts/dbx5x0.dtsi                      | 14 +++++
>  arch/arm/boot/dts/snowball.dts                     | 31 +++++++++++
>  arch/arm/mach-ux500/board-mop500.c                 | 64 ++++++++++++++++++++++
>  4 files changed, 149 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/thermal/db8500-thermal.txt
>
> diff --git a/Documentation/devicetree/bindings/thermal/db8500-thermal.txt b/Documentation/devicetree/bindings/thermal/db8500-thermal.txt
> new file mode 100644
> index 0000000..80d53e6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/db8500-thermal.txt
> @@ -0,0 +1,40 @@
> +* ST-Ericsson DB8500 Thermal
> +
> +** Thermal node properties:
> +
> +- compatible : "stericsson,db8500-thermal";
> +- reg : address range of the thermal sensor registers;
> +- interrupts : interrupts generated form PRCMU;
> +- interrupt-names : "IRQ_HOTMON_LOW" and "IRQ_HOTMON_HIGH";
> +- num-trips : number of total trip points;
> +- tripN-temp : temperature of trip point N;
> +- tripN-type : type of trip point N, should be one of "active" "passive" "hot" "critical";
> +- tripN-cdev-num : number of the cooling devices which can be bound to trip point N;
> +- tripN-cdev-nameM : name of the No. M cooling device of trip point N;
> +
> +Usually the num-trips and tripN-*** are seperated in board related dts files.

s/seperated/separated

> +
> +Example:
> +thermal@801573c0 {
> +       compatible = "stericsson,db8500-thermal";
> +       reg = <0x801573c0 0x40>;
> +       interrupts = <21 0x4>, <22 0x4>;
> +       interrupt-names = "IRQ_HOTMON_LOW", "IRQ_HOTMON_HIGH";
> +
> +       num-trips = <3>;
> +
> +       trip0-temp = <70000>;
> +       trip0-type = "active";
> +       trip0-cdev-num = <1>;
> +       trip0-cdev-name0 = "thermal-cpufreq-0";
> +
> +       trip1-temp = <75000>;
> +       trip1-type = "active";
> +       trip1-cdev-num = <2>;
> +       trip1-cdev-name0 = "thermal-cpufreq-0";
> +       trip1-cdev-name1 = "thermal-fan";
> +
> +       trip2-temp = <85000>;
> +       trip2-type = "critical";
> +       trip2-cdev-num = <0>;
> +}
> diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
> index 748ba7a..949edc2 100644
> --- a/arch/arm/boot/dts/dbx5x0.dtsi
> +++ b/arch/arm/boot/dts/dbx5x0.dtsi
> @@ -203,6 +203,14 @@
>                                 reg = <0x80157450 0xC>;
>                         };
>
> +                       thermal@801573c0 {
> +                               compatible = "stericsson,db8500-thermal";
> +                               reg = <0x801573c0 0x40>;
> +                               interrupts = <21 0x4>, <22 0x4>;
> +                               interrupt-names = "IRQ_HOTMON_LOW", "IRQ_HOTMON_HIGH";
> +                               status = "disabled";
> +                        };
> +
>                         db8500-prcmu-regulators {
>                                 compatible = "stericsson,db8500-prcmu-regulator";
>
> @@ -645,5 +653,11 @@
>                         ranges = <0 0x50000000 0x4000000>;
>                         status = "disabled";
>                 };
> +
> +               cpufreq-cooling {
> +                       compatible = "stericsson,db8500-cpufreq-cooling";
> +                       status = "disabled";
> +                };
> +
>         };
>  };
> diff --git a/arch/arm/boot/dts/snowball.dts b/arch/arm/boot/dts/snowball.dts
> index 702c0ba..c6f85f0 100644
> --- a/arch/arm/boot/dts/snowball.dts
> +++ b/arch/arm/boot/dts/snowball.dts
> @@ -99,6 +99,33 @@
>                         status = "okay";
>                 };
>
> +               prcmu@80157000 {
> +                       thermal@801573c0 {
> +                               num-trips = <4>;
> +
> +                               trip0-temp = <70000>;
> +                               trip0-type = "active";
> +                               trip0-cdev-num = <1>;
> +                               trip0-cdev-name0 = "thermal-cpufreq-0";
> +
> +                               trip1-temp = <75000>;
> +                               trip1-type = "active";
> +                               trip1-cdev-num = <1>;
> +                               trip1-cdev-name0 = "thermal-cpufreq-0";
> +
> +                               trip2-temp = <80000>;
> +                               trip2-type = "active";
> +                               trip2-cdev-num = <1>;
> +                               trip2-cdev-name0 = "thermal-cpufreq-0";
> +
> +                               trip3-temp = <85000>;
> +                               trip3-type = "critical";
> +                               trip3-cdev-num = <0>;
> +
> +                               status = "okay";
> +                        };
> +               };
> +
>                 external-bus@50000000 {
>                         status = "okay";
>
> @@ -183,5 +210,9 @@
>                                 reg = <0x33>;
>                         };
>                 };
> +
> +               cpufreq-cooling {
> +                       status = "okay";
> +               };
>         };
>  };
> diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
> index 416d436..b03216b 100644
> --- a/arch/arm/mach-ux500/board-mop500.c
> +++ b/arch/arm/mach-ux500/board-mop500.c
> @@ -16,6 +16,7 @@
>  #include <linux/io.h>
>  #include <linux/i2c.h>
>  #include <linux/platform_data/i2c-nomadik.h>
> +#include <linux/platform_data/db8500_thermal.h>
>  #include <linux/gpio.h>
>  #include <linux/amba/bus.h>
>  #include <linux/amba/pl022.h>
> @@ -229,6 +230,67 @@ static struct ab8500_platform_data ab8500_platdata = {
>  };
>
>  /*
> + * Thermal Sensor
> + */
> +
> +static struct resource db8500_thsens_resources[] = {
> +       {
> +               .name = "IRQ_HOTMON_LOW",
> +               .start  = IRQ_PRCMU_HOTMON_LOW,
> +               .end    = IRQ_PRCMU_HOTMON_LOW,
> +               .flags  = IORESOURCE_IRQ,
> +       },
> +       {

I prefer }, {

> +               .name = "IRQ_HOTMON_HIGH",
> +               .start  = IRQ_PRCMU_HOTMON_HIGH,
> +               .end    = IRQ_PRCMU_HOTMON_HIGH,
> +               .flags  = IORESOURCE_IRQ,
> +       },
> +};
> +
> +static struct db8500_thsens_platform_data db8500_thsens_data = {
> +       .trip_points[0] = {
> +               .temp = 70000,
> +               .type = THERMAL_TRIP_ACTIVE,
> +               .cdev_name = {
> +                       [0] = "thermal-cpufreq-0",
> +               },
> +       },
> +       .trip_points[1] = {
> +               .temp = 75000,
> +               .type = THERMAL_TRIP_ACTIVE,
> +               .cdev_name = {
> +                       [0] = "thermal-cpufreq-0",
> +               },
> +       },
> +       .trip_points[2] = {
> +               .temp = 80000,
> +               .type = THERMAL_TRIP_ACTIVE,
> +               .cdev_name = {
> +                       [0] = "thermal-cpufreq-0",
> +               },
> +       },
> +       .trip_points[3] = {
> +               .temp = 85000,
> +               .type = THERMAL_TRIP_CRITICAL,
> +       },
> +       .num_trips = 4,
> +};
> +
> +static struct platform_device u8500_thsens_device = {
> +       .name           = "db8500-thermal",
> +       .resource       = db8500_thsens_resources,
> +       .num_resources  = ARRAY_SIZE(db8500_thsens_resources),
> +       .dev    = {
> +               .platform_data  = &db8500_thsens_data,
> +       },
> +};
> +
> +static struct platform_device u8500_cpufreq_cooling_device = {
> +       .name           = "db8500-cpufreq-cooling",
> +};
> +
> +/*
>   * TPS61052
>   */
>
> @@ -583,6 +645,8 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
>         &snowball_key_dev,
>         &snowball_sbnet_dev,
>         &snowball_gpio_en_3v3_regulator_dev,
> +       &u8500_thsens_device,
> +       &u8500_cpufreq_cooling_device,
>  };
>
>  static void __init mop500_init_machine(void)
> --
> 1.7.11.3
>
>
> _______________________________________________
> linaro-dev mailing list
> linaro-dev-cunTk1MwBs8s++Sfvej+rw@public.gmane.org
> http://lists.linaro.org/mailman/listinfo/linaro-dev

^ permalink raw reply

* Re: [PATCH V2 5/6] Thermal: Add ST-Ericsson DB8500 thermal dirver.
From: Viresh Kumar @ 2012-10-24 14:38 UTC (permalink / raw)
  To: hongbo.zhang
  Cc: linaro-dev, linux-kernel, linux-pm, STEricsson_nomadik_linux,
	kernel, linaro-kernel, hongbo.zhang, patches
In-Reply-To: <1351079900-32236-6-git-send-email-hongbo.zhang@linaro.com>

On 24 October 2012 17:28, hongbo.zhang <hongbo.zhang@linaro.org> wrote:
> From: "hongbo.zhang" <hongbo.zhang@linaro.com>
>
> This diver is based on the thermal management framework in thermal_sys.c. A
> thermal zone device is created with the trip points to which cooling devices
> can be bound, the current cooling device is cpufreq, e.g. CPU frequency is
> clipped down to cool the CPU, and other cooling devices can be added and bound
> to the trip points dynamically.  The platform specific PRCMU interrupts are
> used to active thermal update when trip points are reached.
>
> Signed-off-by: hongbo.zhang <hongbo.zhang@linaro.com>
> Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
> Reviewed-by: Francesco Lavra <francescolavra.fl@gmail.com>

You can't add these lines, until somebody has replied you with them in
earlier mails.

They don't show that somebody has put effort in reviewing them, but that current
patch looks Ok to these guys.

> ---
>  arch/arm/configs/u8500_defconfig             |   4 +

This is considered as platform part. So it must be part of next patch.

>  drivers/thermal/Kconfig                      |  20 +
>  drivers/thermal/Makefile                     |   2 +
>  drivers/thermal/db8500_cpufreq_cooling.c     | 123 ++++++
>  drivers/thermal/db8500_thermal.c             | 557 +++++++++++++++++++++++++++
>  include/linux/platform_data/db8500_thermal.h |  39 ++
>  6 files changed, 745 insertions(+)
>  create mode 100644 drivers/thermal/db8500_cpufreq_cooling.c
>  create mode 100644 drivers/thermal/db8500_thermal.c
>  create mode 100644 include/linux/platform_data/db8500_thermal.h
>
> diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
> index cc5e7a8..34918c4 100644
> --- a/arch/arm/configs/u8500_defconfig
> +++ b/arch/arm/configs/u8500_defconfig
> @@ -118,3 +118,7 @@ CONFIG_DEBUG_KERNEL=y
>  CONFIG_DEBUG_INFO=y
>  # CONFIG_FTRACE is not set
>  CONFIG_DEBUG_USER=y
> +CONFIG_THERMAL=y
> +CONFIG_CPU_THERMAL=y
> +CONFIG_DB8500_THERMAL=y
> +CONFIG_DB8500_CPUFREQ_COOLING=y
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index e1cb6bd..54c8fd0 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -31,6 +31,26 @@ config CPU_THERMAL
>           and not the ACPI interface.
>           If you want this support, you should say Y here.
>
> +config DB8500_THERMAL
> +       bool "DB8500 thermal management"
> +       depends on THERMAL
> +       default y
> +       help
> +         Adds DB8500 thermal management implementation according to the thermal
> +         management framework. A thermal zone with several trip points will be
> +         created. Cooling devices can be bound to the trip points to cool this
> +         thermal zone if trip points reached.
> +
> +config DB8500_CPUFREQ_COOLING
> +       tristate "DB8500 cpufreq cooling"
> +       depends on CPU_THERMAL
> +       default y
> +       help
> +         Adds DB8500 cpufreq cooling devices, and these cooling devices can be
> +         bound to thermal zone trip points. When a trip point reached, the
> +         bound cpufreq cooling device turns active to set CPU frequency low to
> +         cool down the CPU.
> +
>  config SPEAR_THERMAL
>         bool "SPEAr thermal sensor driver"
>         depends on THERMAL
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 885550d..c7a8dab 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -7,3 +7,5 @@ obj-$(CONFIG_CPU_THERMAL)               += cpu_cooling.o
>  obj-$(CONFIG_SPEAR_THERMAL)            += spear_thermal.o
>  obj-$(CONFIG_RCAR_THERMAL)     += rcar_thermal.o
>  obj-$(CONFIG_EXYNOS_THERMAL)           += exynos_thermal.o
> +obj-$(CONFIG_DB8500_THERMAL)           += db8500_thermal.o
> +obj-$(CONFIG_DB8500_CPUFREQ_COOLING)   += db8500_cpufreq_cooling.o
> diff --git a/drivers/thermal/db8500_cpufreq_cooling.c b/drivers/thermal/db8500_cpufreq_cooling.c
> new file mode 100644
> index 0000000..e4eddfd
> --- /dev/null
> +++ b/drivers/thermal/db8500_cpufreq_cooling.c
> @@ -0,0 +1,123 @@
> +/*
> + * db8500_cpufreq_cooling.c - db8500 cpufreq works as cooling device.
> + *
> + * Copyright (C) 2012 ST-Ericsson
> + * Copyright (C) 2012 Linaro Ltd.
> + *
> + * Author: Hongbo Zhang <hognbo.zhang@linaro.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *

remove extra blank line.

> + */
> +
> +#include <linux/cpu_cooling.h>
> +#include <linux/cpufreq.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +static LIST_HEAD(db8500_cpufreq_cdev_list);
> +
> +struct db8500_cpufreq_cdev {
> +       struct thermal_cooling_device *cdev;
> +       struct list_head node;
> +};
> +
> +static int __devinit db8500_cpufreq_cooling_probe(struct platform_device *pdev)

As said earlier, don't use __devinit, exit...

> +{
> +       struct db8500_cpufreq_cdev *cooling_dev;
> +       struct cpumask mask_val;
> +
> +       cooling_dev = devm_kzalloc(&pdev->dev,
> +                       sizeof(*cooling_dev), GFP_KERNEL);

Align this too with 'gq'

> +       if (!cooling_dev)
> +               return -ENOMEM;
> +
> +       cpumask_set_cpu(0, &mask_val);
> +       cooling_dev->cdev = cpufreq_cooling_register(&mask_val);
> +
> +       if (IS_ERR_OR_NULL(cooling_dev->cdev)) {
> +               dev_err(&pdev->dev,
> +                       "Failed to register cpufreq cooling device\n");
> +               return PTR_ERR(cooling_dev->cdev);
> +       }
> +
> +       pdev->dev.platform_data = cooling_dev->cdev;

Use platform_set_drvdata() and platform_get_drvdata()

> +       list_add_tail(&cooling_dev->node, &db8500_cpufreq_cdev_list);
> +       dev_info(&pdev->dev, "Cooling device registered: %s\n",
> +               cooling_dev->cdev->type);
> +
> +       return 0;
> +}
> +
> +static int __devexit db8500_cpufreq_cooling_remove(struct platform_device *pdev)
> +{
> +       struct db8500_cpufreq_cdev *cooling_dev;
> +
> +       list_for_each_entry(cooling_dev, &db8500_cpufreq_cdev_list, node)
> +               if (cooling_dev->cdev == pdev->dev.platform_data) {

Use platform_get_drvdata()

> +                       cpufreq_cooling_unregister(cooling_dev->cdev);
> +                       list_del(&cooling_dev->node);
> +               }
> +
> +       return 0;
> +}
> +
> +static int db8500_cpufreq_cooling_suspend(struct platform_device *pdev,
> +               pm_message_t state)
> +{
> +       return -ENOSYS;
> +}
> +
> +static int db8500_cpufreq_cooling_resume(struct platform_device *pdev)
> +{
> +       return -ENOSYS;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id db8500_cpufreq_cooling_match[] = {
> +       { .compatible = "stericsson,db8500-cpufreq-cooling" },
> +       {},
> +};
> +#else
> +#define db8500_cpufreq_cooling_match NULL
> +#endif
> +
> +static struct platform_driver db8500_cpufreq_cooling_driver = {
> +       .driver = {
> +               .owner = THIS_MODULE,
> +               .name = "db8500-cpufreq-cooling",
> +               .of_match_table = db8500_cpufreq_cooling_match,
> +       },
> +       .probe = db8500_cpufreq_cooling_probe,
> +       .suspend = db8500_cpufreq_cooling_suspend,
> +       .resume = db8500_cpufreq_cooling_resume,
> +       .remove = __devexit_p(db8500_cpufreq_cooling_remove),
> +};
> +
> +static int __init db8500_cpufreq_cooling_init(void)
> +{
> +       return platform_driver_register(&db8500_cpufreq_cooling_driver);
> +}
> +
> +static void __exit db8500_cpufreq_cooling_exit(void)
> +{
> +       platform_driver_unregister(&db8500_cpufreq_cooling_driver);
> +}
> +
> +/* Should be later than db8500_cpufreq_register */
> +late_initcall(db8500_cpufreq_cooling_init);
> +module_exit(db8500_cpufreq_cooling_exit);
> +
> +MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@stericsson.com>");
> +MODULE_DESCRIPTION("DB8500 cpufreq cooling driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
> new file mode 100644
> index 0000000..52b814d
> --- /dev/null
> +++ b/drivers/thermal/db8500_thermal.c
> @@ -0,0 +1,557 @@
> +/*
> + * db8500_thermal.c - db8500 Thermal Management Implementation
> + *
> + * Copyright (C) 2012 ST-Ericsson
> + * Copyright (C) 2012 Linaro Ltd.
> + *
> + * Author: Hongbo Zhang <hognbo.zhang@linaro.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *

remove extra blank line.

> + */
> +
> +#include <linux/cpu_cooling.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_data/db8500_thermal.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/thermal.h>
> +
> +#define PRCMU_DEFAULT_MEASURE_TIME     0xFFF
> +#define PRCMU_DEFAULT_LOW_TEMP         0
> +
> +struct db8500_thermal_zone {
> +       struct thermal_zone_device *therm_dev;
> +       struct mutex th_lock;
> +       struct work_struct therm_work;
> +       struct db8500_thsens_platform_data *trip_tab;
> +       enum thermal_device_mode mode;
> +       enum thermal_trend trend;
> +       unsigned long cur_temp_pseudo;
> +       unsigned int cur_index;
> +};
> +
> +/* Local function to check if thermal zone matches cooling devices */
> +static int db8500_thermal_match_cdev(struct thermal_cooling_device *cdev,
> +                       struct db8500_trip_point *trip_points)
> +{
> +       int i;
> +       char *cdev_name;
> +
> +       if (!strlen(cdev->type))
> +               return -EINVAL;
> +
> +       for (i = 0; i < COOLING_DEV_MAX; i++) {
> +               cdev_name = trip_points->cdev_name[i];
> +               if (!strlen(cdev_name))
> +                       continue;

Even if you don't have this strlen(), below strcmp will skip null strings.

> +               if (!strcmp(cdev_name, cdev->type))
> +                       return 0;
> +       }
> +
> +       return -ENODEV;
> +}
> +
> +/* Callback to bind cooling device to thermal zone */
> +static int db8500_cdev_bind(struct thermal_zone_device *thermal,
> +                       struct thermal_cooling_device *cdev)
> +{
> +       struct db8500_thermal_zone *pzone;
> +       struct db8500_thsens_platform_data *ptrips;
> +       unsigned long max_state, upper, lower;
> +       int i, ret = -EINVAL;
> +
> +       pzone = thermal->devdata;
> +       ptrips = pzone->trip_tab;

Do this with definition of these variables.

> +       for (i = 0; i < ptrips->num_trips; i++) {
> +               if (db8500_thermal_match_cdev(cdev, &ptrips->trip_points[i]))
> +                       continue;
> +
> +               cdev->ops->get_max_state(cdev, &max_state);
> +               lower = upper = (i > max_state) ? max_state : i;
> +
> +               ret = thermal_zone_bind_cooling_device(thermal, i,
> +                       cdev, upper, lower);
> +
> +               dev_info(&cdev->device, "%s bind to %d: %d-%s\n",
> +                       cdev->type, i, ret, ret ? "fail" : "succeed");
> +       }
> +
> +       return ret;
> +}
> +
> +/* Callback to unbind cooling device from thermal zone */
> +static int db8500_cdev_unbind(struct thermal_zone_device *thermal,
> +                         struct thermal_cooling_device *cdev)
> +{
> +       struct db8500_thermal_zone *pzone;
> +       struct db8500_thsens_platform_data *ptrips;
> +       int i, ret = -EINVAL;
> +
> +       pzone = thermal->devdata;
> +       ptrips = pzone->trip_tab;

ditto

> +       for (i = 0; i < ptrips->num_trips; i++) {
> +               if (db8500_thermal_match_cdev(cdev, &ptrips->trip_points[i]))
> +                       continue;
> +
> +               ret = thermal_zone_unbind_cooling_device(thermal, i, cdev);
> +
> +               dev_info(&cdev->device, "%s unbind: %s\n",
> +                       cdev->type, ret ? "fail" : "succeed");
> +       }
> +
> +       return ret;
> +}
> +
> +/* Callback to get current temperature */
> +static int db8500_sys_get_temp(struct thermal_zone_device *thermal,
> +                       unsigned long *temp)
> +{
> +       struct db8500_thermal_zone *pzone = thermal->devdata;
> +
> +       /*
> +        * TODO: There is no PRCMU interface to get temperature data currently,
> +        * so a pseudo temperature is returned , it works for thermal framework
> +        * and this will be fixed when the PRCMU interface is available.
> +        */
> +       *temp = pzone->cur_temp_pseudo;
> +
> +       return 0;
> +}
> +
> +/* Callback to get temperature changing trend */
> +static int db8500_sys_get_trend(struct thermal_zone_device *thermal,
> +                       int trip, enum thermal_trend *trend)
> +{
> +       struct db8500_thermal_zone *pzone = thermal->devdata;
> +
> +       *trend = pzone->trend;
> +
> +       return 0;

Can make it return void.

> +}
> +
> +/* Callback to get thermal zone mode */
> +static int db8500_sys_get_mode(struct thermal_zone_device *thermal,
> +                       enum thermal_device_mode *mode)
> +{
> +       struct db8500_thermal_zone *pzone = thermal->devdata;
> +
> +       mutex_lock(&pzone->th_lock);
> +       *mode = pzone->mode;
> +       mutex_unlock(&pzone->th_lock);
> +
> +       return 0;
> +}
> +
> +/* Callback to set thermal zone mode */
> +static int db8500_sys_set_mode(struct thermal_zone_device *thermal,
> +                       enum thermal_device_mode mode)
> +{
> +       struct db8500_thermal_zone *pzone;
> +       struct thermal_zone_device *pthdev;
> +
> +       pzone = thermal->devdata;
> +       pthdev = pzone->therm_dev;

ditto

> +       mutex_lock(&pzone->th_lock);
> +
> +       pzone->mode = mode;
> +       if (mode == THERMAL_DEVICE_ENABLED)
> +               schedule_work(&pzone->therm_work);
> +
> +       mutex_unlock(&pzone->th_lock);
> +
> +       return 0;
> +}
> +
> +/* Callback to get trip point type */
> +static int db8500_sys_get_trip_type(struct thermal_zone_device *thermal,
> +                       int trip, enum thermal_trip_type *type)
> +{
> +       struct db8500_thermal_zone *pzone;
> +       struct db8500_thsens_platform_data *ptrips;
> +
> +       pzone = thermal->devdata;
> +       ptrips = pzone->trip_tab;

ditto

do it everywhere

> +       if (trip >= ptrips->num_trips)
> +               return -EINVAL;
> +
> +       *type = ptrips->trip_points[trip].type;
> +
> +       return 0;
> +}
> +
> +/* Callback to get trip point temperature */
> +static int db8500_sys_get_trip_temp(struct thermal_zone_device *thermal,
> +                       int trip, unsigned long *temp)
> +{
> +       struct db8500_thermal_zone *pzone;
> +       struct db8500_thsens_platform_data *ptrips;
> +
> +       pzone = thermal->devdata;
> +       ptrips = pzone->trip_tab;
> +
> +       if (trip >= ptrips->num_trips)
> +               return -EINVAL;
> +
> +       *temp = ptrips->trip_points[trip].temp;
> +
> +       return 0;
> +}
> +
> +/* Callback to get critical trip point temperature */
> +static int db8500_sys_get_crit_temp(struct thermal_zone_device *thermal,
> +                       unsigned long *temp)
> +{
> +       struct db8500_thermal_zone *pzone;
> +       struct db8500_thsens_platform_data *ptrips;
> +       int i;
> +
> +       pzone = thermal->devdata;
> +       ptrips = pzone->trip_tab;
> +
> +       for (i = (ptrips->num_trips - 1); i > 0; i--) {

don't need extra () here. It would be followed by a ";"

> +               if (ptrips->trip_points[i].type == THERMAL_TRIP_CRITICAL) {
> +                       *temp = ptrips->trip_points[i].temp;
> +                       return 0;
> +               }
> +       }
> +
> +       return -EINVAL;
> +}
> +
> +static struct thermal_zone_device_ops thdev_ops = {
> +       .bind = db8500_cdev_bind,
> +       .unbind = db8500_cdev_unbind,
> +       .get_temp = db8500_sys_get_temp,
> +       .get_trend = db8500_sys_get_trend,
> +       .get_mode = db8500_sys_get_mode,
> +       .set_mode = db8500_sys_set_mode,
> +       .get_trip_type = db8500_sys_get_trip_type,
> +       .get_trip_temp = db8500_sys_get_trip_temp,
> +       .get_crit_temp = db8500_sys_get_crit_temp,
> +};
> +
> +static void db8500_thermal_update_config(struct db8500_thermal_zone *pzone,
> +               unsigned int idx, enum thermal_trend trend,
> +               unsigned long next_low, unsigned long next_high)
> +{
> +       pzone->cur_index = idx;
> +       pzone->cur_temp_pseudo = (next_low + next_high)/2;
> +       pzone->trend = trend;
> +
> +       prcmu_stop_temp_sense();
> +       prcmu_config_hotmon((u8)(next_low/1000), (u8)(next_high/1000));
> +       prcmu_start_temp_sense(PRCMU_DEFAULT_MEASURE_TIME);
> +}
> +
> +static irqreturn_t prcmu_low_irq_handler(int irq, void *irq_data)
> +{
> +       struct db8500_thermal_zone *pzone = irq_data;
> +       struct db8500_thsens_platform_data *ptrips;
> +       unsigned long next_low, next_high;
> +       unsigned int idx;
> +
> +       ptrips = pzone->trip_tab;
> +       idx = pzone->cur_index;
> +       if (unlikely(idx == 0))
> +               /* Meaningless for thermal management, ignoring it */
> +               return IRQ_HANDLED;
> +
> +       if (idx == 1) {
> +               next_high = ptrips->trip_points[0].temp;
> +               next_low = PRCMU_DEFAULT_LOW_TEMP;
> +       } else {
> +               next_high = ptrips->trip_points[idx-1].temp;
> +               next_low = ptrips->trip_points[idx-2].temp;
> +       }
> +       idx -= 1;
> +
> +       db8500_thermal_update_config(pzone, idx, THERMAL_TREND_DROPPING,
> +                       next_low, next_high);
> +
> +       dev_dbg(&pzone->therm_dev->device,
> +               "PRCMU set max %ld, min %ld\n", next_high, next_low);
> +
> +       schedule_work(&pzone->therm_work);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t prcmu_high_irq_handler(int irq, void *irq_data)
> +{
> +       struct db8500_thermal_zone *pzone = irq_data;
> +       struct db8500_thsens_platform_data *ptrips;
> +       unsigned long next_low, next_high;
> +       unsigned int idx;
> +
> +       ptrips = pzone->trip_tab;
> +       idx = pzone->cur_index;
> +
> +       if (idx < ptrips->num_trips - 1) {
> +               next_high = ptrips->trip_points[idx+1].temp;
> +               next_low = ptrips->trip_points[idx].temp;
> +               idx += 1;
> +
> +               db8500_thermal_update_config(pzone, idx, THERMAL_TREND_RAISING,
> +                       next_low, next_high);
> +
> +               dev_dbg(&pzone->therm_dev->device,
> +               "PRCMU set max %ld, min %ld\n", next_high, next_low);
> +       }
> +
> +       else if (idx == ptrips->num_trips - 1)
> +               pzone->cur_temp_pseudo = ptrips->trip_points[idx].temp + 1;
> +
> +       schedule_work(&pzone->therm_work);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static void db8500_thermal_work(struct work_struct *work)
> +{
> +       enum thermal_device_mode cur_mode;
> +       struct db8500_thermal_zone *pzone;
> +
> +       pzone = container_of(work, struct db8500_thermal_zone, therm_work);
> +
> +       mutex_lock(&pzone->th_lock);
> +       cur_mode = pzone->mode;
> +       mutex_unlock(&pzone->th_lock);
> +
> +       if (cur_mode == THERMAL_DEVICE_DISABLED)
> +               return;
> +
> +       thermal_zone_device_update(pzone->therm_dev);
> +       dev_dbg(&pzone->therm_dev->device, "thermal work finished.\n");
> +}
> +
> +#ifdef CONFIG_OF
> +static struct db8500_thsens_platform_data*
> +               db8500_thermal_parse_dt(struct platform_device *pdev)
> +{
> +       struct db8500_thsens_platform_data *ptrips;
> +       struct device_node *np = pdev->dev.of_node;
> +       char prop_name[32];
> +       const char *tmp_str;
> +       u32 tmp_data;
> +       int i, j;
> +
> +       if (!np) {
> +               dev_err(&pdev->dev, "Missing device tree data\n");
> +               return NULL;
> +       }
> +
> +       ptrips = devm_kzalloc(&pdev->dev, sizeof(*ptrips), GFP_KERNEL);
> +       if (!ptrips)
> +               return NULL;
> +
> +       if (of_property_read_u32(np, "num-trips", &tmp_data))
> +               goto err_parse_dt;
> +
> +       ptrips->num_trips = tmp_data;
> +
> +       for (i = 0; i < ptrips->num_trips; i++) {
> +               sprintf(prop_name, "trip%d-temp", i);
> +               if (of_property_read_u32(np, prop_name, &tmp_data))
> +                       goto err_parse_dt;
> +
> +               ptrips->trip_points[i].temp = tmp_data;
> +
> +               sprintf(prop_name, "trip%d-type", i);
> +               if (of_property_read_string(np, prop_name, &tmp_str))
> +                       goto err_parse_dt;
> +
> +               if (!strcmp(tmp_str, "active"))
> +                       ptrips->trip_points[i].type = THERMAL_TRIP_ACTIVE;
> +               else if (!strcmp(tmp_str, "passive"))
> +                       ptrips->trip_points[i].type = THERMAL_TRIP_PASSIVE;
> +               else if (!strcmp(tmp_str, "hot"))
> +                       ptrips->trip_points[i].type = THERMAL_TRIP_HOT;
> +               else if (!strcmp(tmp_str, "critical"))
> +                       ptrips->trip_points[i].type = THERMAL_TRIP_CRITICAL;
> +               else
> +                       goto err_parse_dt;
> +
> +               sprintf(prop_name, "trip%d-cdev-num", i);
> +               if (of_property_read_u32(np, prop_name, &tmp_data))
> +                       goto err_parse_dt;
> +
> +               for (j = 0; j < tmp_data; j++) {
> +                       sprintf(prop_name, "trip%d-cdev-name%d", i, j);
> +                       if (of_property_read_string(np, prop_name, &tmp_str))
> +                               goto err_parse_dt;
> +                       strcpy(ptrips->trip_points[i].cdev_name[j], tmp_str);
> +               }
> +       }
> +       return ptrips;
> +
> +err_parse_dt:
> +       dev_err(&pdev->dev, "Parsing device tree data error.\n");
> +       return NULL;
> +}
> +#else
> +static struct db8500_thsens_platform_data*
> +               db8500_thermal_parse_dt(struct platform_device *pdev)

mark it inline here.

> +{
> +       return NULL;
> +}
> +#endif
> +
> +static int __devinit db8500_thermal_probe(struct platform_device *pdev)
> +{
> +       struct db8500_thermal_zone *pzone = NULL;
> +       struct db8500_thsens_platform_data *ptrips = NULL;
> +       int low_irq, high_irq, ret = 0;
> +       unsigned long dft_low, dft_high;
> +
> +       pzone = devm_kzalloc(&pdev->dev, sizeof(*pzone), GFP_KERNEL);
> +       if (!pzone)
> +               return -ENOMEM;
> +
> +       ptrips = db8500_thermal_parse_dt(pdev);

This is what u have in this routine at the very first line:

       if (!np) {
               dev_err(&pdev->dev, "Missing device tree data\n");

So, you will end up printing this line for every non-DT case. Not good.
What u can do is, give preference to normal pdata here.

> +       if (!ptrips)
> +               ptrips = dev_get_platdata(&pdev->dev);
> +
> +       if (!ptrips)

In case we have a DT case, you will run this if statement twice :(

> +               return -EINVAL;
> +

move pzone = devm_kzalloc, here after verifying pdata is there. so that
you don't allocate things for error cases.

> +       mutex_init(&pzone->th_lock);
> +       mutex_lock(&pzone->th_lock);
> +
> +       pzone->mode = THERMAL_DEVICE_DISABLED;
> +       pzone->trip_tab = ptrips;
> +
> +       pzone->therm_dev = thermal_zone_device_register("db8500_thermal_zone",
> +               ptrips->num_trips, 0, pzone, &thdev_ops, 0, 0);
> +
> +       if (IS_ERR_OR_NULL(pzone->therm_dev)) {
> +               dev_err(&pdev->dev, "Register thermal zone device failed.\n");
> +               return PTR_ERR(pzone->therm_dev);
> +       }
> +       dev_info(&pdev->dev, "Thermal zone device registered.\n");
> +
> +       dft_low = PRCMU_DEFAULT_LOW_TEMP;
> +       dft_high = ptrips->trip_points[0].temp;
> +
> +       db8500_thermal_update_config(pzone, 0, THERMAL_TREND_STABLE,
> +                       dft_low, dft_high);
> +
> +       INIT_WORK(&pzone->therm_work, db8500_thermal_work);
> +
> +       low_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_LOW");
> +       if (low_irq < 0) {
> +               dev_err(&pdev->dev, "Get IRQ_HOTMON_LOW failed.\n");
> +               return low_irq;

Don't you want to do thermal_zone_device_unregister here? Please check
the sequence of stuff in this routine.

> +       }
> +
> +       ret = devm_request_threaded_irq(&pdev->dev, low_irq, NULL,

why threaded irq?

> +               prcmu_low_irq_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
> +               "dbx500_temp_low", pzone);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Failed to allocate temp low irq.\n");
> +               return ret;
> +       }
> +
> +       high_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_HIGH");
> +       if (high_irq < 0) {
> +               dev_err(&pdev->dev, "Get IRQ_HOTMON_HIGH failed.\n");
> +               return high_irq;

don't want to free resources?

> +       }
> +
> +       ret = devm_request_threaded_irq(&pdev->dev, high_irq, NULL,
> +               prcmu_high_irq_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
> +               "dbx500_temp_high", pzone);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Failed to allocate temp high irq.\n");
> +               return ret;
> +       }
> +
> +       platform_set_drvdata(pdev, pzone);
> +       pzone->mode = THERMAL_DEVICE_ENABLED;
> +       mutex_unlock(&pzone->th_lock);
> +
> +       return 0;
> +}
> +
> +static int __devexit db8500_thermal_remove(struct platform_device *pdev)
> +{
> +       struct db8500_thermal_zone *pzone;
> +       pzone = platform_get_drvdata(pdev);
> +
> +       cancel_work_sync(&pzone->therm_work);
> +       mutex_destroy(&pzone->th_lock);
> +       thermal_zone_device_unregister(pzone->therm_dev);

The first thing you must do here is unregister... Then cancel work and mutex
destroy. It has to be opposite of probe.

> +       return 0;
> +}
> +
> +static int db8500_thermal_suspend(struct platform_device *pdev,
> +               pm_message_t state)
> +{
> +       struct db8500_thermal_zone *pzone;
> +       pzone = platform_get_drvdata(pdev);
> +
> +       flush_work_sync(&pzone->therm_work);
> +       prcmu_stop_temp_sense();
> +
> +       return 0;
> +}
> +
> +static int db8500_thermal_resume(struct platform_device *pdev)
> +{
> +       struct db8500_thermal_zone *pzone;
> +       struct db8500_thsens_platform_data *ptrips;
> +       unsigned long dft_low, dft_high;
> +
> +       pzone = platform_get_drvdata(pdev);
> +       ptrips = pzone->trip_tab;
> +       dft_low = PRCMU_DEFAULT_LOW_TEMP;
> +       dft_high = ptrips->trip_points[0].temp;
> +
> +       db8500_thermal_update_config(pzone, 0, THERMAL_TREND_STABLE,
> +                               dft_low, dft_high);
> +
> +       return 0;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id db8500_thermal_match[] = {
> +       { .compatible = "stericsson,db8500-thermal" },
> +       {},
> +};
> +#else
> +#define db8500_thermal_match NULL
> +#endif
> +
> +static struct platform_driver db8500_thermal_driver = {
> +       .driver = {
> +               .owner = THIS_MODULE,
> +               .name = "db8500-thermal",
> +               .of_match_table = db8500_thermal_match,
> +       },
> +       .probe = db8500_thermal_probe,
> +       .suspend = db8500_thermal_suspend,
> +       .resume = db8500_thermal_resume,
> +       .remove = __devexit_p(db8500_thermal_remove),
> +};
> +
> +module_platform_driver(db8500_thermal_driver);
> +
> +MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@stericsson.com>");
> +MODULE_DESCRIPTION("DB8500 thermal driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/platform_data/db8500_thermal.h b/include/linux/platform_data/db8500_thermal.h
> new file mode 100644
> index 0000000..8825cd9
> --- /dev/null
> +++ b/include/linux/platform_data/db8500_thermal.h
> @@ -0,0 +1,39 @@
> +/*
> + * db8500_thermal.h - db8500 Thermal Management Implementation
> + *
> + * Copyright (C) 2012 ST-Ericsson
> + * Copyright (C) 2012 Linaro Ltd.
> + *
> + * Author: Hongbo Zhang <hognbo.zhang@linaro.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *

:(

> + */
> +
> +#ifndef _DB8500_THERMAL_H_
> +#define _DB8500_THERMAL_H_
> +
> +#include <linux/thermal.h>
> +
> +#define COOLING_DEV_MAX 8
> +
> +struct db8500_trip_point {
> +       unsigned long temp;
> +       enum thermal_trip_type type;
> +       char cdev_name[COOLING_DEV_MAX][THERMAL_NAME_LENGTH];
> +};
> +
> +struct db8500_thsens_platform_data {
> +       struct db8500_trip_point trip_points[THERMAL_MAX_TRIPS];
> +       int num_trips;
> +};
> +
> +#endif /* _DB8500_THERMAL_H_ */

^ permalink raw reply

* Re: [PATCH V2 6/6] Thermal: Add ST-Ericsson DB8500 thermal properties and platform data.
From: Joe Perches @ 2012-10-24 14:32 UTC (permalink / raw)
  To: hongbo.zhang
  Cc: linaro-dev, linux-kernel, linux-pm, patches, linaro-kernel,
	STEricsson_nomadik_linux, kernel, hongbo.zhang
In-Reply-To: <1351079900-32236-7-git-send-email-hongbo.zhang@linaro.com>

On Wed, 2012-10-24 at 19:58 +0800, hongbo.zhang wrote:
> This patch adds device tree properties for ST-Ericsson DB8500 thermal driver,
> also adds the platform data to support the old fashion.

Just a trivial note:

> diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c

> @@ -229,6 +230,67 @@ static struct ab8500_platform_data ab8500_platdata = {
>  };
>  
>  /*
> + * Thermal Sensor
> + */
> +
> +static struct resource db8500_thsens_resources[] = {

should there be a const in any of these?

> +static struct db8500_thsens_platform_data db8500_thsens_data = {
[]
> +static struct platform_device u8500_thsens_device = {
[]
> +static struct platform_device u8500_cpufreq_cooling_device = {

^ permalink raw reply

* Re: [PATCH V2 3/6] Thermal: fix bug of counting cpu frequencies.
From: Viresh Kumar @ 2012-10-24 13:34 UTC (permalink / raw)
  To: hongbo.zhang
  Cc: linaro-dev, linux-kernel, linux-pm, STEricsson_nomadik_linux,
	kernel, linaro-kernel, hongbo.zhang, patches
In-Reply-To: <1351079900-32236-4-git-send-email-hongbo.zhang@linaro.com>

On 24 October 2012 17:28, hongbo.zhang <hongbo.zhang@linaro.org> wrote:
> From: "hongbo.zhang" <hongbo.zhang@linaro.com>
>
> In the while loop for counting cpu frequencies, if table[i].frequency equals
> CPUFREQ_ENTRY_INVALID, index i won't be increased, so this leads to an endless
> loop, what's more the index i cannot be referred as cpu frequencies number if
> there is CPUFREQ_ENTRY_INVALID case.
>
> Signed-off-by: hongbo.zhang <hongbo.zhang@linaro.com>

Good one.

Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>

^ permalink raw reply

* Re: [RFC PATCH v2 2/6] PM / Runtime: introduce pm_runtime_set_memalloc_noio()
From: Alan Cox @ 2012-10-24 12:26 UTC (permalink / raw)
  To: David Laight
  Cc: Ming Lei, Alan Stern, linux-kernel, Oliver Neukum, Minchan Kim,
	Greg Kroah-Hartman, Rafael J. Wysocki, Jens Axboe,
	David S. Miller, Andrew Morton, netdev, linux-usb, linux-pm,
	linux-mm
In-Reply-To: <AE90C24D6B3A694183C094C60CF0A2F6026B7060@saturn3.aculab.com>

On Wed, 24 Oct 2012 10:06:36 +0100
"David Laight" <David.Laight@ACULAB.COM> wrote:

> > Looks the problem is worse than above, not only bitfields are affected, the
> > adjacent fields might be involved too, see:
> > 
> >            http://lwn.net/Articles/478657/
> 
> Not mentioned in there is that even with x86/amd64 given
> a struct with the following adjacent fields:
> 	char a;
> 	char b;
> 	char c;
> then foo->b |= 0x80; might do a 32bit RMW cycle.

There are processors that will do this for the char case at least as they
do byte ops by a mix of 32bit ops and rotate.

> This will (well might - but probably does) happen
> if compiled to a 'BTS' instruction.
> The x86 instruction set docs are actually unclear
> as to whether the 32bit cycle might even be misaligned!
> amd64 might do a 64bit cycle (not checked the docs).

Even with a suitably aligned field the compiler is at liberty to generate
things like

	reg = 0x80
	reg |= foo->b
	foo->b = reg;

One reason it's a good idea to use set_bit/test_bit and friends.

Alan

--
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

* [PATCH V2 1/6] Thermal: add indent for code alignment.
From: hongbo.zhang @ 2012-10-24 11:58 UTC (permalink / raw)
  To: linaro-dev, linux-kernel, linux-pm
  Cc: patches, linaro-kernel, STEricsson_nomadik_linux, kernel,
	hongbo.zhang
In-Reply-To: <1351079900-32236-1-git-send-email-hongbo.zhang@linaro.com>

From: "hongbo.zhang" <hongbo.zhang@linaro.com>

The curly bracket should be aligned with corresponding if else statements.

Signed-off-by: hongbo.zhang <hongbo.zhang@linaro.com>
Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/thermal/cpu_cooling.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index cc1c930..b6b4c2a 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -369,7 +369,7 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 			if (min != policy.cpuinfo.min_freq ||
 				max != policy.cpuinfo.max_freq)
 				return ERR_PTR(-EINVAL);
-}
+		}
 	}
 	cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device),
 			GFP_KERNEL);
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH V2 0/6] Fix thermal bugs and Upstream ST-Ericsson thermal driver
From: hongbo.zhang @ 2012-10-24 11:58 UTC (permalink / raw)
  To: linaro-dev, linux-kernel, linux-pm
  Cc: patches, linaro-kernel, STEricsson_nomadik_linux, kernel,
	hongbo.zhang
In-Reply-To: <1350387889-15324-1-git-send-email-hongbo.zhang@linaro.com>

From: "hongbo.zhang" <hongbo.zhang@linaro.com>

V1->V2 Changes:

DB8500 thermal dirver: Accept comments from Francesco Lavra and Viresh Kumar,
and split platform and driver parts into separate patches.

Thermal layer: Cancel the patch for deferring bind due to new patch for generic
cpu cooling layer to fix this issue.

CPU cooling layer: New patch "Remove the cooling_cpufreq_list" added, thus old
patch to fix empty list checking is also removed.

hongbo.zhang (6):
  Thermal: add indent for code alignment.
  Thermal: make sure cpufreq cooling register after cpufreq driver
  Thermal: fix bug of counting cpu frequencies.
  Thermal: Remove the cooling_cpufreq_list.
  Thermal: Add ST-Ericsson DB8500 thermal dirver.
  Thermal: Add ST-Ericsson DB8500 thermal properties and platform data.

 .../devicetree/bindings/thermal/db8500-thermal.txt |  40 ++
 arch/arm/boot/dts/dbx5x0.dtsi                      |  14 +
 arch/arm/boot/dts/snowball.dts                     |  31 ++
 arch/arm/configs/u8500_defconfig                   |   4 +
 arch/arm/mach-ux500/board-mop500.c                 |  64 +++
 drivers/thermal/Kconfig                            |  20 +
 drivers/thermal/Makefile                           |   2 +
 drivers/thermal/cpu_cooling.c                      |  95 +---
 drivers/thermal/db8500_cpufreq_cooling.c           | 123 +++++
 drivers/thermal/db8500_thermal.c                   | 557 +++++++++++++++++++++
 include/linux/platform_data/db8500_thermal.h       |  39 ++
 11 files changed, 920 insertions(+), 69 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/thermal/db8500-thermal.txt
 create mode 100644 drivers/thermal/db8500_cpufreq_cooling.c
 create mode 100644 drivers/thermal/db8500_thermal.c
 create mode 100644 include/linux/platform_data/db8500_thermal.h

-- 
1.7.11.3


^ permalink raw reply

* [PATCH V2 6/6] Thermal: Add ST-Ericsson DB8500 thermal properties and platform data.
From: hongbo.zhang @ 2012-10-24 11:58 UTC (permalink / raw)
  To: linaro-dev-cunTk1MwBs8s++Sfvej+rw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: STEricsson_nomadik_linux-nkJGhpqTU55BDgjK7y7TUQ,
	kernel-vMlcbD5RyM6HZuj8yyL1ah2eb7JE58TQ,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, hongbo.zhang,
	patches-QSEj5FYQhm4dnm+yROfE0A
In-Reply-To: <1351079900-32236-1-git-send-email-hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>

From: "hongbo.zhang" <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>

This patch adds device tree properties for ST-Ericsson DB8500 thermal driver,
also adds the platform data to support the old fashion.

Signed-off-by: hongbo.zhang <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>
---
 .../devicetree/bindings/thermal/db8500-thermal.txt | 40 ++++++++++++++
 arch/arm/boot/dts/dbx5x0.dtsi                      | 14 +++++
 arch/arm/boot/dts/snowball.dts                     | 31 +++++++++++
 arch/arm/mach-ux500/board-mop500.c                 | 64 ++++++++++++++++++++++
 4 files changed, 149 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/thermal/db8500-thermal.txt

diff --git a/Documentation/devicetree/bindings/thermal/db8500-thermal.txt b/Documentation/devicetree/bindings/thermal/db8500-thermal.txt
new file mode 100644
index 0000000..80d53e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/db8500-thermal.txt
@@ -0,0 +1,40 @@
+* ST-Ericsson DB8500 Thermal
+
+** Thermal node properties:
+
+- compatible : "stericsson,db8500-thermal";
+- reg : address range of the thermal sensor registers;
+- interrupts : interrupts generated form PRCMU;
+- interrupt-names : "IRQ_HOTMON_LOW" and "IRQ_HOTMON_HIGH";
+- num-trips : number of total trip points;
+- tripN-temp : temperature of trip point N;
+- tripN-type : type of trip point N, should be one of "active" "passive" "hot" "critical";
+- tripN-cdev-num : number of the cooling devices which can be bound to trip point N;
+- tripN-cdev-nameM : name of the No. M cooling device of trip point N;
+
+Usually the num-trips and tripN-*** are seperated in board related dts files.
+
+Example:
+thermal@801573c0 {
+	compatible = "stericsson,db8500-thermal";
+	reg = <0x801573c0 0x40>;
+	interrupts = <21 0x4>, <22 0x4>;
+	interrupt-names = "IRQ_HOTMON_LOW", "IRQ_HOTMON_HIGH";
+
+	num-trips = <3>;
+
+	trip0-temp = <70000>;
+	trip0-type = "active";
+	trip0-cdev-num = <1>;
+	trip0-cdev-name0 = "thermal-cpufreq-0";
+
+	trip1-temp = <75000>;
+	trip1-type = "active";
+	trip1-cdev-num = <2>;
+	trip1-cdev-name0 = "thermal-cpufreq-0";
+	trip1-cdev-name1 = "thermal-fan";
+
+	trip2-temp = <85000>;
+	trip2-type = "critical";
+	trip2-cdev-num = <0>;
+}
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 748ba7a..949edc2 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -203,6 +203,14 @@
 				reg = <0x80157450 0xC>;
 			};
 
+			thermal@801573c0 {
+				compatible = "stericsson,db8500-thermal";
+				reg = <0x801573c0 0x40>;
+				interrupts = <21 0x4>, <22 0x4>;
+				interrupt-names = "IRQ_HOTMON_LOW", "IRQ_HOTMON_HIGH";
+				status = "disabled";
+			 };
+
 			db8500-prcmu-regulators {
 				compatible = "stericsson,db8500-prcmu-regulator";
 
@@ -645,5 +653,11 @@
 			ranges = <0 0x50000000 0x4000000>;
 			status = "disabled";
 		};
+
+		cpufreq-cooling {
+			compatible = "stericsson,db8500-cpufreq-cooling";
+			status = "disabled";
+		 };
+
 	};
 };
diff --git a/arch/arm/boot/dts/snowball.dts b/arch/arm/boot/dts/snowball.dts
index 702c0ba..c6f85f0 100644
--- a/arch/arm/boot/dts/snowball.dts
+++ b/arch/arm/boot/dts/snowball.dts
@@ -99,6 +99,33 @@
 			status = "okay";
 		};
 
+		prcmu@80157000 {
+			thermal@801573c0 {
+				num-trips = <4>;
+
+				trip0-temp = <70000>;
+				trip0-type = "active";
+				trip0-cdev-num = <1>;
+				trip0-cdev-name0 = "thermal-cpufreq-0";
+
+				trip1-temp = <75000>;
+				trip1-type = "active";
+				trip1-cdev-num = <1>;
+				trip1-cdev-name0 = "thermal-cpufreq-0";
+
+				trip2-temp = <80000>;
+				trip2-type = "active";
+				trip2-cdev-num = <1>;
+				trip2-cdev-name0 = "thermal-cpufreq-0";
+
+				trip3-temp = <85000>;
+				trip3-type = "critical";
+				trip3-cdev-num = <0>;
+
+				status = "okay";
+			 };
+		};
+
 		external-bus@50000000 {
 			status = "okay";
 
@@ -183,5 +210,9 @@
 				reg = <0x33>;
 			};
 		};
+
+		cpufreq-cooling {
+			status = "okay";
+		};
 	};
 };
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 416d436..b03216b 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/platform_data/i2c-nomadik.h>
+#include <linux/platform_data/db8500_thermal.h>
 #include <linux/gpio.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/pl022.h>
@@ -229,6 +230,67 @@ static struct ab8500_platform_data ab8500_platdata = {
 };
 
 /*
+ * Thermal Sensor
+ */
+
+static struct resource db8500_thsens_resources[] = {
+	{
+		.name = "IRQ_HOTMON_LOW",
+		.start  = IRQ_PRCMU_HOTMON_LOW,
+		.end    = IRQ_PRCMU_HOTMON_LOW,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name = "IRQ_HOTMON_HIGH",
+		.start  = IRQ_PRCMU_HOTMON_HIGH,
+		.end    = IRQ_PRCMU_HOTMON_HIGH,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct db8500_thsens_platform_data db8500_thsens_data = {
+	.trip_points[0] = {
+		.temp = 70000,
+		.type = THERMAL_TRIP_ACTIVE,
+		.cdev_name = {
+			[0] = "thermal-cpufreq-0",
+		},
+	},
+	.trip_points[1] = {
+		.temp = 75000,
+		.type = THERMAL_TRIP_ACTIVE,
+		.cdev_name = {
+			[0] = "thermal-cpufreq-0",
+		},
+	},
+	.trip_points[2] = {
+		.temp = 80000,
+		.type = THERMAL_TRIP_ACTIVE,
+		.cdev_name = {
+			[0] = "thermal-cpufreq-0",
+		},
+	},
+	.trip_points[3] = {
+		.temp = 85000,
+		.type = THERMAL_TRIP_CRITICAL,
+	},
+	.num_trips = 4,
+};
+
+static struct platform_device u8500_thsens_device = {
+	.name           = "db8500-thermal",
+	.resource       = db8500_thsens_resources,
+	.num_resources  = ARRAY_SIZE(db8500_thsens_resources),
+	.dev	= {
+		.platform_data	= &db8500_thsens_data,
+	},
+};
+
+static struct platform_device u8500_cpufreq_cooling_device = {
+	.name           = "db8500-cpufreq-cooling",
+};
+
+/*
  * TPS61052
  */
 
@@ -583,6 +645,8 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
 	&snowball_key_dev,
 	&snowball_sbnet_dev,
 	&snowball_gpio_en_3v3_regulator_dev,
+	&u8500_thsens_device,
+	&u8500_cpufreq_cooling_device,
 };
 
 static void __init mop500_init_machine(void)
-- 
1.7.11.3

^ permalink raw reply related

* [PATCH V2 5/6] Thermal: Add ST-Ericsson DB8500 thermal dirver.
From: hongbo.zhang @ 2012-10-24 11:58 UTC (permalink / raw)
  To: linaro-dev-cunTk1MwBs8s++Sfvej+rw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: STEricsson_nomadik_linux-nkJGhpqTU55BDgjK7y7TUQ,
	kernel-vMlcbD5RyM6HZuj8yyL1ah2eb7JE58TQ,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, hongbo.zhang,
	patches-QSEj5FYQhm4dnm+yROfE0A
In-Reply-To: <1351079900-32236-1-git-send-email-hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>

From: "hongbo.zhang" <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>

This diver is based on the thermal management framework in thermal_sys.c. A
thermal zone device is created with the trip points to which cooling devices
can be bound, the current cooling device is cpufreq, e.g. CPU frequency is
clipped down to cool the CPU, and other cooling devices can be added and bound
to the trip points dynamically.  The platform specific PRCMU interrupts are
used to active thermal update when trip points are reached.

Signed-off-by: hongbo.zhang <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>
Reviewed-by: Viresh Kumar <viresh.kumar-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Reviewed-by: Francesco Lavra <francescolavra.fl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 arch/arm/configs/u8500_defconfig             |   4 +
 drivers/thermal/Kconfig                      |  20 +
 drivers/thermal/Makefile                     |   2 +
 drivers/thermal/db8500_cpufreq_cooling.c     | 123 ++++++
 drivers/thermal/db8500_thermal.c             | 557 +++++++++++++++++++++++++++
 include/linux/platform_data/db8500_thermal.h |  39 ++
 6 files changed, 745 insertions(+)
 create mode 100644 drivers/thermal/db8500_cpufreq_cooling.c
 create mode 100644 drivers/thermal/db8500_thermal.c
 create mode 100644 include/linux/platform_data/db8500_thermal.h

diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index cc5e7a8..34918c4 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -118,3 +118,7 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_USER=y
+CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
+CONFIG_DB8500_THERMAL=y
+CONFIG_DB8500_CPUFREQ_COOLING=y
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index e1cb6bd..54c8fd0 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -31,6 +31,26 @@ config CPU_THERMAL
 	  and not the ACPI interface.
 	  If you want this support, you should say Y here.
 
+config DB8500_THERMAL
+	bool "DB8500 thermal management"
+	depends on THERMAL
+	default y
+	help
+	  Adds DB8500 thermal management implementation according to the thermal
+	  management framework. A thermal zone with several trip points will be
+	  created. Cooling devices can be bound to the trip points to cool this
+	  thermal zone if trip points reached.
+
+config DB8500_CPUFREQ_COOLING
+	tristate "DB8500 cpufreq cooling"
+	depends on CPU_THERMAL
+	default y
+	help
+	  Adds DB8500 cpufreq cooling devices, and these cooling devices can be
+	  bound to thermal zone trip points. When a trip point reached, the
+	  bound cpufreq cooling device turns active to set CPU frequency low to
+	  cool down the CPU.
+
 config SPEAR_THERMAL
 	bool "SPEAr thermal sensor driver"
 	depends on THERMAL
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 885550d..c7a8dab 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -7,3 +7,5 @@ obj-$(CONFIG_CPU_THERMAL)		+= cpu_cooling.o
 obj-$(CONFIG_SPEAR_THERMAL)		+= spear_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
 obj-$(CONFIG_EXYNOS_THERMAL)		+= exynos_thermal.o
+obj-$(CONFIG_DB8500_THERMAL)		+= db8500_thermal.o
+obj-$(CONFIG_DB8500_CPUFREQ_COOLING)	+= db8500_cpufreq_cooling.o
diff --git a/drivers/thermal/db8500_cpufreq_cooling.c b/drivers/thermal/db8500_cpufreq_cooling.c
new file mode 100644
index 0000000..e4eddfd
--- /dev/null
+++ b/drivers/thermal/db8500_cpufreq_cooling.c
@@ -0,0 +1,123 @@
+/*
+ * db8500_cpufreq_cooling.c - db8500 cpufreq works as cooling device.
+ *
+ * Copyright (C) 2012 ST-Ericsson
+ * Copyright (C) 2012 Linaro Ltd.
+ *
+ * Author: Hongbo Zhang <hognbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/cpu_cooling.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+static LIST_HEAD(db8500_cpufreq_cdev_list);
+
+struct db8500_cpufreq_cdev {
+	struct thermal_cooling_device *cdev;
+	struct list_head node;
+};
+
+static int __devinit db8500_cpufreq_cooling_probe(struct platform_device *pdev)
+{
+	struct db8500_cpufreq_cdev *cooling_dev;
+	struct cpumask mask_val;
+
+	cooling_dev = devm_kzalloc(&pdev->dev,
+			sizeof(*cooling_dev), GFP_KERNEL);
+	if (!cooling_dev)
+		return -ENOMEM;
+
+	cpumask_set_cpu(0, &mask_val);
+	cooling_dev->cdev = cpufreq_cooling_register(&mask_val);
+
+	if (IS_ERR_OR_NULL(cooling_dev->cdev)) {
+		dev_err(&pdev->dev,
+			"Failed to register cpufreq cooling device\n");
+		return PTR_ERR(cooling_dev->cdev);
+	}
+
+	pdev->dev.platform_data = cooling_dev->cdev;
+	list_add_tail(&cooling_dev->node, &db8500_cpufreq_cdev_list);
+	dev_info(&pdev->dev, "Cooling device registered: %s\n",
+		cooling_dev->cdev->type);
+
+	return 0;
+}
+
+static int __devexit db8500_cpufreq_cooling_remove(struct platform_device *pdev)
+{
+	struct db8500_cpufreq_cdev *cooling_dev;
+
+	list_for_each_entry(cooling_dev, &db8500_cpufreq_cdev_list, node)
+		if (cooling_dev->cdev == pdev->dev.platform_data) {
+			cpufreq_cooling_unregister(cooling_dev->cdev);
+			list_del(&cooling_dev->node);
+		}
+
+	return 0;
+}
+
+static int db8500_cpufreq_cooling_suspend(struct platform_device *pdev,
+		pm_message_t state)
+{
+	return -ENOSYS;
+}
+
+static int db8500_cpufreq_cooling_resume(struct platform_device *pdev)
+{
+	return -ENOSYS;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id db8500_cpufreq_cooling_match[] = {
+	{ .compatible = "stericsson,db8500-cpufreq-cooling" },
+	{},
+};
+#else
+#define db8500_cpufreq_cooling_match NULL
+#endif
+
+static struct platform_driver db8500_cpufreq_cooling_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "db8500-cpufreq-cooling",
+		.of_match_table = db8500_cpufreq_cooling_match,
+	},
+	.probe = db8500_cpufreq_cooling_probe,
+	.suspend = db8500_cpufreq_cooling_suspend,
+	.resume = db8500_cpufreq_cooling_resume,
+	.remove = __devexit_p(db8500_cpufreq_cooling_remove),
+};
+
+static int __init db8500_cpufreq_cooling_init(void)
+{
+	return platform_driver_register(&db8500_cpufreq_cooling_driver);
+}
+
+static void __exit db8500_cpufreq_cooling_exit(void)
+{
+	platform_driver_unregister(&db8500_cpufreq_cooling_driver);
+}
+
+/* Should be later than db8500_cpufreq_register */
+late_initcall(db8500_cpufreq_cooling_init);
+module_exit(db8500_cpufreq_cooling_exit);
+
+MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org>");
+MODULE_DESCRIPTION("DB8500 cpufreq cooling driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
new file mode 100644
index 0000000..52b814d
--- /dev/null
+++ b/drivers/thermal/db8500_thermal.c
@@ -0,0 +1,557 @@
+/*
+ * db8500_thermal.c - db8500 Thermal Management Implementation
+ *
+ * Copyright (C) 2012 ST-Ericsson
+ * Copyright (C) 2012 Linaro Ltd.
+ *
+ * Author: Hongbo Zhang <hognbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/cpu_cooling.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_data/db8500_thermal.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+
+#define PRCMU_DEFAULT_MEASURE_TIME	0xFFF
+#define PRCMU_DEFAULT_LOW_TEMP		0
+
+struct db8500_thermal_zone {
+	struct thermal_zone_device *therm_dev;
+	struct mutex th_lock;
+	struct work_struct therm_work;
+	struct db8500_thsens_platform_data *trip_tab;
+	enum thermal_device_mode mode;
+	enum thermal_trend trend;
+	unsigned long cur_temp_pseudo;
+	unsigned int cur_index;
+};
+
+/* Local function to check if thermal zone matches cooling devices */
+static int db8500_thermal_match_cdev(struct thermal_cooling_device *cdev,
+			struct db8500_trip_point *trip_points)
+{
+	int i;
+	char *cdev_name;
+
+	if (!strlen(cdev->type))
+		return -EINVAL;
+
+	for (i = 0; i < COOLING_DEV_MAX; i++) {
+		cdev_name = trip_points->cdev_name[i];
+		if (!strlen(cdev_name))
+			continue;
+		if (!strcmp(cdev_name, cdev->type))
+			return 0;
+	}
+
+	return -ENODEV;
+}
+
+/* Callback to bind cooling device to thermal zone */
+static int db8500_cdev_bind(struct thermal_zone_device *thermal,
+			struct thermal_cooling_device *cdev)
+{
+	struct db8500_thermal_zone *pzone;
+	struct db8500_thsens_platform_data *ptrips;
+	unsigned long max_state, upper, lower;
+	int i, ret = -EINVAL;
+
+	pzone = thermal->devdata;
+	ptrips = pzone->trip_tab;
+
+	for (i = 0; i < ptrips->num_trips; i++) {
+		if (db8500_thermal_match_cdev(cdev, &ptrips->trip_points[i]))
+			continue;
+
+		cdev->ops->get_max_state(cdev, &max_state);
+		lower = upper = (i > max_state) ? max_state : i;
+
+		ret = thermal_zone_bind_cooling_device(thermal, i,
+			cdev, upper, lower);
+
+		dev_info(&cdev->device, "%s bind to %d: %d-%s\n",
+			cdev->type, i, ret, ret ? "fail" : "succeed");
+	}
+
+	return ret;
+}
+
+/* Callback to unbind cooling device from thermal zone */
+static int db8500_cdev_unbind(struct thermal_zone_device *thermal,
+			  struct thermal_cooling_device *cdev)
+{
+	struct db8500_thermal_zone *pzone;
+	struct db8500_thsens_platform_data *ptrips;
+	int i, ret = -EINVAL;
+
+	pzone = thermal->devdata;
+	ptrips = pzone->trip_tab;
+
+	for (i = 0; i < ptrips->num_trips; i++) {
+		if (db8500_thermal_match_cdev(cdev, &ptrips->trip_points[i]))
+			continue;
+
+		ret = thermal_zone_unbind_cooling_device(thermal, i, cdev);
+
+		dev_info(&cdev->device, "%s unbind: %s\n",
+			cdev->type, ret ? "fail" : "succeed");
+	}
+
+	return ret;
+}
+
+/* Callback to get current temperature */
+static int db8500_sys_get_temp(struct thermal_zone_device *thermal,
+			unsigned long *temp)
+{
+	struct db8500_thermal_zone *pzone = thermal->devdata;
+
+	/*
+	 * TODO: There is no PRCMU interface to get temperature data currently,
+	 * so a pseudo temperature is returned , it works for thermal framework
+	 * and this will be fixed when the PRCMU interface is available.
+	 */
+	*temp = pzone->cur_temp_pseudo;
+
+	return 0;
+}
+
+/* Callback to get temperature changing trend */
+static int db8500_sys_get_trend(struct thermal_zone_device *thermal,
+			int trip, enum thermal_trend *trend)
+{
+	struct db8500_thermal_zone *pzone = thermal->devdata;
+
+	*trend = pzone->trend;
+
+	return 0;
+}
+
+/* Callback to get thermal zone mode */
+static int db8500_sys_get_mode(struct thermal_zone_device *thermal,
+			enum thermal_device_mode *mode)
+{
+	struct db8500_thermal_zone *pzone = thermal->devdata;
+
+	mutex_lock(&pzone->th_lock);
+	*mode = pzone->mode;
+	mutex_unlock(&pzone->th_lock);
+
+	return 0;
+}
+
+/* Callback to set thermal zone mode */
+static int db8500_sys_set_mode(struct thermal_zone_device *thermal,
+			enum thermal_device_mode mode)
+{
+	struct db8500_thermal_zone *pzone;
+	struct thermal_zone_device *pthdev;
+
+	pzone = thermal->devdata;
+	pthdev = pzone->therm_dev;
+
+	mutex_lock(&pzone->th_lock);
+
+	pzone->mode = mode;
+	if (mode == THERMAL_DEVICE_ENABLED)
+		schedule_work(&pzone->therm_work);
+
+	mutex_unlock(&pzone->th_lock);
+
+	return 0;
+}
+
+/* Callback to get trip point type */
+static int db8500_sys_get_trip_type(struct thermal_zone_device *thermal,
+			int trip, enum thermal_trip_type *type)
+{
+	struct db8500_thermal_zone *pzone;
+	struct db8500_thsens_platform_data *ptrips;
+
+	pzone = thermal->devdata;
+	ptrips = pzone->trip_tab;
+
+	if (trip >= ptrips->num_trips)
+		return -EINVAL;
+
+	*type = ptrips->trip_points[trip].type;
+
+	return 0;
+}
+
+/* Callback to get trip point temperature */
+static int db8500_sys_get_trip_temp(struct thermal_zone_device *thermal,
+			int trip, unsigned long *temp)
+{
+	struct db8500_thermal_zone *pzone;
+	struct db8500_thsens_platform_data *ptrips;
+
+	pzone = thermal->devdata;
+	ptrips = pzone->trip_tab;
+
+	if (trip >= ptrips->num_trips)
+		return -EINVAL;
+
+	*temp = ptrips->trip_points[trip].temp;
+
+	return 0;
+}
+
+/* Callback to get critical trip point temperature */
+static int db8500_sys_get_crit_temp(struct thermal_zone_device *thermal,
+			unsigned long *temp)
+{
+	struct db8500_thermal_zone *pzone;
+	struct db8500_thsens_platform_data *ptrips;
+	int i;
+
+	pzone = thermal->devdata;
+	ptrips = pzone->trip_tab;
+
+	for (i = (ptrips->num_trips - 1); i > 0; i--) {
+		if (ptrips->trip_points[i].type == THERMAL_TRIP_CRITICAL) {
+			*temp = ptrips->trip_points[i].temp;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static struct thermal_zone_device_ops thdev_ops = {
+	.bind = db8500_cdev_bind,
+	.unbind = db8500_cdev_unbind,
+	.get_temp = db8500_sys_get_temp,
+	.get_trend = db8500_sys_get_trend,
+	.get_mode = db8500_sys_get_mode,
+	.set_mode = db8500_sys_set_mode,
+	.get_trip_type = db8500_sys_get_trip_type,
+	.get_trip_temp = db8500_sys_get_trip_temp,
+	.get_crit_temp = db8500_sys_get_crit_temp,
+};
+
+static void db8500_thermal_update_config(struct db8500_thermal_zone *pzone,
+		unsigned int idx, enum thermal_trend trend,
+		unsigned long next_low, unsigned long next_high)
+{
+	pzone->cur_index = idx;
+	pzone->cur_temp_pseudo = (next_low + next_high)/2;
+	pzone->trend = trend;
+
+	prcmu_stop_temp_sense();
+	prcmu_config_hotmon((u8)(next_low/1000), (u8)(next_high/1000));
+	prcmu_start_temp_sense(PRCMU_DEFAULT_MEASURE_TIME);
+}
+
+static irqreturn_t prcmu_low_irq_handler(int irq, void *irq_data)
+{
+	struct db8500_thermal_zone *pzone = irq_data;
+	struct db8500_thsens_platform_data *ptrips;
+	unsigned long next_low, next_high;
+	unsigned int idx;
+
+	ptrips = pzone->trip_tab;
+	idx = pzone->cur_index;
+	if (unlikely(idx == 0))
+		/* Meaningless for thermal management, ignoring it */
+		return IRQ_HANDLED;
+
+	if (idx == 1) {
+		next_high = ptrips->trip_points[0].temp;
+		next_low = PRCMU_DEFAULT_LOW_TEMP;
+	} else {
+		next_high = ptrips->trip_points[idx-1].temp;
+		next_low = ptrips->trip_points[idx-2].temp;
+	}
+	idx -= 1;
+
+	db8500_thermal_update_config(pzone, idx, THERMAL_TREND_DROPPING,
+			next_low, next_high);
+
+	dev_dbg(&pzone->therm_dev->device,
+		"PRCMU set max %ld, min %ld\n", next_high, next_low);
+
+	schedule_work(&pzone->therm_work);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t prcmu_high_irq_handler(int irq, void *irq_data)
+{
+	struct db8500_thermal_zone *pzone = irq_data;
+	struct db8500_thsens_platform_data *ptrips;
+	unsigned long next_low, next_high;
+	unsigned int idx;
+
+	ptrips = pzone->trip_tab;
+	idx = pzone->cur_index;
+
+	if (idx < ptrips->num_trips - 1) {
+		next_high = ptrips->trip_points[idx+1].temp;
+		next_low = ptrips->trip_points[idx].temp;
+		idx += 1;
+
+		db8500_thermal_update_config(pzone, idx, THERMAL_TREND_RAISING,
+			next_low, next_high);
+
+		dev_dbg(&pzone->therm_dev->device,
+		"PRCMU set max %ld, min %ld\n", next_high, next_low);
+	}
+
+	else if (idx == ptrips->num_trips - 1)
+		pzone->cur_temp_pseudo = ptrips->trip_points[idx].temp + 1;
+
+	schedule_work(&pzone->therm_work);
+
+	return IRQ_HANDLED;
+}
+
+static void db8500_thermal_work(struct work_struct *work)
+{
+	enum thermal_device_mode cur_mode;
+	struct db8500_thermal_zone *pzone;
+
+	pzone = container_of(work, struct db8500_thermal_zone, therm_work);
+
+	mutex_lock(&pzone->th_lock);
+	cur_mode = pzone->mode;
+	mutex_unlock(&pzone->th_lock);
+
+	if (cur_mode == THERMAL_DEVICE_DISABLED)
+		return;
+
+	thermal_zone_device_update(pzone->therm_dev);
+	dev_dbg(&pzone->therm_dev->device, "thermal work finished.\n");
+}
+
+#ifdef CONFIG_OF
+static struct db8500_thsens_platform_data*
+		db8500_thermal_parse_dt(struct platform_device *pdev)
+{
+	struct db8500_thsens_platform_data *ptrips;
+	struct device_node *np = pdev->dev.of_node;
+	char prop_name[32];
+	const char *tmp_str;
+	u32 tmp_data;
+	int i, j;
+
+	if (!np) {
+		dev_err(&pdev->dev, "Missing device tree data\n");
+		return NULL;
+	}
+
+	ptrips = devm_kzalloc(&pdev->dev, sizeof(*ptrips), GFP_KERNEL);
+	if (!ptrips)
+		return NULL;
+
+	if (of_property_read_u32(np, "num-trips", &tmp_data))
+		goto err_parse_dt;
+
+	ptrips->num_trips = tmp_data;
+
+	for (i = 0; i < ptrips->num_trips; i++) {
+		sprintf(prop_name, "trip%d-temp", i);
+		if (of_property_read_u32(np, prop_name, &tmp_data))
+			goto err_parse_dt;
+
+		ptrips->trip_points[i].temp = tmp_data;
+
+		sprintf(prop_name, "trip%d-type", i);
+		if (of_property_read_string(np, prop_name, &tmp_str))
+			goto err_parse_dt;
+
+		if (!strcmp(tmp_str, "active"))
+			ptrips->trip_points[i].type = THERMAL_TRIP_ACTIVE;
+		else if (!strcmp(tmp_str, "passive"))
+			ptrips->trip_points[i].type = THERMAL_TRIP_PASSIVE;
+		else if (!strcmp(tmp_str, "hot"))
+			ptrips->trip_points[i].type = THERMAL_TRIP_HOT;
+		else if (!strcmp(tmp_str, "critical"))
+			ptrips->trip_points[i].type = THERMAL_TRIP_CRITICAL;
+		else
+			goto err_parse_dt;
+
+		sprintf(prop_name, "trip%d-cdev-num", i);
+		if (of_property_read_u32(np, prop_name, &tmp_data))
+			goto err_parse_dt;
+
+		for (j = 0; j < tmp_data; j++) {
+			sprintf(prop_name, "trip%d-cdev-name%d", i, j);
+			if (of_property_read_string(np, prop_name, &tmp_str))
+				goto err_parse_dt;
+			strcpy(ptrips->trip_points[i].cdev_name[j], tmp_str);
+		}
+	}
+	return ptrips;
+
+err_parse_dt:
+	dev_err(&pdev->dev, "Parsing device tree data error.\n");
+	return NULL;
+}
+#else
+static struct db8500_thsens_platform_data*
+		db8500_thermal_parse_dt(struct platform_device *pdev)
+{
+	return NULL;
+}
+#endif
+
+static int __devinit db8500_thermal_probe(struct platform_device *pdev)
+{
+	struct db8500_thermal_zone *pzone = NULL;
+	struct db8500_thsens_platform_data *ptrips = NULL;
+	int low_irq, high_irq, ret = 0;
+	unsigned long dft_low, dft_high;
+
+	pzone = devm_kzalloc(&pdev->dev, sizeof(*pzone), GFP_KERNEL);
+	if (!pzone)
+		return -ENOMEM;
+
+	ptrips = db8500_thermal_parse_dt(pdev);
+	if (!ptrips)
+		ptrips = dev_get_platdata(&pdev->dev);
+
+	if (!ptrips)
+		return -EINVAL;
+
+	mutex_init(&pzone->th_lock);
+	mutex_lock(&pzone->th_lock);
+
+	pzone->mode = THERMAL_DEVICE_DISABLED;
+	pzone->trip_tab = ptrips;
+
+	pzone->therm_dev = thermal_zone_device_register("db8500_thermal_zone",
+		ptrips->num_trips, 0, pzone, &thdev_ops, 0, 0);
+
+	if (IS_ERR_OR_NULL(pzone->therm_dev)) {
+		dev_err(&pdev->dev, "Register thermal zone device failed.\n");
+		return PTR_ERR(pzone->therm_dev);
+	}
+	dev_info(&pdev->dev, "Thermal zone device registered.\n");
+
+	dft_low = PRCMU_DEFAULT_LOW_TEMP;
+	dft_high = ptrips->trip_points[0].temp;
+
+	db8500_thermal_update_config(pzone, 0, THERMAL_TREND_STABLE,
+			dft_low, dft_high);
+
+	INIT_WORK(&pzone->therm_work, db8500_thermal_work);
+
+	low_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_LOW");
+	if (low_irq < 0) {
+		dev_err(&pdev->dev, "Get IRQ_HOTMON_LOW failed.\n");
+		return low_irq;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, low_irq, NULL,
+		prcmu_low_irq_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
+		"dbx500_temp_low", pzone);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to allocate temp low irq.\n");
+		return ret;
+	}
+
+	high_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_HIGH");
+	if (high_irq < 0) {
+		dev_err(&pdev->dev, "Get IRQ_HOTMON_HIGH failed.\n");
+		return high_irq;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, high_irq, NULL,
+		prcmu_high_irq_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
+		"dbx500_temp_high", pzone);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to allocate temp high irq.\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, pzone);
+	pzone->mode = THERMAL_DEVICE_ENABLED;
+	mutex_unlock(&pzone->th_lock);
+
+	return 0;
+}
+
+static int __devexit db8500_thermal_remove(struct platform_device *pdev)
+{
+	struct db8500_thermal_zone *pzone;
+	pzone = platform_get_drvdata(pdev);
+
+	cancel_work_sync(&pzone->therm_work);
+	mutex_destroy(&pzone->th_lock);
+	thermal_zone_device_unregister(pzone->therm_dev);
+
+	return 0;
+}
+
+static int db8500_thermal_suspend(struct platform_device *pdev,
+		pm_message_t state)
+{
+	struct db8500_thermal_zone *pzone;
+	pzone = platform_get_drvdata(pdev);
+
+	flush_work_sync(&pzone->therm_work);
+	prcmu_stop_temp_sense();
+
+	return 0;
+}
+
+static int db8500_thermal_resume(struct platform_device *pdev)
+{
+	struct db8500_thermal_zone *pzone;
+	struct db8500_thsens_platform_data *ptrips;
+	unsigned long dft_low, dft_high;
+
+	pzone = platform_get_drvdata(pdev);
+	ptrips = pzone->trip_tab;
+	dft_low = PRCMU_DEFAULT_LOW_TEMP;
+	dft_high = ptrips->trip_points[0].temp;
+
+	db8500_thermal_update_config(pzone, 0, THERMAL_TREND_STABLE,
+				dft_low, dft_high);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id db8500_thermal_match[] = {
+	{ .compatible = "stericsson,db8500-thermal" },
+	{},
+};
+#else
+#define db8500_thermal_match NULL
+#endif
+
+static struct platform_driver db8500_thermal_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "db8500-thermal",
+		.of_match_table = db8500_thermal_match,
+	},
+	.probe = db8500_thermal_probe,
+	.suspend = db8500_thermal_suspend,
+	.resume = db8500_thermal_resume,
+	.remove = __devexit_p(db8500_thermal_remove),
+};
+
+module_platform_driver(db8500_thermal_driver);
+
+MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org>");
+MODULE_DESCRIPTION("DB8500 thermal driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/db8500_thermal.h b/include/linux/platform_data/db8500_thermal.h
new file mode 100644
index 0000000..8825cd9
--- /dev/null
+++ b/include/linux/platform_data/db8500_thermal.h
@@ -0,0 +1,39 @@
+/*
+ * db8500_thermal.h - db8500 Thermal Management Implementation
+ *
+ * Copyright (C) 2012 ST-Ericsson
+ * Copyright (C) 2012 Linaro Ltd.
+ *
+ * Author: Hongbo Zhang <hognbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _DB8500_THERMAL_H_
+#define _DB8500_THERMAL_H_
+
+#include <linux/thermal.h>
+
+#define COOLING_DEV_MAX 8
+
+struct db8500_trip_point {
+	unsigned long temp;
+	enum thermal_trip_type type;
+	char cdev_name[COOLING_DEV_MAX][THERMAL_NAME_LENGTH];
+};
+
+struct db8500_thsens_platform_data {
+	struct db8500_trip_point trip_points[THERMAL_MAX_TRIPS];
+	int num_trips;
+};
+
+#endif /* _DB8500_THERMAL_H_ */
-- 
1.7.11.3

^ permalink raw reply related

* [PATCH V2 4/6] Thermal: Remove the cooling_cpufreq_list.
From: hongbo.zhang @ 2012-10-24 11:58 UTC (permalink / raw)
  To: linaro-dev, linux-kernel, linux-pm
  Cc: patches, linaro-kernel, STEricsson_nomadik_linux, kernel,
	hongbo.zhang
In-Reply-To: <1351079900-32236-1-git-send-email-hongbo.zhang@linaro.com>

From: "hongbo.zhang" <hongbo.zhang@linaro.com>

Problem of using this list is that the cpufreq_get_max_state callback will be
called when register cooling device by thermal_cooling_device_register, but
this list isn't ready at this moment. What's more, there is no need to maintain
such a list, we can get cpufreq_cooling_device instance by the private
thermal_cooling_device.devdata.

Signed-off-by: hongbo.zhang <hongbo.zhang@linaro.com>
---
 drivers/thermal/cpu_cooling.c | 81 +++++++++----------------------------------
 1 file changed, 16 insertions(+), 65 deletions(-)

diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 415b041..cc80d29 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -58,8 +58,9 @@ struct cpufreq_cooling_device {
 };
 static LIST_HEAD(cooling_cpufreq_list);
 static DEFINE_IDR(cpufreq_idr);
+static DEFINE_MUTEX(cooling_cpufreq_lock);
 
-static struct mutex cooling_cpufreq_lock;
+static unsigned int cpufreq_dev_count;
 
 /* notify_table passes value to the CPUFREQ_ADJUST callback function. */
 #define NOTIFY_INVALID NULL
@@ -241,20 +242,12 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 				 unsigned long *state)
 {
 	int ret = -EINVAL, i = 0;
-	struct cpufreq_cooling_device *cpufreq_device;
+	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
 	struct cpumask *maskPtr;
 	unsigned int cpu;
 	struct cpufreq_frequency_table *table;
 	unsigned long count = 0;
 
-	mutex_lock(&cooling_cpufreq_lock);
-	list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
-		if (cpufreq_device && cpufreq_device->cool_dev == cdev)
-			break;
-	}
-	if (cpufreq_device == NULL)
-		goto return_get_max_state;
-
 	maskPtr = &cpufreq_device->allowed_cpus;
 	cpu = cpumask_any(maskPtr);
 	table = cpufreq_frequency_get_table(cpu);
@@ -276,7 +269,6 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 	}
 
 return_get_max_state:
-	mutex_unlock(&cooling_cpufreq_lock);
 	return ret;
 }
 
@@ -288,20 +280,10 @@ return_get_max_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);
+	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
 
-	return ret;
+	*state = cpufreq_device->cpufreq_state;
+	return 0;
 }
 
 /**
@@ -312,22 +294,9 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
 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);
+	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
 
-	mutex_unlock(&cooling_cpufreq_lock);
-
-	return ret;
+	return cpufreq_apply_cooling(cpufreq_device, state);
 }
 
 /* Bind cpufreq callbacks to thermal cooling device ops */
@@ -351,7 +320,7 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 {
 	struct thermal_cooling_device *cool_dev;
 	struct cpufreq_cooling_device *cpufreq_dev = NULL;
-	unsigned int cpufreq_dev_count = 0, min = 0, max = 0;
+	unsigned int min = 0, max = 0;
 	char dev_name[THERMAL_NAME_LENGTH];
 	int ret = 0, i;
 	struct cpufreq_policy policy;
@@ -360,9 +329,6 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 	if (!cpufreq_frequency_get_table(cpumask_any(clip_cpus)))
 		return ERR_PTR(-EPROBE_DEFER);
 
-	list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
-		cpufreq_dev_count++;
-
 	/*Verify that all the clip cpus have same freq_min, freq_max limit*/
 	for_each_cpu(i, clip_cpus) {
 		/*continue if cpufreq policy not found and not return error*/
@@ -384,9 +350,6 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 
 	cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);
 
-	if (cpufreq_dev_count == 0)
-		mutex_init(&cooling_cpufreq_lock);
-
 	ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
 	if (ret) {
 		kfree(cpufreq_dev);
@@ -405,12 +368,12 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 	cpufreq_dev->cool_dev = cool_dev;
 	cpufreq_dev->cpufreq_state = 0;
 	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);
+	cpufreq_dev_count++;
 
 	mutex_unlock(&cooling_cpufreq_lock);
 	return cool_dev;
@@ -423,33 +386,21 @@ EXPORT_SYMBOL(cpufreq_cooling_register);
  */
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
-	struct cpufreq_cooling_device *cpufreq_dev = NULL;
-	unsigned int cpufreq_dev_count = 0;
+	struct cpufreq_cooling_device *cpufreq_dev = cdev->devdata;
 
-	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;
-	}
+	thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
 
-	list_del(&cpufreq_dev->node);
+	mutex_lock(&cooling_cpufreq_lock);
+	cpufreq_dev_count--;
 
 	/* Unregister the notifier for the last cpufreq cooling device */
-	if (cpufreq_dev_count == 1) {
+	if (cpufreq_dev_count == 0) {
 		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);
-	if (cpufreq_dev_count == 1)
-		mutex_destroy(&cooling_cpufreq_lock);
 	kfree(cpufreq_dev);
 }
 EXPORT_SYMBOL(cpufreq_cooling_unregister);
-- 
1.7.11.3

^ permalink raw reply related

* [PATCH V2 3/6] Thermal: fix bug of counting cpu frequencies.
From: hongbo.zhang @ 2012-10-24 11:58 UTC (permalink / raw)
  To: linaro-dev-cunTk1MwBs8s++Sfvej+rw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: STEricsson_nomadik_linux-nkJGhpqTU55BDgjK7y7TUQ,
	kernel-vMlcbD5RyM6HZuj8yyL1ah2eb7JE58TQ,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, hongbo.zhang,
	patches-QSEj5FYQhm4dnm+yROfE0A
In-Reply-To: <1351079900-32236-1-git-send-email-hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>

From: "hongbo.zhang" <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>

In the while loop for counting cpu frequencies, if table[i].frequency equals
CPUFREQ_ENTRY_INVALID, index i won't be increased, so this leads to an endless
loop, what's more the index i cannot be referred as cpu frequencies number if
there is CPUFREQ_ENTRY_INVALID case.

Signed-off-by: hongbo.zhang <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>
---
 drivers/thermal/cpu_cooling.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 7519a0b..415b041 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -245,6 +245,7 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 	struct cpumask *maskPtr;
 	unsigned int cpu;
 	struct cpufreq_frequency_table *table;
+	unsigned long count = 0;
 
 	mutex_lock(&cooling_cpufreq_lock);
 	list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
@@ -263,13 +264,14 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 		goto return_get_max_state;
 	}
 
-	while (table[i].frequency != CPUFREQ_TABLE_END) {
+	for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
 		if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
 			continue;
-		i++;
+		count++;
 	}
-	if (i > 0) {
-		*state = --i;
+
+	if (count > 0) {
+		*state = --count;
 		ret = 0;
 	}
 
-- 
1.7.11.3

^ permalink raw reply related

* [PATCH V2 2/6] Thermal: make sure cpufreq cooling register after cpufreq driver
From: hongbo.zhang @ 2012-10-24 11:58 UTC (permalink / raw)
  To: linaro-dev-cunTk1MwBs8s++Sfvej+rw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: STEricsson_nomadik_linux-nkJGhpqTU55BDgjK7y7TUQ,
	kernel-vMlcbD5RyM6HZuj8yyL1ah2eb7JE58TQ,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, hongbo.zhang,
	patches-QSEj5FYQhm4dnm+yROfE0A
In-Reply-To: <1351079900-32236-1-git-send-email-hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>

From: "hongbo.zhang" <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>

The cpufreq works as a cooling device, so the cooling layer should check if the
cpufreq driver is initialized or not.

Signed-off-by: hongbo.zhang <hongbo.zhang-68IGFXMjmZ7QT0dZR+AlfA@public.gmane.org>
---
 drivers/thermal/cpu_cooling.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index b6b4c2a..7519a0b 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -354,6 +354,10 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 	int ret = 0, i;
 	struct cpufreq_policy policy;
 
+	/* make sure cpufreq driver has been initialized */
+	if (!cpufreq_frequency_get_table(cpumask_any(clip_cpus)))
+		return ERR_PTR(-EPROBE_DEFER);
+
 	list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
 		cpufreq_dev_count++;
 
-- 
1.7.11.3

^ permalink raw reply related

* RE: [RFC PATCH v2 2/6] PM / Runtime: introduce pm_runtime_set_memalloc_noio()
From: David Laight @ 2012-10-24  9:06 UTC (permalink / raw)
  To: Ming Lei, Alan Stern
  Cc: linux-kernel, Oliver Neukum, Minchan Kim, Greg Kroah-Hartman,
	Rafael J. Wysocki, Jens Axboe, David S. Miller, Andrew Morton,
	netdev, linux-usb, linux-pm, linux-mm
In-Reply-To: <CACVXFVN+=XH_f5BmRkXeagTNowz0o0-Pd7GcxCneO0FSq8xqEw@mail.gmail.com>

> Looks the problem is worse than above, not only bitfields are affected, the
> adjacent fields might be involved too, see:
> 
>            http://lwn.net/Articles/478657/

Not mentioned in there is that even with x86/amd64 given
a struct with the following adjacent fields:
	char a;
	char b;
	char c;
then foo->b |= 0x80; might do a 32bit RMW cycle.
This will (well might - but probably does) happen
if compiled to a 'BTS' instruction.
The x86 instruction set docs are actually unclear
as to whether the 32bit cycle might even be misaligned!
amd64 might do a 64bit cycle (not checked the docs).

	David




^ permalink raw reply

* [PATCH 2/2] cpufreq: Fix sparse warning by making local function static
From: Viresh Kumar @ 2012-10-24  7:45 UTC (permalink / raw)
  To: rjw
  Cc: cpufreq, linux-pm, linaro-dev, patches, pdsw-power-team,
	arvind.chauhan, fengguang.wu, Viresh Kumar
In-Reply-To: <93ed702aba4c33d9a477c7296c59cc2882e16f82.1351064553.git.viresh.kumar@linaro.org>

cpufreq_disabled() is a local function, so should be marked static.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/cpufreq/cpufreq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index f552d5f..261ef65 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -129,7 +129,7 @@ static int __init init_cpufreq_transition_notifier_list(void)
 pure_initcall(init_cpufreq_transition_notifier_list);
 
 static int off __read_mostly;
-int cpufreq_disabled(void)
+static int cpufreq_disabled(void)
 {
 	return off;
 }
-- 
1.7.12.rc2.18.g61b472e


^ permalink raw reply related

* [PATCH 1/2] cpufreq: Fix sparse warnings by updating cputime64_t to u64
From: Viresh Kumar @ 2012-10-24  7:45 UTC (permalink / raw)
  To: rjw
  Cc: cpufreq, linux-pm, linaro-dev, patches, pdsw-power-team,
	arvind.chauhan, fengguang.wu, Viresh Kumar

There were few sparse warnings due to mismatch of type on function arguments.
Two types were used u64 and cputime64_t. Both are actually u64, so use u64 only.

Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---

This solution was discussed here:

http://www.mail-archive.com/linaro-dev@lists.linaro.org/msg13744.html

 drivers/cpufreq/cpufreq_governor.c |  4 ++--
 drivers/cpufreq/cpufreq_governor.h | 11 +++++------
 drivers/cpufreq/cpufreq_stats.c    |  4 ++--
 3 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index cd5fe57..e39bf81 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -49,7 +49,7 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
 	return jiffies_to_usecs(idle_time);
 }
 
-cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
+u64 get_cpu_idle_time(unsigned int cpu, u64 *wall)
 {
 	u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
 
@@ -81,7 +81,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
 	/* Get Absolute Load (in terms of freq for ondemand gov) */
 	for_each_cpu(j, policy->cpus) {
 		struct cpu_dbs_common_info *j_cdbs;
-		cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time;
+		u64 cur_wall_time, cur_idle_time, cur_iowait_time;
 		unsigned int idle_time, wall_time, iowait_time;
 		unsigned int load;
 
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 34e14ad..f661654 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -17,7 +17,6 @@
 #ifndef _CPUFREQ_GOVERNER_H
 #define _CPUFREQ_GOVERNER_H
 
-#include <asm/cputime.h>
 #include <linux/cpufreq.h>
 #include <linux/kobject.h>
 #include <linux/mutex.h>
@@ -72,9 +71,9 @@ static void *get_cpu_dbs_info_s(int cpu)				\
 /* Per cpu structures */
 struct cpu_dbs_common_info {
 	int cpu;
-	cputime64_t prev_cpu_idle;
-	cputime64_t prev_cpu_wall;
-	cputime64_t prev_cpu_nice;
+	u64 prev_cpu_idle;
+	u64 prev_cpu_wall;
+	u64 prev_cpu_nice;
 	struct cpufreq_policy *cur_policy;
 	struct delayed_work work;
 	/*
@@ -87,7 +86,7 @@ struct cpu_dbs_common_info {
 
 struct od_cpu_dbs_info_s {
 	struct cpu_dbs_common_info cdbs;
-	cputime64_t prev_cpu_iowait;
+	u64 prev_cpu_iowait;
 	struct cpufreq_frequency_table *freq_table;
 	unsigned int freq_lo;
 	unsigned int freq_lo_jiffies;
@@ -170,7 +169,7 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate)
 	return delay;
 }
 
-cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall);
+u64 get_cpu_idle_time(unsigned int cpu, u64 *wall);
 void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
 int cpufreq_governor_dbs(struct dbs_data *dbs_data,
 		struct cpufreq_policy *policy, unsigned int event);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index b40ee14..683a48f 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -37,7 +37,7 @@ struct cpufreq_stats {
 	unsigned int max_state;
 	unsigned int state_num;
 	unsigned int last_index;
-	cputime64_t *time_in_state;
+	u64 *time_in_state;
 	unsigned int *freq_table;
 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
 	unsigned int *trans_table;
@@ -223,7 +223,7 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
 		count++;
 	}
 
-	alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
+	alloc_size = count * sizeof(int) + count * sizeof(u64);
 
 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
 	alloc_size += count * count * sizeof(int);
-- 
1.7.12.rc2.18.g61b472e


^ permalink raw reply related

* [BUGFIX 1/2] PCI/PM: Fix deadlock when unbind device if its parent in D3cold
From: Huang Ying @ 2012-10-24  6:54 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-kernel, linux-pci, linux-pm, Rafael J. Wysocki, Huang Ying,
	Zhang Yanmin

If a PCI device and its parents are put into D3cold, unbinding the
device will trigger deadlock as follow:

- driver_unbind
  - device_release_driver
    - device_lock(dev)				<--- previous lock here
    - __device_release_driver
      - pm_runtime_get_sync
        ...
          - rpm_resume(dev)
            - rpm_resume(dev->parent)
              ...
                - pci_pm_runtime_resume
                  ...
                  - pci_set_power_state
                    - __pci_start_power_transition
                      - pci_wakeup_bus(dev->parent->subordinate)
                        - pci_walk_bus
                          - device_lock(dev)	<--- dead lock here


If we do not do device_lock in pci_walk_bus, we can avoid dead lock.
Device_lock in pci_walk_bus is introduced in commit:
d71374dafbba7ec3f67371d3b7e9f6310a588808, corresponding email thread
is: https://lkml.org/lkml/2006/5/26/38.  The patch author Zhang Yanmin
said device_lock is added to pci_walk_bus because:

  Some error handling functions call pci_walk_bus. For example, PCIe
  aer. Here we lock the device, so the driver wouldn't detach from the
  device, as the cb might call driver's callback function.

So I fixed the dead lock as follow:

- remove device_lock from pci_walk_bus
- add device_lock into callback if callback will call driver's callback

I checked pci_walk_bus users one by one, and found only PCIe aer needs
device lock.

Signed-off-by: Huang Ying <ying.huang@intel.com>
Cc: Zhang Yanmin <yanmin.zhang@intel.com>
---
 drivers/pci/bus.c                  |    3 ---
 drivers/pci/pcie/aer/aerdrv_core.c |   20 ++++++++++++++++----
 2 files changed, 16 insertions(+), 7 deletions(-)

--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -320,10 +320,7 @@ void pci_walk_bus(struct pci_bus *top, i
 		} else
 			next = dev->bus_list.next;
 
-		/* Run device routines with the device locked */
-		device_lock(&dev->dev);
 		retval = cb(dev, userdata);
-		device_unlock(&dev->dev);
 		if (retval)
 			break;
 	}
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -213,6 +213,7 @@ static int report_error_detected(struct
 	struct aer_broadcast_data *result_data;
 	result_data = (struct aer_broadcast_data *) data;
 
+	device_lock(&dev->dev);
 	dev->error_state = result_data->state;
 
 	if (!dev->driver ||
@@ -231,12 +232,14 @@ static int report_error_detected(struct
 				   dev->driver ?
 				   "no AER-aware driver" : "no driver");
 		}
-		return 0;
+		goto out;
 	}
 
 	err_handler = dev->driver->err_handler;
 	vote = err_handler->error_detected(dev, result_data->state);
 	result_data->result = merge_result(result_data->result, vote);
+out:
+	device_unlock(&dev->dev);
 	return 0;
 }
 
@@ -247,14 +250,17 @@ static int report_mmio_enabled(struct pc
 	struct aer_broadcast_data *result_data;
 	result_data = (struct aer_broadcast_data *) data;
 
+	device_lock(&dev->dev);
 	if (!dev->driver ||
 		!dev->driver->err_handler ||
 		!dev->driver->err_handler->mmio_enabled)
-		return 0;
+		goto out;
 
 	err_handler = dev->driver->err_handler;
 	vote = err_handler->mmio_enabled(dev);
 	result_data->result = merge_result(result_data->result, vote);
+out:
+	device_unlock(&dev->dev);
 	return 0;
 }
 
@@ -265,14 +271,17 @@ static int report_slot_reset(struct pci_
 	struct aer_broadcast_data *result_data;
 	result_data = (struct aer_broadcast_data *) data;
 
+	device_lock(&dev->dev);
 	if (!dev->driver ||
 		!dev->driver->err_handler ||
 		!dev->driver->err_handler->slot_reset)
-		return 0;
+		goto out;
 
 	err_handler = dev->driver->err_handler;
 	vote = err_handler->slot_reset(dev);
 	result_data->result = merge_result(result_data->result, vote);
+out:
+	device_unlock(&dev->dev);
 	return 0;
 }
 
@@ -280,15 +289,18 @@ static int report_resume(struct pci_dev
 {
 	const struct pci_error_handlers *err_handler;
 
+	device_lock(&dev->dev);
 	dev->error_state = pci_channel_io_normal;
 
 	if (!dev->driver ||
 		!dev->driver->err_handler ||
 		!dev->driver->err_handler->resume)
-		return 0;
+		goto out;
 
 	err_handler = dev->driver->err_handler;
 	err_handler->resume(dev);
+out:
+	device_unlock(&dev->dev);
 	return 0;
 }
 

^ permalink raw reply

* [BUGFIX 2/2] PCI/PM: Resume device before shutdown
From: Huang Ying @ 2012-10-24  6:54 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-kernel, linux-pci, linux-pm, Rafael J. Wysocki, Huang Ying
In-Reply-To: <1351061654-8339-1-git-send-email-ying.huang@intel.com>

Some actions during shutdown need device to be in D0 state, such as
MSI shutdown etc, so resume device before shutdown.

Signed-off-by: Huang Ying <ying.huang@intel.com>
---
 drivers/pci/pci-driver.c |   12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -398,6 +398,8 @@ static void pci_device_shutdown(struct d
 	struct pci_dev *pci_dev = to_pci_dev(dev);
 	struct pci_driver *drv = pci_dev->driver;
 
+	pm_runtime_resume(dev);
+
 	if (drv && drv->shutdown)
 		drv->shutdown(pci_dev);
 	pci_msi_shutdown(pci_dev);
@@ -408,16 +410,6 @@ static void pci_device_shutdown(struct d
 	 * continue to do DMA
 	 */
 	pci_disable_device(pci_dev);
-
-	/*
-	 * Devices may be enabled to wake up by runtime PM, but they need not
-	 * be supposed to wake up the system from its "power off" state (e.g.
-	 * ACPI S5).  Therefore disable wakeup for all devices that aren't
-	 * supposed to wake up the system at this point.  The state argument
-	 * will be ignored by pci_enable_wake().
-	 */
-	if (!device_may_wakeup(dev))
-		pci_enable_wake(pci_dev, PCI_UNKNOWN, false);
 }
 
 #ifdef CONFIG_PM

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox