diff mbox series

[2/5] thermal/core: Add critical and hot ops

Message ID 20201210121514.25760-2-daniel.lezcano@linaro.org
State Accepted
Commit d7203eedf4f68e9909fd489453168a9d26bf0c3d
Headers show
Series [1/5] thermal/core: Emit a warning if the thermal zone is updated without ops | expand

Commit Message

Daniel Lezcano Dec. 10, 2020, 12:15 p.m. UTC
Currently there is no way to the sensors to directly call an ops in
interrupt mode without calling thermal_zone_device_update assuming all
the trip points are defined.

A sensor may want to do something special if a trip point is hot or
critical.

This patch adds the critical and hot ops to the thermal zone device,
so a sensor can directly invoke them or let the thermal framework to
call the sensor specific ones.

Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

---
 drivers/thermal/thermal_core.c | 43 +++++++++++++++++++++-------------
 include/linux/thermal.h        |  3 +++
 2 files changed, 30 insertions(+), 16 deletions(-)

-- 
2.17.1

Comments

Lukasz Luba Dec. 10, 2020, 12:44 p.m. UTC | #1
On 12/10/20 12:15 PM, Daniel Lezcano wrote:
> Currently there is no way to the sensors to directly call an ops in

> interrupt mode without calling thermal_zone_device_update assuming all

> the trip points are defined.

> 

> A sensor may want to do something special if a trip point is hot or

> critical.

> 

> This patch adds the critical and hot ops to the thermal zone device,

> so a sensor can directly invoke them or let the thermal framework to

> call the sensor specific ones.

> 

> Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>

> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

> ---

>   drivers/thermal/thermal_core.c | 43 +++++++++++++++++++++-------------

>   include/linux/thermal.h        |  3 +++

>   2 files changed, 30 insertions(+), 16 deletions(-)

> 

> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c

> index e6771e5aeedb..cee0b31b5cd7 100644

> --- a/drivers/thermal/thermal_core.c

> +++ b/drivers/thermal/thermal_core.c

> @@ -375,6 +375,25 @@ static void thermal_emergency_poweroff(void)

>   			      msecs_to_jiffies(poweroff_delay_ms));

>   }

>   

> +void thermal_zone_device_critical(struct thermal_zone_device *tz)

> +{

> +	dev_emerg(&tz->device, "%s: critical temperature reached, "

> +		  "shutting down\n", tz->type);

> +

> +	mutex_lock(&poweroff_lock);

> +	if (!power_off_triggered) {

> +		/*

> +		 * Queue a backup emergency shutdown in the event of

> +		 * orderly_poweroff failure

> +		 */

> +		thermal_emergency_poweroff();

> +		orderly_poweroff(true);

> +		power_off_triggered = true;

> +	}

> +	mutex_unlock(&poweroff_lock);

> +}

> +EXPORT_SYMBOL(thermal_zone_device_critical);

> +

>   static void handle_critical_trips(struct thermal_zone_device *tz,

>   				  int trip, enum thermal_trip_type trip_type)

>   {

> @@ -391,22 +410,10 @@ static void handle_critical_trips(struct thermal_zone_device *tz,

>   	if (tz->ops->notify)

>   		tz->ops->notify(tz, trip, trip_type);

>   

> -	if (trip_type == THERMAL_TRIP_CRITICAL) {

> -		dev_emerg(&tz->device,

> -			  "critical temperature reached (%d C), shutting down\n",

> -			  tz->temperature / 1000);

> -		mutex_lock(&poweroff_lock);

> -		if (!power_off_triggered) {

> -			/*

> -			 * Queue a backup emergency shutdown in the event of

> -			 * orderly_poweroff failure

> -			 */

> -			thermal_emergency_poweroff();

> -			orderly_poweroff(true);

> -			power_off_triggered = true;

> -		}

> -		mutex_unlock(&poweroff_lock);

> -	}

> +	if (trip_type == THERMAL_TRIP_HOT && tz->ops->hot)

> +		tz->ops->hot(tz);

> +	else if (trip_type == THERMAL_TRIP_CRITICAL)

> +		tz->ops->critical(tz);


I can see that in the patch 3/5 there driver .critical() callback
calls framework thermal_zone_device_critical() at the end.
I wonder if we could always call this framework function.

Something like a helper function always called:
void _handle_critical( *tz)
{
	if (tz->ops->critical)
		tz->ops->critical(tz);

	thermal_zone_device_critical(tz);
}

and then called:

	else if (trip_type == THERMAL_TRIP_CRITICAL)
		_handle_critical(tz);

>   }

>   

>   static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)

