linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 2/2] power: charger-manager: Avoid recursive thermal get_temp call
  2014-10-07 15:47 [PATCH v2 1/2] power_supply: Add no_thermal property to prevent recursive get_temp calls Krzysztof Kozlowski
@ 2014-10-07 15:47 ` Krzysztof Kozlowski
  2014-10-27 18:32   ` Sebastian Reichel
  0 siblings, 1 reply; 4+ messages in thread
From: Krzysztof Kozlowski @ 2014-10-07 15:47 UTC (permalink / raw)
  To: Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	Myungjoo Ham, Anton Vorontsov, Jonghwa Lee, Chanwoo Choi,
	linux-pm, linux-kernel
  Cc: Kyungmin Park, Marek Szyprowski, Bartlomiej Zolnierkiewicz,
	Krzysztof Kozlowski

The charger manager supports POWER_SUPPLY_PROP_TEMP property and acts
as a thermal zone if any of these conditions match:
1. Fuel gauge used by charger manager supports POWER_SUPPLY_PROP_TEMP.
2. 'cm-thermal-zone' property is present in DTS (then it will supersede
   the fuel gauge temperature property).

However in case 1 (fuel gauge reports temperature and 'cm-thermal-zone'
is not set) the charger manager forwards its get_temp calls to fuel
gauge thermal zone.

This leads to reporting by lockdep a false positive deadlock for thermal
zone's mutex because of nested calls to thermal_zone_get_temp(). This is
false positive because these are different mutexes: one for charger
manager thermal zone and second for fuel gauge thermal zone.

Get rid of false lockdep alert and recursive call by setting
'no_thermal' property for this power supply class. The thermal zone for
charger manager won't be created (user space does not use it anyway).

