]> Git Repo - linux.git/blob - drivers/thermal/thermal_trip.c
ACPI: CPPC: Adjust debug messages in amd_set_max_freq_ratio() to warn
[linux.git] / drivers / thermal / thermal_trip.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Copyright (C) 2008 Intel Corp
4  *  Copyright (C) 2008 Zhang Rui <[email protected]>
5  *  Copyright (C) 2008 Sujith Thomas <[email protected]>
6  *  Copyright 2022 Linaro Limited
7  *
8  * Thermal trips handling
9  */
10 #include "thermal_core.h"
11
12 static const char *trip_type_names[] = {
13         [THERMAL_TRIP_ACTIVE] = "active",
14         [THERMAL_TRIP_PASSIVE] = "passive",
15         [THERMAL_TRIP_HOT] = "hot",
16         [THERMAL_TRIP_CRITICAL] = "critical",
17 };
18
19 const char *thermal_trip_type_name(enum thermal_trip_type trip_type)
20 {
21         if (trip_type < THERMAL_TRIP_ACTIVE || trip_type > THERMAL_TRIP_CRITICAL)
22                 return "unknown";
23
24         return trip_type_names[trip_type];
25 }
26
27 int for_each_thermal_trip(struct thermal_zone_device *tz,
28                           int (*cb)(struct thermal_trip *, void *),
29                           void *data)
30 {
31         struct thermal_trip_desc *td;
32         int ret;
33
34         for_each_trip_desc(tz, td) {
35                 ret = cb(&td->trip, data);
36                 if (ret)
37                         return ret;
38         }
39
40         return 0;
41 }
42 EXPORT_SYMBOL_GPL(for_each_thermal_trip);
43
44 int thermal_zone_for_each_trip(struct thermal_zone_device *tz,
45                                int (*cb)(struct thermal_trip *, void *),
46                                void *data)
47 {
48         int ret;
49
50         mutex_lock(&tz->lock);
51         ret = for_each_thermal_trip(tz, cb, data);
52         mutex_unlock(&tz->lock);
53
54         return ret;
55 }
56 EXPORT_SYMBOL_GPL(thermal_zone_for_each_trip);
57
58 int thermal_zone_get_num_trips(struct thermal_zone_device *tz)
59 {
60         return tz->num_trips;
61 }
62 EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips);
63
64 /**
65  * thermal_zone_set_trips - Computes the next trip points for the driver
66  * @tz: a pointer to a thermal zone device structure
67  *
68  * The function computes the next temperature boundaries by browsing
69  * the trip points. The result is the closer low and high trip points
70  * to the current temperature. These values are passed to the backend
71  * driver to let it set its own notification mechanism (usually an
72  * interrupt).
73  *
74  * This function must be called with tz->lock held. Both tz and tz->ops
75  * must be valid pointers.
76  *
77  * It does not return a value
78  */
79 void thermal_zone_set_trips(struct thermal_zone_device *tz)
80 {
81         const struct thermal_trip_desc *td;
82         int low = -INT_MAX, high = INT_MAX;
83         int ret;
84
85         lockdep_assert_held(&tz->lock);
86
87         if (!tz->ops.set_trips)
88                 return;
89
90         for_each_trip_desc(tz, td) {
91                 if (td->threshold < tz->temperature && td->threshold > low)
92                         low = td->threshold;
93
94                 if (td->threshold > tz->temperature && td->threshold < high)
95                         high = td->threshold;
96         }
97
98         /* No need to change trip points */
99         if (tz->prev_low_trip == low && tz->prev_high_trip == high)
100                 return;
101
102         tz->prev_low_trip = low;
103         tz->prev_high_trip = high;
104
105         dev_dbg(&tz->device,
106                 "new temperature boundaries: %d < x < %d\n", low, high);
107
108         /*
109          * Set a temperature window. When this window is left the driver
110          * must inform the thermal core via thermal_zone_device_update.
111          */
112         ret = tz->ops.set_trips(tz, low, high);
113         if (ret)
114                 dev_err(&tz->device, "Failed to set trips: %d\n", ret);
115 }
116
117 int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
118                           struct thermal_trip *trip)
119 {
120         if (!tz || !trip || trip_id < 0 || trip_id >= tz->num_trips)
121                 return -EINVAL;
122
123         mutex_lock(&tz->lock);
124         *trip = tz->trips[trip_id].trip;
125         mutex_unlock(&tz->lock);
126
127         return 0;
128 }
129 EXPORT_SYMBOL_GPL(thermal_zone_get_trip);
130
131 int thermal_zone_trip_id(const struct thermal_zone_device *tz,
132                          const struct thermal_trip *trip)
133 {
134         /*
135          * Assume the trip to be located within the bounds of the thermal
136          * zone's trips[] table.
137          */
138         return trip_to_trip_desc(trip) - tz->trips;
139 }
140
141 void thermal_zone_trip_updated(struct thermal_zone_device *tz,
142                                const struct thermal_trip *trip)
143 {
144         thermal_notify_tz_trip_change(tz, trip);
145         __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
146 }
147
148 void thermal_zone_set_trip_temp(struct thermal_zone_device *tz,
149                                 struct thermal_trip *trip, int temp)
150 {
151         if (trip->temperature == temp)
152                 return;
153
154         WRITE_ONCE(trip->temperature, temp);
155         thermal_notify_tz_trip_change(tz, trip);
156
157         if (temp == THERMAL_TEMP_INVALID) {
158                 struct thermal_trip_desc *td = trip_to_trip_desc(trip);
159
160                 if (tz->temperature >= td->threshold) {
161                         /*
162                          * The trip has been crossed on the way up, so some
163                          * adjustments are needed to compensate for the lack
164                          * of it going forward.
165                          */
166                         if (trip->type == THERMAL_TRIP_PASSIVE) {
167                                 tz->passive--;
168                                 WARN_ON_ONCE(tz->passive < 0);
169                         }
170                         thermal_zone_trip_down(tz, trip);
171                 }
172                 /*
173                  * Invalidate the threshold to avoid triggering a spurious
174                  * trip crossing notification when the trip becomes valid.
175                  */
176                 td->threshold = INT_MAX;
177         }
178 }
179 EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp);
This page took 0.05648 seconds and 4 git commands to generate.