> @@ -1331,6 +1338,10 @@ thermal_zone_device_register(const char *type, int trips, int mask,

>   

>   	tz->id = id;

>   	strlcpy(tz->type, type, sizeof(tz->type));

> +

> +	if (!ops->critical)

> +		ops->critical = thermal_zone_device_critical;


Then we could drop this default assignment.

> +

>   	tz->ops = ops;

>   	tz->tzp = tzp;

>   	tz->device.class = &thermal_class;

> diff --git a/include/linux/thermal.h b/include/linux/thermal.h

> index f23a388ded15..125c8a4d52e6 100644

> --- a/include/linux/thermal.h

> +++ b/include/linux/thermal.h

> @@ -79,6 +79,8 @@ struct thermal_zone_device_ops {

>   			  enum thermal_trend *);

>   	int (*notify) (struct thermal_zone_device *, int,

>   		       enum thermal_trip_type);

> +	void (*hot)(struct thermal_zone_device *);

> +	void (*critical)(struct thermal_zone_device *);

>   };

>   

>   struct thermal_cooling_device_ops {

> @@ -399,6 +401,7 @@ void thermal_cdev_update(struct thermal_cooling_device *);

>   void thermal_notify_framework(struct thermal_zone_device *, int);

>   int thermal_zone_device_enable(struct thermal_zone_device *tz);

>   int thermal_zone_device_disable(struct thermal_zone_device *tz);

> +void thermal_zone_device_critical(struct thermal_zone_device *tz);

>   #else

>   static inline struct thermal_zone_device *thermal_zone_device_register(

>   	const char *type, int trips, int mask, void *devdata,

> 


I am just concerned about drivers which provide own .critical() callback
but forgot to call thermal_zone_device_critical() at the end and
framework could skip it.

Or we can make sure during the review that it's not an issue (and ignore
out of tree drivers)?

Regards,
Lukasz
Daniel Lezcano Dec. 10, 2020, 1:37 p.m. UTC | #2
On 10/12/2020 13:44, Lukasz Luba wrote:
> 

> 

> On 12/10/20 12:15 PM, Daniel Lezcano wrote:

>> Currently there is no way to the sensors to directly call an ops in

>> interrupt mode without calling thermal_zone_device_update assuming all

>> the trip points are defined.

>>

>> A sensor may want to do something special if a trip point is hot or

>> critical.

>>

>> This patch adds the critical and hot ops to the thermal zone device,

>> so a sensor can directly invoke them or let the thermal framework to

>> call the sensor specific ones.

>>

>> Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>

>> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

>> ---

>>   drivers/thermal/thermal_core.c | 43 +++++++++++++++++++++-------------

>>   include/linux/thermal.h        |  3 +++

>>   2 files changed, 30 insertions(+), 16 deletions(-)

>>

>> diff --git a/drivers/thermal/thermal_core.c

>> b/drivers/thermal/thermal_core.c

>> index e6771e5aeedb..cee0b31b5cd7 100644

>> --- a/drivers/thermal/thermal_core.c

>> +++ b/drivers/thermal/thermal_core.c

>> @@ -375,6 +375,25 @@ static void thermal_emergency_poweroff(void)

>>                     msecs_to_jiffies(poweroff_delay_ms));

>>   }

>>   +void thermal_zone_device_critical(struct thermal_zone_device *tz)

>> +{

>> +    dev_emerg(&tz->device, "%s: critical temperature reached, "

>> +          "shutting down\n", tz->type);

>> +

>> +    mutex_lock(&poweroff_lock);

>> +    if (!power_off_triggered) {

>> +        /*

>> +         * Queue a backup emergency shutdown in the event of

>> +         * orderly_poweroff failure

>> +         */

>> +        thermal_emergency_poweroff();

>> +        orderly_poweroff(true);

>> +        power_off_triggered = true;

>> +    }

>> +    mutex_unlock(&poweroff_lock);

>> +}

>> +EXPORT_SYMBOL(thermal_zone_device_critical);

>> +

>>   static void handle_critical_trips(struct thermal_zone_device *tz,

>>                     int trip, enum thermal_trip_type trip_type)