The lockdep report:
[    2.540339] charger-manager charger-manager@0: Ignoring full-battery voltage threshold as it is not supplied
[    2.540351] charger-manager charger-manager@0: Ignoring full-battery full capacity threshold as it is not supplied
[    2.546296]
[    2.546302] =============================================
[    2.546305] [ INFO: possible recursive locking detected ]
[    2.546312] 3.17.0-rc6-next-20140926-00012-gbb13895e46af-dirty #39 Not tainted
[    2.546316] ---------------------------------------------
[    2.546321] swapper/0/1 is trying to acquire lock:
[    2.546348]  (&tz->lock){+.+...}, at: [<c0321d24>] thermal_zone_get_temp+0x38/0x68
[    2.546352]
[    2.546352] but task is already holding lock:
[    2.546369]  (&tz->lock){+.+...}, at: [<c0321d24>] thermal_zone_get_temp+0x38/0x68
[    2.546373]
[    2.546373] other info that might help us debug this:
[    2.546376]  Possible unsafe locking scenario:
[    2.546376]
[    2.546378]        CPU0
[    2.546380]        ----
[    2.546386]   lock(&tz->lock);
[    2.546392]   lock(&tz->lock);
[    2.546394]
[    2.546394]  *** DEADLOCK ***
[    2.546394]
[    2.546397]  May be due to missing lock nesting notation
[    2.546397]
[    2.546401] 2 locks held by swapper/0/1:
[    2.546430]  #0:  (&dev->mutex){......}, at: [<c02720c4>] __driver_attach+0x58/0x98
[    2.546448]  #1:  (&tz->lock){+.+...}, at: [<c0321d24>] thermal_zone_get_temp+0x38/0x68
[    2.546451]
[    2.546451] stack backtrace:
[    2.546460] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.17.0-rc6-next-20140926-00012-gbb13895e46af-dirty #39
[    2.546497] [<c00140f0>] (unwind_backtrace) from [<c0011228>] (show_stack+0x10/0x14)
[    2.546526] [<c0011228>] (show_stack) from [<c046158c>] (dump_stack+0x70/0xbc)
[    2.546554] [<c046158c>] (dump_stack) from [<c005e32c>] (validate_chain.isra.24+0x718/0x890)
[    2.546569] [<c005e32c>] (validate_chain.isra.24) from [<c005f0a0>] (__lock_acquire+0x498/0xa78)
[    2.546581] [<c005f0a0>] (__lock_acquire) from [<c005fb50>] (lock_acquire+0x78/0xb8)
[    2.546594] [<c005fb50>] (lock_acquire) from [<c0464260>] (mutex_lock_nested+0x64/0x458)
[    2.546605] [<c0464260>] (mutex_lock_nested) from [<c0321d24>] (thermal_zone_get_temp+0x38/0x68)
[    2.546634] [<c0321d24>] (thermal_zone_get_temp) from [<c031f1e0>] (charger_get_property+0x10c/0x348)
[    2.546649] [<c031f1e0>] (charger_get_property) from [<c031af18>] (power_supply_read_temp+0x28/0x58)
[    2.546662] [<c031af18>] (power_supply_read_temp) from [<c0321d38>] (thermal_zone_get_temp+0x4c/0x68)
[    2.546676] [<c0321d38>] (thermal_zone_get_temp) from [<c03233d8>] (thermal_zone_device_update+0x24/0x9c)
[    2.546687] [<c03233d8>] (thermal_zone_device_update) from [<c0323874>] (thermal_zone_device_register+0x424/0x550)
[    2.546701] [<c0323874>] (thermal_zone_device_register) from [<c031b3c0>] (__power_supply_register+0x2a4/0x348)
[    2.546714] [<c031b3c0>] (__power_supply_register) from [<c031ff64>] (charger_manager_probe+0x600/0xe5c)
[    2.546727] [<c031ff64>] (charger_manager_probe) from [<c0273384>] (platform_drv_probe+0x48/0xa4)
[    2.546746] [<c0273384>] (platform_drv_probe) from [<c0271f54>] (driver_probe_device+0x10c/0x224)
[    2.546760] [<c0271f54>] (driver_probe_device) from [<c0272100>] (__driver_attach+0x94/0x98)
[    2.546772] [<c0272100>] (__driver_attach) from [<c0270780>] (bus_for_each_dev+0x54/0x88)
[    2.546784] [<c0270780>] (bus_for_each_dev) from [<c027173c>] (bus_add_driver+0xd4/0x1d0)
[    2.546797] [<c027173c>] (bus_add_driver) from [<c027271c>] (driver_register+0x78/0xf4)
[    2.546809] [<c027271c>] (driver_register) from [<c0008984>] (do_one_initcall+0x80/0x1d4)
[    2.546829] [<c0008984>] (do_one_initcall) from [<c0612d60>] (kernel_init_freeable+0x10c/0x1d8)
[    2.546847] [<c0612d60>] (kernel_init_freeable) from [<c045c238>] (kernel_init+0x8/0xec)
[    2.546863] [<c045c238>] (kernel_init) from [<c000e828>] (ret_from_fork+0x14/0x2c)
[    2.551396] charger-manager charger-manager@0: 'chg-reg' regulator's externally_control is 0

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

---

Changes since v1:
1. Use newly introduced 'no_thermal' property to fix the issue
   definitely. Previously only one path was solved.
