| 1 | ===================================
|
| 2 | Generic Thermal Sysfs driver How To
|
| 3 | ===================================
|
| 4 |
|
| 5 | Written by Sujith Thomas <[email protected]>, Zhang Rui <[email protected]>
|
| 6 |
|
| 7 | Copyright (c) 2008 Intel Corporation
|
| 8 |
|
| 9 |
|
| 10 | 0. Introduction
|
| 11 | ===============
|
| 12 |
|
| 13 | The generic thermal sysfs provides a set of interfaces for thermal zone
|
| 14 | devices (sensors) and thermal cooling devices (fan, processor...) to register
|
| 15 | with the thermal management solution and to be a part of it.
|
| 16 |
|
| 17 | This how-to focuses on enabling new thermal zone and cooling devices to
|
| 18 | participate in thermal management.
|
| 19 | This solution is platform independent and any type of thermal zone devices
|
| 20 | and cooling devices should be able to make use of the infrastructure.
|
| 21 |
|
| 22 | The main task of the thermal sysfs driver is to expose thermal zone attributes
|
| 23 | as well as cooling device attributes to the user space.
|
| 24 | An intelligent thermal management application can make decisions based on
|
| 25 | inputs from thermal zone attributes (the current temperature and trip point
|
| 26 | temperature) and throttle appropriate devices.
|
| 27 |
|
| 28 | - `[0-*]` denotes any positive number starting from 0
|
| 29 | - `[1-*]` denotes any positive number starting from 1
|
| 30 |
|
| 31 | 1. thermal sysfs driver interface functions
|
| 32 | ===========================================
|
| 33 |
|
| 34 | 1.1 thermal zone device interface
|
| 35 | ---------------------------------
|
| 36 |
|
| 37 | ::
|
| 38 |
|
| 39 | struct thermal_zone_device *
|
| 40 | thermal_zone_device_register_with_trips(const char *type,
|
| 41 | const struct thermal_trip *trips,
|
| 42 | int num_trips, void *devdata,
|
| 43 | const struct thermal_zone_device_ops *ops,
|
| 44 | const struct thermal_zone_params *tzp,
|
| 45 | unsigned int passive_delay,
|
| 46 | unsigned int polling_delay)
|
| 47 |
|
| 48 | This interface function adds a new thermal zone device (sensor) to the
|
| 49 | /sys/class/thermal folder as `thermal_zone[0-*]`. It tries to bind all the
|
| 50 | thermal cooling devices registered to it at the same time.
|
| 51 |
|
| 52 | type:
|
| 53 | the thermal zone type.
|
| 54 | trips:
|
| 55 | the table of trip points for this thermal zone.
|
| 56 | devdata:
|
| 57 | device private data
|
| 58 | ops:
|
| 59 | thermal zone device call-backs.
|
| 60 |
|
| 61 | .should_bind:
|
| 62 | check whether or not a given cooling device should be bound to
|
| 63 | a given trip point in this thermal zone.
|
| 64 | .get_temp:
|
| 65 | get the current temperature of the thermal zone.
|
| 66 | .set_trips:
|
| 67 | set the trip points window. Whenever the current temperature
|
| 68 | is updated, the trip points immediately below and above the
|
| 69 | current temperature are found.
|
| 70 | .change_mode:
|
| 71 | change the mode (enabled/disabled) of the thermal zone.
|
| 72 | .set_trip_temp:
|
| 73 | set the temperature of a given trip point.
|
| 74 | .get_crit_temp:
|
| 75 | get the critical temperature for this thermal zone.
|
| 76 | .set_emul_temp:
|
| 77 | set the emulation temperature which helps in debugging
|
| 78 | different threshold temperature points.
|
| 79 | .get_trend:
|
| 80 | get the trend of most recent zone temperature changes.
|
| 81 | .hot:
|
| 82 | hot trip point crossing handler.
|
| 83 | .critical:
|
| 84 | critical trip point crossing handler.
|
| 85 | tzp:
|
| 86 | thermal zone platform parameters.
|
| 87 | passive_delay:
|
| 88 | number of milliseconds to wait between polls when performing passive
|
| 89 | cooling.
|
| 90 | polling_delay:
|
| 91 | number of milliseconds to wait between polls when checking
|
| 92 | whether trip points have been crossed (0 for interrupt driven systems).
|
| 93 |
|
| 94 | ::
|
| 95 |
|
| 96 | void thermal_zone_device_unregister(struct thermal_zone_device *tz)
|
| 97 |
|
| 98 | This interface function removes the thermal zone device.
|
| 99 | It deletes the corresponding entry from /sys/class/thermal folder and
|
| 100 | unbinds all the thermal cooling devices it uses.
|
| 101 |
|
| 102 | ::
|
| 103 |
|
| 104 | struct thermal_zone_device
|
| 105 | *thermal_zone_of_sensor_register(struct device *dev, int sensor_id,
|
| 106 | void *data,
|
| 107 | const struct thermal_zone_of_device_ops *ops)
|
| 108 |
|
| 109 | This interface adds a new sensor to a DT thermal zone.
|
| 110 | This function will search the list of thermal zones described in
|
| 111 | device tree and look for the zone that refer to the sensor device
|
| 112 | pointed by dev->of_node as temperature providers. For the zone
|
| 113 | pointing to the sensor node, the sensor will be added to the DT
|
| 114 | thermal zone device.
|
| 115 |
|
| 116 | The parameters for this interface are:
|
| 117 |
|
| 118 | dev:
|
| 119 | Device node of sensor containing valid node pointer in
|
| 120 | dev->of_node.
|
| 121 | sensor_id:
|
| 122 | a sensor identifier, in case the sensor IP has more
|
| 123 | than one sensors
|
| 124 | data:
|
| 125 | a private pointer (owned by the caller) that will be
|
| 126 | passed back, when a temperature reading is needed.
|
| 127 | ops:
|
| 128 | `struct thermal_zone_of_device_ops *`.
|
| 129 |
|
| 130 | ============== =======================================
|
| 131 | get_temp a pointer to a function that reads the
|
| 132 | sensor temperature. This is mandatory
|
| 133 | callback provided by sensor driver.
|
| 134 | set_trips a pointer to a function that sets a
|
| 135 | temperature window. When this window is
|
| 136 | left the driver must inform the thermal
|
| 137 | core via thermal_zone_device_update.
|
| 138 | get_trend a pointer to a function that reads the
|
| 139 | sensor temperature trend.
|
| 140 | set_emul_temp a pointer to a function that sets
|
| 141 | sensor emulated temperature.
|
| 142 | ============== =======================================
|
| 143 |
|
| 144 | The thermal zone temperature is provided by the get_temp() function
|
| 145 | pointer of thermal_zone_of_device_ops. When called, it will
|
| 146 | have the private pointer @data back.
|
| 147 |
|
| 148 | It returns error pointer if fails otherwise valid thermal zone device
|
| 149 | handle. Caller should check the return handle with IS_ERR() for finding
|
| 150 | whether success or not.
|
| 151 |
|
| 152 | ::
|
| 153 |
|
| 154 | void thermal_zone_of_sensor_unregister(struct device *dev,
|
| 155 | struct thermal_zone_device *tzd)
|
| 156 |
|
| 157 | This interface unregisters a sensor from a DT thermal zone which was
|
| 158 | successfully added by interface thermal_zone_of_sensor_register().
|
| 159 | This function removes the sensor callbacks and private data from the
|
| 160 | thermal zone device registered with thermal_zone_of_sensor_register()
|
| 161 | interface. It will also silent the zone by remove the .get_temp() and
|
| 162 | get_trend() thermal zone device callbacks.
|
| 163 |
|
| 164 | ::
|
| 165 |
|
| 166 | struct thermal_zone_device
|
| 167 | *devm_thermal_zone_of_sensor_register(struct device *dev,
|
| 168 | int sensor_id,
|
| 169 | void *data,
|
| 170 | const struct thermal_zone_of_device_ops *ops)
|
| 171 |
|
| 172 | This interface is resource managed version of
|
| 173 | thermal_zone_of_sensor_register().
|
| 174 |
|
| 175 | All details of thermal_zone_of_sensor_register() described in
|
| 176 | section 1.1.3 is applicable here.
|
| 177 |
|
| 178 | The benefit of using this interface to register sensor is that it
|
| 179 | is not require to explicitly call thermal_zone_of_sensor_unregister()
|
| 180 | in error path or during driver unbinding as this is done by driver
|
| 181 | resource manager.
|
| 182 |
|
| 183 | ::
|
| 184 |
|
| 185 | void devm_thermal_zone_of_sensor_unregister(struct device *dev,
|
| 186 | struct thermal_zone_device *tzd)
|
| 187 |
|
| 188 | This interface is resource managed version of
|
| 189 | thermal_zone_of_sensor_unregister().
|
| 190 | All details of thermal_zone_of_sensor_unregister() described in
|
| 191 | section 1.1.4 is applicable here.
|
| 192 | Normally this function will not need to be called and the resource
|
| 193 | management code will ensure that the resource is freed.
|
| 194 |
|
| 195 | ::
|
| 196 |
|
| 197 | int thermal_zone_get_slope(struct thermal_zone_device *tz)
|
| 198 |
|
| 199 | This interface is used to read the slope attribute value
|
| 200 | for the thermal zone device, which might be useful for platform
|
| 201 | drivers for temperature calculations.
|
| 202 |
|
| 203 | ::
|
| 204 |
|
| 205 | int thermal_zone_get_offset(struct thermal_zone_device *tz)
|
| 206 |
|
| 207 | This interface is used to read the offset attribute value
|
| 208 | for the thermal zone device, which might be useful for platform
|
| 209 | drivers for temperature calculations.
|
| 210 |
|
| 211 | 1.2 thermal cooling device interface
|
| 212 | ------------------------------------
|
| 213 |
|
| 214 |
|
| 215 | ::
|
| 216 |
|
| 217 | struct thermal_cooling_device
|
| 218 | *thermal_cooling_device_register(char *name,
|
| 219 | void *devdata, struct thermal_cooling_device_ops *)
|
| 220 |
|
| 221 | This interface function adds a new thermal cooling device (fan/processor/...)
|
| 222 | to /sys/class/thermal/ folder as `cooling_device[0-*]`. It tries to bind itself
|
| 223 | to all the thermal zone devices registered at the same time.
|
| 224 |
|
| 225 | name:
|
| 226 | the cooling device name.
|
| 227 | devdata:
|
| 228 | device private data.
|
| 229 | ops:
|
| 230 | thermal cooling devices call-backs.
|
| 231 |
|
| 232 | .get_max_state:
|
| 233 | get the Maximum throttle state of the cooling device.
|
| 234 | .get_cur_state:
|
| 235 | get the Currently requested throttle state of the
|
| 236 | cooling device.
|
| 237 | .set_cur_state:
|
| 238 | set the Current throttle state of the cooling device.
|
| 239 |
|
| 240 | ::
|
| 241 |
|
| 242 | void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
|
| 243 |
|
| 244 | This interface function removes the thermal cooling device.
|
| 245 | It deletes the corresponding entry from /sys/class/thermal folder and
|
| 246 | unbinds itself from all the thermal zone devices using it.
|
| 247 |
|
| 248 | 1.4 Thermal Zone Parameters
|
| 249 | ---------------------------
|
| 250 |
|
| 251 | ::
|
| 252 |
|
| 253 | struct thermal_zone_params
|
| 254 |
|
| 255 | This structure defines the platform level parameters for a thermal zone.
|
| 256 | This data, for each thermal zone should come from the platform layer.
|
| 257 | This is an optional feature where some platforms can choose not to
|
| 258 | provide this data.
|
| 259 |
|
| 260 | .governor_name:
|
| 261 | Name of the thermal governor used for this zone
|
| 262 | .no_hwmon:
|
| 263 | a boolean to indicate if the thermal to hwmon sysfs interface
|
| 264 | is required. when no_hwmon == false, a hwmon sysfs interface
|
| 265 | will be created. when no_hwmon == true, nothing will be done.
|
| 266 | In case the thermal_zone_params is NULL, the hwmon interface
|
| 267 | will be created (for backward compatibility).
|
| 268 |
|
| 269 | 2. sysfs attributes structure
|
| 270 | =============================
|
| 271 |
|
| 272 | == ================
|
| 273 | RO read only value
|
| 274 | WO write only value
|
| 275 | RW read/write value
|
| 276 | == ================
|
| 277 |
|
| 278 | Thermal sysfs attributes will be represented under /sys/class/thermal.
|
| 279 | Hwmon sysfs I/F extension is also available under /sys/class/hwmon
|
| 280 | if hwmon is compiled in or built as a module.
|
| 281 |
|
| 282 | Thermal zone device sys I/F, created once it's registered::
|
| 283 |
|
| 284 | /sys/class/thermal/thermal_zone[0-*]:
|
| 285 | |---type: Type of the thermal zone
|
| 286 | |---temp: Current temperature
|
| 287 | |---mode: Working mode of the thermal zone
|
| 288 | |---policy: Thermal governor used for this zone
|
| 289 | |---available_policies: Available thermal governors for this zone
|
| 290 | |---trip_point_[0-*]_temp: Trip point temperature
|
| 291 | |---trip_point_[0-*]_type: Trip point type
|
| 292 | |---trip_point_[0-*]_hyst: Hysteresis value for this trip point
|
| 293 | |---emul_temp: Emulated temperature set node
|
| 294 | |---sustainable_power: Sustainable dissipatable power
|
| 295 | |---k_po: Proportional term during temperature overshoot
|
| 296 | |---k_pu: Proportional term during temperature undershoot
|
| 297 | |---k_i: PID's integral term in the power allocator gov
|
| 298 | |---k_d: PID's derivative term in the power allocator
|
| 299 | |---integral_cutoff: Offset above which errors are accumulated
|
| 300 | |---slope: Slope constant applied as linear extrapolation
|
| 301 | |---offset: Offset constant applied as linear extrapolation
|
| 302 |
|
| 303 | Thermal cooling device sys I/F, created once it's registered::
|
| 304 |
|
| 305 | /sys/class/thermal/cooling_device[0-*]:
|
| 306 | |---type: Type of the cooling device(processor/fan/...)
|
| 307 | |---max_state: Maximum cooling state of the cooling device
|
| 308 | |---cur_state: Current cooling state of the cooling device
|
| 309 | |---stats: Directory containing cooling device's statistics
|
| 310 | |---stats/reset: Writing any value resets the statistics
|
| 311 | |---stats/time_in_state_ms: Time (msec) spent in various cooling states
|
| 312 | |---stats/total_trans: Total number of times cooling state is changed
|
| 313 | |---stats/trans_table: Cooling state transition table
|
| 314 |
|
| 315 |
|
| 316 | Then next two dynamic attributes are created/removed in pairs. They represent
|
| 317 | the relationship between a thermal zone and its associated cooling device.
|
| 318 |
|
| 319 | ::
|
| 320 |
|
| 321 | /sys/class/thermal/thermal_zone[0-*]:
|
| 322 | |---cdev[0-*]: [0-*]th cooling device in current thermal zone
|
| 323 | |---cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with
|
| 324 | |---cdev[0-*]_weight: Influence of the cooling device in
|
| 325 | this thermal zone
|
| 326 |
|
| 327 | Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,
|
| 328 | the generic thermal driver also creates a hwmon sysfs I/F for each _type_
|
| 329 | of thermal zone device. E.g. the generic thermal driver registers one hwmon
|
| 330 | class device and build the associated hwmon sysfs I/F for all the registered
|
| 331 | ACPI thermal zones.
|
| 332 |
|
| 333 | Please read Documentation/ABI/testing/sysfs-class-thermal for thermal
|
| 334 | zone and cooling device attribute details.
|
| 335 |
|
| 336 | ::
|
| 337 |
|
| 338 | /sys/class/hwmon/hwmon[0-*]:
|
| 339 | |---name: The type of the thermal zone devices
|
| 340 | |---temp[1-*]_input: The current temperature of thermal zone [1-*]
|
| 341 | |---temp[1-*]_critical: The critical trip point of thermal zone [1-*]
|
| 342 |
|
| 343 | Please read Documentation/hwmon/sysfs-interface.rst for additional information.
|
| 344 |
|
| 345 | 3. A simple implementation
|
| 346 | ==========================
|
| 347 |
|
| 348 | ACPI thermal zone may support multiple trip points like critical, hot,
|
| 349 | passive, active. If an ACPI thermal zone supports critical, passive,
|
| 350 | active[0] and active[1] at the same time, it may register itself as a
|
| 351 | thermal_zone_device (thermal_zone1) with 4 trip points in all.
|
| 352 | It has one processor and one fan, which are both registered as
|
| 353 | thermal_cooling_device. Both are considered to have the same
|
| 354 | effectiveness in cooling the thermal zone.
|
| 355 |
|
| 356 | If the processor is listed in _PSL method, and the fan is listed in _AL0
|
| 357 | method, the sys I/F structure will be built like this::
|
| 358 |
|
| 359 | /sys/class/thermal:
|
| 360 | |thermal_zone1:
|
| 361 | |---type: acpitz
|
| 362 | |---temp: 37000
|
| 363 | |---mode: enabled
|
| 364 | |---policy: step_wise
|
| 365 | |---available_policies: step_wise fair_share
|
| 366 | |---trip_point_0_temp: 100000
|
| 367 | |---trip_point_0_type: critical
|
| 368 | |---trip_point_1_temp: 80000
|
| 369 | |---trip_point_1_type: passive
|
| 370 | |---trip_point_2_temp: 70000
|
| 371 | |---trip_point_2_type: active0
|
| 372 | |---trip_point_3_temp: 60000
|
| 373 | |---trip_point_3_type: active1
|
| 374 | |---cdev0: --->/sys/class/thermal/cooling_device0
|
| 375 | |---cdev0_trip_point: 1 /* cdev0 can be used for passive */
|
| 376 | |---cdev0_weight: 1024
|
| 377 | |---cdev1: --->/sys/class/thermal/cooling_device3
|
| 378 | |---cdev1_trip_point: 2 /* cdev1 can be used for active[0]*/
|
| 379 | |---cdev1_weight: 1024
|
| 380 |
|
| 381 | |cooling_device0:
|
| 382 | |---type: Processor
|
| 383 | |---max_state: 8
|
| 384 | |---cur_state: 0
|
| 385 |
|
| 386 | |cooling_device3:
|
| 387 | |---type: Fan
|
| 388 | |---max_state: 2
|
| 389 | |---cur_state: 0
|
| 390 |
|
| 391 | /sys/class/hwmon:
|
| 392 | |hwmon0:
|
| 393 | |---name: acpitz
|
| 394 | |---temp1_input: 37000
|
| 395 | |---temp1_crit: 100000
|
| 396 |
|
| 397 | 4. Export Symbol APIs
|
| 398 | =====================
|
| 399 |
|
| 400 | 4.1. get_tz_trend
|
| 401 | -----------------
|
| 402 |
|
| 403 | This function returns the trend of a thermal zone, i.e the rate of change
|
| 404 | of temperature of the thermal zone. Ideally, the thermal sensor drivers
|
| 405 | are supposed to implement the callback. If they don't, the thermal
|
| 406 | framework calculated the trend by comparing the previous and the current
|
| 407 | temperature values.
|
| 408 |
|
| 409 | 4.2. thermal_cdev_update
|
| 410 | ------------------------
|
| 411 |
|
| 412 | This function serves as an arbitrator to set the state of a cooling
|
| 413 | device. It sets the cooling device to the deepest cooling state if
|
| 414 | possible.
|
| 415 |
|
| 416 | 5. Critical Events
|
| 417 | ==================
|
| 418 |
|
| 419 | On an event of critical trip temperature crossing, the thermal framework
|
| 420 | will trigger a hardware protection power-off (shutdown) or reboot,
|
| 421 | depending on configuration.
|
| 422 |
|
| 423 | At first, the kernel will attempt an orderly power-off or reboot, but
|
| 424 | accepts a delay after which it proceeds to do a forced power-off or
|
| 425 | reboot, respectively. If this fails, ``emergency_restart()`` is invoked
|
| 426 | as last resort.
|
| 427 |
|
| 428 | The delay should be carefully profiled so as to give adequate time for
|
| 429 | orderly power-off or reboot.
|
| 430 |
|
| 431 | If the delay is set to 0, the emergency action will not be supported. So a
|
| 432 | carefully profiled non-zero positive value is a must for the emergency
|
| 433 | action to be triggered.
|