>>   {

>> @@ -391,22 +410,10 @@ static void handle_critical_trips(struct

>> thermal_zone_device *tz,

>>       if (tz->ops->notify)

>>           tz->ops->notify(tz, trip, trip_type);

>>   -    if (trip_type == THERMAL_TRIP_CRITICAL) {

>> -        dev_emerg(&tz->device,

>> -              "critical temperature reached (%d C), shutting down\n",

>> -              tz->temperature / 1000);

>> -        mutex_lock(&poweroff_lock);

>> -        if (!power_off_triggered) {

>> -            /*

>> -             * Queue a backup emergency shutdown in the event of

>> -             * orderly_poweroff failure

>> -             */

>> -            thermal_emergency_poweroff();

>> -            orderly_poweroff(true);

>> -            power_off_triggered = true;

>> -        }

>> -        mutex_unlock(&poweroff_lock);

>> -    }

>> +    if (trip_type == THERMAL_TRIP_HOT && tz->ops->hot)

>> +        tz->ops->hot(tz);

>> +    else if (trip_type == THERMAL_TRIP_CRITICAL)

>> +        tz->ops->critical(tz);

> 

> I can see that in the patch 3/5 there driver .critical() callback

> calls framework thermal_zone_device_critical() at the end.

> I wonder if we could always call this framework function.


It is actually done on purpose, we want to let the driver to handle the
critical routine which may not end up with an emergency shutdown.

[ ... ]

>>   #else

>>   static inline struct thermal_zone_device *thermal_zone_device_register(

>>       const char *type, int trips, int mask, void *devdata,

>>

> 

> I am just concerned about drivers which provide own .critical() callback

> but forgot to call thermal_zone_device_critical() at the end and

> framework could skip it.

> 

> Or we can make sure during the review that it's not an issue (and ignore

> out of tree drivers)?


Yes, the framework guarantees if the critical trip point is crossed we
call the emergency shutdown by default. If the driver choose to override
it, it takes responsibility of the change.



-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
Lukasz Luba Dec. 10, 2020, 1:51 p.m. UTC | #3
On 12/10/20 1:37 PM, Daniel Lezcano wrote:
> On 10/12/2020 13:44, Lukasz Luba wrote:

>>

>>

>> On 12/10/20 12:15 PM, Daniel Lezcano wrote:

>>> Currently there is no way to the sensors to directly call an ops in

>>> interrupt mode without calling thermal_zone_device_update assuming all

>>> the trip points are defined.

>>>

>>> A sensor may want to do something special if a trip point is hot or

>>> critical.

>>>

>>> This patch adds the critical and hot ops to the thermal zone device,

>>> so a sensor can directly invoke them or let the thermal framework to

>>> call the sensor specific ones.

>>>

>>> Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>

>>> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

>>> ---

>>>    drivers/thermal/thermal_core.c | 43 +++++++++++++++++++++-------------

>>>    include/linux/thermal.h        |  3 +++

>>>    2 files changed, 30 insertions(+), 16 deletions(-)

>>>

>>> diff --git a/drivers/thermal/thermal_core.c

>>> b/drivers/thermal/thermal_core.c

>>> index e6771e5aeedb..cee0b31b5cd7 100644

>>> --- a/drivers/thermal/thermal_core.c

>>> +++ b/drivers/thermal/thermal_core.c

>>> @@ -375,6 +375,25 @@ static void thermal_emergency_poweroff(void)

>>>                      msecs_to_jiffies(poweroff_delay_ms));

>>>    }

>>>    +void thermal_zone_device_critical(struct thermal_zone_device *tz)

>>> +{

>>> +    dev_emerg(&tz->device, "%s: critical temperature reached, "

>>> +          "shutting down\n", tz->type);

>>> +

>>> +    mutex_lock(&poweroff_lock);

>>> +    if (!power_off_triggered) {

>>> +        /*

>>> +         * Queue a backup emergency shutdown in the event of

>>> +         * orderly_poweroff failure

>>> +         */

>>> +        thermal_emergency_poweroff();

>>> +        orderly_poweroff(true);

>>> +        power_off_triggered = true;

>>> +    }

>>> +    mutex_unlock(&poweroff_lock);

>>> +}

>>> +EXPORT_SYMBOL(thermal_zone_device_critical);

>>> +

>>>    static void handle_critical_trips(struct thermal_zone_device *tz,

>>>                      int trip, enum thermal_trip_type trip_type)