---
 drivers/power/charger-manager.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 7098a1ce2d3c..7a1177ea238d 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -970,6 +970,7 @@ static struct power_supply psy_default = {
 	.properties = default_charger_props,
 	.num_properties = ARRAY_SIZE(default_charger_props),
 	.get_property = charger_get_property,
+	.no_thermal = true,
 };
 
 /**
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 2/2] power: charger-manager: Avoid recursive thermal get_temp call
@ 2014-10-13  6:01 MyungJoo Ham
  2014-10-13  8:58 ` Krzysztof Kozlowski
  0 siblings, 1 reply; 4+ messages in thread
From: MyungJoo Ham @ 2014-10-13  6:01 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Sebastian Reichel, Dmitry Eremin-Solenikov,
	David Woodhouse, Anton Vorontsov, 이종화,
	최찬우, linux-pm@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: 박경민, Marek Szyprowski,
	Bartlomiej Zolnierkiewicz

>   
>  Add a 'no_thermal' property to the power supply class. If true then
> thermal zone won't be created for this power supply in
> power_supply_register().
> 
> Power supply drivers may want to set it if they support
> POWER_SUPPLY_PROP_TEMP and they are forwarding this get property call to
> other thermal zone.
> 
> If they won't set it lockdep may report false positive deadlock for
> thermal zone's mutex because of nested calls to thermal_zone_get_temp().
> First is the call to thermal_zone_get_temp() of the driver's thermal
> zone. Thermal core gets POWER_SUPPLY_PROP_TEMP property from this
> driver. The driver then calls other thermal zone thermal_zone_get_temp()
> and returns result.
> 
> Example of such driver is charger manager.
> 
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Do we really need to add another variable in the psy struct?
In the previous thread, I thought that wasn't needed, though.


Cheers,
MyungJoo

> 
> ---
> 
> Changes since v1:
> 1. New patch (new idea).
> ---
>  drivers/power/power_supply_core.c | 3 +++
>  include/linux/power_supply.h      | 6 ++++++
>  2 files changed, 9 insertions(+)
> 
> diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
> index 6cb7fe5c022d..694e8cddd5c1 100644
> --- a/drivers/power/power_supply_core.c
> +++ b/drivers/power/power_supply_core.c
> @@ -417,6 +417,9 @@ static int psy_register_thermal(struct power_supply *psy)
>  {
>  	int i;
>  
> +	if (psy->no_thermal)
> +		return 0;
> +
>  	/* Register battery zone device psy reports temperature */
>  	for (i = 0; i < psy->num_properties; i++) {
>  		if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) {
> diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
> index 3ed049673022..096dbced02ac 100644
> --- a/include/linux/power_supply.h
> +++ b/include/linux/power_supply.h
> @@ -200,6 +200,12 @@ struct power_supply {
>  	void (*external_power_changed)(struct power_supply *psy);
>  	void (*set_charged)(struct power_supply *psy);
>  
> +	/*
> +	 * Set if thermal zone should not be created for this power supply.
> +	 * For example for virtual supplies forwarding calls to actual
> +	 * sensors or other supplies.
> +	 */
> +	bool no_thermal;
>  	/* For APM emulation, think legacy userspace. */
>  	int use_for_apm;
>  
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 2/2] power: charger-manager: Avoid recursive thermal get_temp call
  2014-10-13  6:01 [PATCH v2 2/2] power: charger-manager: Avoid recursive thermal get_temp call MyungJoo Ham
@ 2014-10-13  8:58 ` Krzysztof Kozlowski
  0 siblings, 0 replies; 4+ messages in thread
From: Krzysztof Kozlowski @ 2014-10-13  8:58 UTC (permalink / raw)
  To: myungjoo.ham
  Cc: Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	Anton Vorontsov, 이종화,
	최찬우, linux-pm@vger.kernel.org,
	linux-kernel@vger.kernel.org, 박경민,
	Marek Szyprowski, Bartlomiej Zolnierkiewicz

On pon, 2014-10-13 at 06:01 +0000, MyungJoo Ham wrote:
> >   
> >  Add a 'no_thermal' property to the power supply class. If true then
> > thermal zone won't be created for this power supply in
> > power_supply_register().
> > 
> > Power supply drivers may want to set it if they support
> > POWER_SUPPLY_PROP_TEMP and they are forwarding this get property call to
> > other thermal zone.
> > 
> > If they won't set it lockdep may report false positive deadlock for
> > thermal zone's mutex because of nested calls to thermal_zone_get_temp().
> > First is the call to thermal_zone_get_temp() of the driver's thermal
> > zone. Thermal core gets POWER_SUPPLY_PROP_TEMP property from this
> > driver. The driver then calls other thermal zone thermal_zone_get_temp()
> > and returns result.
> > 
> > Example of such driver is charger manager.
> > 
> > Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> 
> Do we really need to add another variable in the psy struct?
> In the previous thread, I thought that wasn't needed, though.

I considered the idea mentioned by  Jonghwa Lee:

static int psy_register_thermal(struct power_supply *psy)
{
...
+       if (psy->tzd)
+               return 0; 

but there would be problem in determining the ownership of the thermal
zone - who should unregister that thermal zone? Charger manager's power
supply or fuel gauge's power supply?

We could NULL-ify it manually from charger's remove function before
calling power_supply_unregister... but it is really accessing a private
field of power_supply structure. 

I think this should be done in API-level.

Best regards,
Krzysztof

> 
> 
> Cheers,
> MyungJoo
> 
> > 
> > ---
> > 
> > Changes since v1:
> > 1. New patch (new idea).
> > ---
> >  drivers/power/power_supply_core.c | 3 +++
> >  include/linux/power_supply.h      | 6 ++++++
> >  2 files changed, 9 insertions(+)
> > 
> > diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
> > index 6cb7fe5c022d..694e8cddd5c1 100644
> > --- a/drivers/power/power_supply_core.c
> > +++ b/drivers/power/power_supply_core.c
> > @@ -417,6 +417,9 @@ static int psy_register_thermal(struct power_supply *psy)
> >  {
> >  	int i;
> >  
> > +	if (psy->no_thermal)
> > +		return 0;
> > +
> >  	/* Register battery zone device psy reports temperature */
> >  	for (i = 0; i < psy->num_properties; i++) {
> >  		if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) {
> > diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
> > index 3ed049673022..096dbced02ac 100644
> > --- a/include/linux/power_supply.h
> > +++ b/include/linux/power_supply.h
> > @@ -200,6 +200,12 @@ struct power_supply {
> >  	void (*external_power_changed)(struct power_supply *psy);
> >  	void (*set_charged)(struct power_supply *psy);
> >  
> > +	/*
> > +	 * Set if thermal zone should not be created for this power supply.
> > +	 * For example for virtual supplies forwarding calls to actual
> > +	 * sensors or other supplies.
> > +	 */
> > +	bool no_thermal;
> >  	/* For APM emulation, think legacy userspace. */
> >  	int use_for_apm;
> >  
> > -- 
> > 1.9.1
> > 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 2/2] power: charger-manager: Avoid recursive thermal get_temp call
  2014-10-07 15:47 ` [PATCH v2 2/2] power: charger-manager: Avoid recursive thermal get_temp call Krzysztof Kozlowski
@ 2014-10-27 18:32   ` Sebastian Reichel
  0 siblings, 0 replies; 4+ messages in thread
From: Sebastian Reichel @ 2014-10-27 18:32 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Dmitry Eremin-Solenikov, David Woodhouse, Myungjoo Ham,
	Anton Vorontsov, Jonghwa Lee, Chanwoo Choi, linux-pm,
	linux-kernel, Kyungmin Park, Marek Szyprowski,
	Bartlomiej Zolnierkiewicz

[-- Attachment #1: Type: text/plain, Size: 1167 bytes --]

Hi,

On Tue, Oct 07, 2014 at 05:47:37PM +0200, Krzysztof Kozlowski wrote:
> The charger manager supports POWER_SUPPLY_PROP_TEMP property and acts
> as a thermal zone if any of these conditions match:
> 1. Fuel gauge used by charger manager supports POWER_SUPPLY_PROP_TEMP.
> 2. 'cm-thermal-zone' property is present in DTS (then it will supersede
>    the fuel gauge temperature property).
> 
> However in case 1 (fuel gauge reports temperature and 'cm-thermal-zone'
> is not set) the charger manager forwards its get_temp calls to fuel
> gauge thermal zone.
> 
> This leads to reporting by lockdep a false positive deadlock for thermal
> zone's mutex because of nested calls to thermal_zone_get_temp(). This is
> false positive because these are different mutexes: one for charger
> manager thermal zone and second for fuel gauge thermal zone.
> 
> Get rid of false lockdep alert and recursive call by setting
> 'no_thermal' property for this power supply class. The thermal zone for
> charger manager won't be created (user space does not use it anyway).

also pulled into next, will also be included in 3.18-rc pull request.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2014-10-27 18:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-13  6:01 [PATCH v2 2/2] power: charger-manager: Avoid recursive thermal get_temp call MyungJoo Ham
2014-10-13  8:58 ` Krzysztof Kozlowski
  -- strict thread matches above, loose matches on Subject: below --
2014-10-07 15:47 [PATCH v2 1/2] power_supply: Add no_thermal property to prevent recursive get_temp calls Krzysztof Kozlowski
2014-10-07 15:47 ` [PATCH v2 2/2] power: charger-manager: Avoid recursive thermal get_temp call Krzysztof Kozlowski
2014-10-27 18:32   ` Sebastian Reichel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).