>>>    {

>>> @@ -391,22 +410,10 @@ static void handle_critical_trips(struct

>>> thermal_zone_device *tz,

>>>        if (tz->ops->notify)

>>>            tz->ops->notify(tz, trip, trip_type);

>>>    -    if (trip_type == THERMAL_TRIP_CRITICAL) {

>>> -        dev_emerg(&tz->device,

>>> -              "critical temperature reached (%d C), shutting down\n",

>>> -              tz->temperature / 1000);

>>> -        mutex_lock(&poweroff_lock);

>>> -        if (!power_off_triggered) {

>>> -            /*

>>> -             * Queue a backup emergency shutdown in the event of

>>> -             * orderly_poweroff failure

>>> -             */

>>> -            thermal_emergency_poweroff();

>>> -            orderly_poweroff(true);

>>> -            power_off_triggered = true;

>>> -        }

>>> -        mutex_unlock(&poweroff_lock);

>>> -    }

>>> +    if (trip_type == THERMAL_TRIP_HOT && tz->ops->hot)

>>> +        tz->ops->hot(tz);

>>> +    else if (trip_type == THERMAL_TRIP_CRITICAL)

>>> +        tz->ops->critical(tz);

>>

>> I can see that in the patch 3/5 there driver .critical() callback

>> calls framework thermal_zone_device_critical() at the end.

>> I wonder if we could always call this framework function.

> 

> It is actually done on purpose, we want to let the driver to handle the

> critical routine which may not end up with an emergency shutdown.


I see.

> 

> [ ... ]

> 

>>>    #else

>>>    static inline struct thermal_zone_device *thermal_zone_device_register(

>>>        const char *type, int trips, int mask, void *devdata,

>>>

>>

>> I am just concerned about drivers which provide own .critical() callback

>> but forgot to call thermal_zone_device_critical() at the end and

>> framework could skip it.

>>

>> Or we can make sure during the review that it's not an issue (and ignore

>> out of tree drivers)?

> 

> Yes, the framework guarantees if the critical trip point is crossed we

> call the emergency shutdown by default. If the driver choose to override

> it, it takes responsibility of the change.

> 


Fair enough. Thus, the patch LGTM

Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>


Regards,
Lukasz
diff mbox series

Patch

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index e6771e5aeedb..cee0b31b5cd7 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -375,6 +375,25 @@  static void thermal_emergency_poweroff(void)
 			      msecs_to_jiffies(poweroff_delay_ms));
 }
 
+void thermal_zone_device_critical(struct thermal_zone_device *tz)
+{
+	dev_emerg(&tz->device, "%s: critical temperature reached, "
+		  "shutting down\n", tz->type);
+
+	mutex_lock(&poweroff_lock);
+	if (!power_off_triggered) {
+		/*
+		 * Queue a backup emergency shutdown in the event of
+		 * orderly_poweroff failure
+		 */
+		thermal_emergency_poweroff();
+		orderly_poweroff(true);
+		power_off_triggered = true;
+	}
+	mutex_unlock(&poweroff_lock);
+}
+EXPORT_SYMBOL(thermal_zone_device_critical);
+
 static void handle_critical_trips(struct thermal_zone_device *tz,
 				  int trip, enum thermal_trip_type trip_type)
 {
@@ -391,22 +410,10 @@  static void handle_critical_trips(struct thermal_zone_device *tz,
 	if (tz->ops->notify)
 		tz->ops->notify(tz, trip, trip_type);
 
-	if (trip_type == THERMAL_TRIP_CRITICAL) {
-		dev_emerg(&tz->device,
-			  "critical temperature reached (%d C), shutting down\n",
-			  tz->temperature / 1000);
-		mutex_lock(&poweroff_lock);
-		if (!power_off_triggered) {
-			/*
-			 * Queue a backup emergency shutdown in the event of
-			 * orderly_poweroff failure
-			 */
-			thermal_emergency_poweroff();
-			orderly_poweroff(true);
-			power_off_triggered = true;
-		}
-		mutex_unlock(&poweroff_lock);
-	}
+	if (trip_type == THERMAL_TRIP_HOT && tz->ops->hot)
+		tz->ops->hot(tz);
+	else if (trip_type == THERMAL_TRIP_CRITICAL)
+		tz->ops->critical(tz);
 }
 
 static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
@@ -1331,6 +1338,10 @@  thermal_zone_device_register(const char *type, int trips, int mask,
 
 	tz->id = id;
 	strlcpy(tz->type, type, sizeof(tz->type));
+
+	if (!ops->critical)
+		ops->critical = thermal_zone_device_critical;
+
 	tz->ops = ops;
 	tz->tzp = tzp;
 	tz->device.class = &thermal_class;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f23a388ded15..125c8a4d52e6 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -79,6 +79,8 @@  struct thermal_zone_device_ops {
 			  enum thermal_trend *);
 	int (*notify) (struct thermal_zone_device *, int,
 		       enum thermal_trip_type);
+	void (*hot)(struct thermal_zone_device *);
+	void (*critical)(struct thermal_zone_device *);
 };
 
 struct thermal_cooling_device_ops {
@@ -399,6 +401,7 @@  void thermal_cdev_update(struct thermal_cooling_device *);
 void thermal_notify_framework(struct thermal_zone_device *, int);
 int thermal_zone_device_enable(struct thermal_zone_device *tz);
 int thermal_zone_device_disable(struct thermal_zone_device *tz);
+void thermal_zone_device_critical(struct thermal_zone_device *tz);
 #else
 static inline struct thermal_zone_device *thermal_zone_device_register(
 	const char *type, int trips, int mask, void *devdata,