Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'thermal-6.8-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull more thermal control updates from Rafael Wysocki:
"These add support for debugfs-based diagnostics to the thermal core,
simplify the thermal netlink API, fix system-wide PM support in the
Intel HFI driver and clean up some code.

Specifics:

- Add debugfs-based diagnostics support to the thermal core (Daniel
Lezcano, Dan Carpenter)

- Fix a power allocator thermal governor issue preventing it from
resetting cooling devices sometimes (Di Shen)

- Simplify the thermal netlink API and clean up related code (Rafael
J. Wysocki)

- Make the Intel HFI driver support hibernation and deep suspend
properly (Ricardo Neri)"

* tag 'thermal-6.8-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
thermal/debugfs: Unlock on error path in thermal_debug_tz_trip_up()
thermal: intel: hfi: Add syscore callbacks for system-wide PM
thermal: gov_power_allocator: avoid inability to reset a cdev
thermal: helpers: Rearrange thermal_cdev_set_cur_state()
thermal: netlink: Rework notify API for cooling devices
thermal: core: Use kstrdup_const() during cooling device registration
thermal/debugfs: Add thermal debugfs information for mitigation episodes
thermal/debugfs: Add thermal cooling device debugfs information
thermal: netlink: Pass thermal zone pointer to notify routines
thermal: netlink: Drop thermal_notify_tz_trip_add/delete()
thermal: netlink: Pass pointers to thermal_notify_tz_trip_up/down()
thermal: netlink: Pass pointers to thermal_notify_tz_trip_change()

+1026 -127
+7
drivers/thermal/Kconfig
··· 33 33 34 34 If in doubt, say N. 35 35 36 + config THERMAL_DEBUGFS 37 + bool "Thermal subsystem debug support" 38 + depends on DEBUG_FS 39 + help 40 + Say Y to allow the thermal subsystem to collect diagnostic 41 + information that can be accessed via debugfs. 42 + 36 43 config THERMAL_EMERGENCY_POWEROFF_DELAY_MS 37 44 int "Emergency poweroff delay in milli-seconds" 38 45 default 0
+2
drivers/thermal/Makefile
··· 10 10 # netlink interface to manage the thermal framework 11 11 thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o 12 12 13 + thermal_sys-$(CONFIG_THERMAL_DEBUGFS) += thermal_debugfs.o 14 + 13 15 # interface to/from other layers providing sensors 14 16 thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o 15 17 thermal_sys-$(CONFIG_THERMAL_OF) += thermal_of.o
+1 -1
drivers/thermal/gov_power_allocator.c
··· 762 762 763 763 trip = params->trip_switch_on; 764 764 if (trip && tz->temperature < trip->temperature) { 765 - update = tz->last_temperature >= trip->temperature; 765 + update = tz->passive; 766 766 tz->passive = 0; 767 767 reset_pid_controller(params); 768 768 allow_maximum_power(tz, update);
+28
drivers/thermal/intel/intel_hfi.c
··· 35 35 #include <linux/processor.h> 36 36 #include <linux/slab.h> 37 37 #include <linux/spinlock.h> 38 + #include <linux/suspend.h> 38 39 #include <linux/string.h> 40 + #include <linux/syscore_ops.h> 39 41 #include <linux/topology.h> 40 42 #include <linux/workqueue.h> 41 43 ··· 573 571 return 0; 574 572 } 575 573 574 + static void hfi_do_enable(void) 575 + { 576 + /* This code runs only on the boot CPU. */ 577 + struct hfi_cpu_info *info = &per_cpu(hfi_cpu_info, 0); 578 + struct hfi_instance *hfi_instance = info->hfi_instance; 579 + 580 + /* No locking needed. There is no concurrency with CPU online. */ 581 + hfi_set_hw_table(hfi_instance); 582 + hfi_enable(); 583 + } 584 + 585 + static int hfi_do_disable(void) 586 + { 587 + /* No locking needed. There is no concurrency with CPU offline. */ 588 + hfi_disable(); 589 + 590 + return 0; 591 + } 592 + 593 + static struct syscore_ops hfi_pm_ops = { 594 + .resume = hfi_do_enable, 595 + .suspend = hfi_do_disable, 596 + }; 597 + 576 598 void __init intel_hfi_init(void) 577 599 { 578 600 struct hfi_instance *hfi_instance; ··· 627 601 hfi_updates_wq = create_singlethread_workqueue("hfi-updates"); 628 602 if (!hfi_updates_wq) 629 603 goto err_nomem; 604 + 605 + register_syscore_ops(&hfi_pm_ops); 630 606 631 607 return; 632 608
+22 -16
drivers/thermal/thermal_core.c
··· 211 211 mutex_unlock(&tz->lock); 212 212 mutex_unlock(&thermal_governor_lock); 213 213 214 - thermal_notify_tz_gov_change(tz->id, policy); 214 + thermal_notify_tz_gov_change(tz, policy); 215 215 216 216 return ret; 217 217 } ··· 381 381 * the threshold and the trip temperature will be equal. 382 382 */ 383 383 if (tz->temperature >= trip->temperature) { 384 - thermal_notify_tz_trip_up(tz->id, 385 - thermal_zone_trip_id(tz, trip), 386 - tz->temperature); 384 + thermal_notify_tz_trip_up(tz, trip); 385 + thermal_debug_tz_trip_up(tz, trip); 387 386 trip->threshold = trip->temperature - trip->hysteresis; 388 387 } else { 389 388 trip->threshold = trip->temperature; ··· 399 400 * the trip. 400 401 */ 401 402 if (tz->temperature < trip->temperature - trip->hysteresis) { 402 - thermal_notify_tz_trip_down(tz->id, 403 - thermal_zone_trip_id(tz, trip), 404 - tz->temperature); 403 + thermal_notify_tz_trip_down(tz, trip); 404 + thermal_debug_tz_trip_down(tz, trip); 405 405 trip->threshold = trip->temperature; 406 406 } else { 407 407 trip->threshold = trip->temperature - trip->hysteresis; ··· 432 434 trace_thermal_temperature(tz); 433 435 434 436 thermal_genl_sampling_temp(tz->id, temp); 437 + thermal_debug_update_temp(tz); 435 438 } 436 439 437 440 static void thermal_zone_device_check(struct work_struct *work) ··· 504 505 mutex_unlock(&tz->lock); 505 506 506 507 if (mode == THERMAL_DEVICE_ENABLED) 507 - thermal_notify_tz_enable(tz->id); 508 + thermal_notify_tz_enable(tz); 508 509 else 509 - thermal_notify_tz_disable(tz->id); 510 + thermal_notify_tz_disable(tz); 510 511 511 512 return ret; 512 513 } ··· 845 846 sizeof("cooling_device") - 1)) { 846 847 cdev = to_cooling_device(dev); 847 848 thermal_cooling_device_destroy_sysfs(cdev); 848 - kfree(cdev->type); 849 + kfree_const(cdev->type); 849 850 ida_free(&thermal_cdev_ida, cdev->id); 850 851 kfree(cdev); 851 852 } ··· 917 918 cdev->id = ret; 918 919 id = ret; 919 920 920 - cdev->type = kstrdup(type ? type : "", GFP_KERNEL); 921 + cdev->type = kstrdup_const(type ? type : "", GFP_KERNEL); 921 922 if (!cdev->type) { 922 923 ret = -ENOMEM; 923 924 goto out_ida_remove; ··· 963 964 964 965 mutex_unlock(&thermal_list_lock); 965 966 967 + thermal_debug_cdev_add(cdev); 968 + 966 969 return cdev; 967 970 968 971 out_cooling_dev: 969 972 thermal_cooling_device_destroy_sysfs(cdev); 970 973 out_cdev_type: 971 - kfree(cdev->type); 974 + kfree_const(cdev->type); 972 975 out_ida_remove: 973 976 ida_free(&thermal_cdev_ida, id); 974 977 out_kfree_cdev: ··· 1170 1169 1171 1170 if (!cdev) 1172 1171 return; 1172 + 1173 + thermal_debug_cdev_remove(cdev); 1173 1174 1174 1175 mutex_lock(&thermal_list_lock); 1175 1176 ··· 1414 1411 if (atomic_cmpxchg(&tz->need_update, 1, 0)) 1415 1412 thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); 1416 1413 1417 - thermal_notify_tz_create(tz->id, tz->type); 1414 + thermal_notify_tz_create(tz); 1415 + 1416 + thermal_debug_tz_add(tz); 1418 1417 1419 1418 return tz; 1420 1419 ··· 1475 1470 */ 1476 1471 void thermal_zone_device_unregister(struct thermal_zone_device *tz) 1477 1472 { 1478 - int tz_id; 1479 1473 struct thermal_cooling_device *cdev; 1480 1474 struct thermal_zone_device *pos = NULL; 1481 1475 1482 1476 if (!tz) 1483 1477 return; 1484 1478 1485 - tz_id = tz->id; 1479 + thermal_debug_tz_remove(tz); 1486 1480 1487 1481 mutex_lock(&thermal_list_lock); 1488 1482 list_for_each_entry(pos, &thermal_tz_list, node) ··· 1518 1514 1519 1515 put_device(&tz->device); 1520 1516 1521 - thermal_notify_tz_delete(tz_id); 1517 + thermal_notify_tz_delete(tz); 1522 1518 1523 1519 wait_for_completion(&tz->removal); 1524 1520 kfree(tz); ··· 1639 1635 static int __init thermal_init(void) 1640 1636 { 1641 1637 int result; 1638 + 1639 + thermal_debug_init(); 1642 1640 1643 1641 result = thermal_netlink_init(); 1644 1642 if (result)
+1
drivers/thermal/thermal_core.h
··· 13 13 #include <linux/thermal.h> 14 14 15 15 #include "thermal_netlink.h" 16 + #include "thermal_debugfs.h" 16 17 17 18 /* Default Thermal Governor */ 18 19 #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE)
+839
drivers/thermal/thermal_debugfs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2023 Linaro Limited 4 + * 5 + * Author: Daniel Lezcano <daniel.lezcano@linaro.org> 6 + * 7 + * Thermal subsystem debug support 8 + */ 9 + #include <linux/debugfs.h> 10 + #include <linux/ktime.h> 11 + #include <linux/list.h> 12 + #include <linux/minmax.h> 13 + #include <linux/mutex.h> 14 + #include <linux/thermal.h> 15 + 16 + #include "thermal_core.h" 17 + 18 + static struct dentry *d_root; 19 + static struct dentry *d_cdev; 20 + static struct dentry *d_tz; 21 + 22 + /* 23 + * Length of the string containing the thermal zone id or the cooling 24 + * device id, including the ending nul character. We can reasonably 25 + * assume there won't be more than 256 thermal zones as the maximum 26 + * observed today is around 32. 27 + */ 28 + #define IDSLENGTH 4 29 + 30 + /* 31 + * The cooling device transition list is stored in a hash table where 32 + * the size is CDEVSTATS_HASH_SIZE. The majority of cooling devices 33 + * have dozen of states but some can have much more, so a hash table 34 + * is more adequate in this case, because the cost of browsing the entire 35 + * list when storing the transitions may not be negligible. 36 + */ 37 + #define CDEVSTATS_HASH_SIZE 16 38 + 39 + /** 40 + * struct cdev_debugfs - per cooling device statistics structure 41 + * A cooling device can have a high number of states. Showing the 42 + * transitions on a matrix based representation can be overkill given 43 + * most of the transitions won't happen and we end up with a matrix 44 + * filled with zero. Instead, we show the transitions which actually 45 + * happened. 46 + * 47 + * Every transition updates the current_state and the timestamp. The 48 + * transitions and the durations are stored in lists. 49 + * 50 + * @total: the number of transitions for this cooling device 51 + * @current_state: the current cooling device state 52 + * @timestamp: the state change timestamp 53 + * @transitions: an array of lists containing the state transitions 54 + * @durations: an array of lists containing the residencies of each state 55 + */ 56 + struct cdev_debugfs { 57 + u32 total; 58 + int current_state; 59 + ktime_t timestamp; 60 + struct list_head transitions[CDEVSTATS_HASH_SIZE]; 61 + struct list_head durations[CDEVSTATS_HASH_SIZE]; 62 + }; 63 + 64 + /** 65 + * struct cdev_record - Common structure for cooling device entry 66 + * 67 + * The following common structure allows to store the information 68 + * related to the transitions and to the state residencies. They are 69 + * identified with a id which is associated to a value. It is used as 70 + * nodes for the "transitions" and "durations" above. 71 + * 72 + * @node: node to insert the structure in a list 73 + * @id: identifier of the value which can be a state or a transition 74 + * @residency: a ktime_t representing a state residency duration 75 + * @count: a number of occurrences 76 + */ 77 + struct cdev_record { 78 + struct list_head node; 79 + int id; 80 + union { 81 + ktime_t residency; 82 + u64 count; 83 + }; 84 + }; 85 + 86 + /** 87 + * struct trip_stats - Thermal trip statistics 88 + * 89 + * The trip_stats structure has the relevant information to show the 90 + * statistics related to temperature going above a trip point. 91 + * 92 + * @timestamp: the trip crossing timestamp 93 + * @duration: total time when the zone temperature was above the trip point 94 + * @count: the number of times the zone temperature was above the trip point 95 + * @max: maximum recorded temperature above the trip point 96 + * @min: minimum recorded temperature above the trip point 97 + * @avg: average temperature above the trip point 98 + */ 99 + struct trip_stats { 100 + ktime_t timestamp; 101 + ktime_t duration; 102 + int count; 103 + int max; 104 + int min; 105 + int avg; 106 + }; 107 + 108 + /** 109 + * struct tz_episode - A mitigation episode information 110 + * 111 + * The tz_episode structure describes a mitigation episode. A 112 + * mitigation episode begins the trip point with the lower temperature 113 + * is crossed the way up and ends when it is crossed the way 114 + * down. During this episode we can have multiple trip points crossed 115 + * the way up and down if there are multiple trip described in the 116 + * firmware after the lowest temperature trip point. 117 + * 118 + * @timestamp: first trip point crossed the way up 119 + * @duration: total duration of the mitigation episode 120 + * @node: a list element to be added to the list of tz events 121 + * @trip_stats: per trip point statistics, flexible array 122 + */ 123 + struct tz_episode { 124 + ktime_t timestamp; 125 + ktime_t duration; 126 + struct list_head node; 127 + struct trip_stats trip_stats[]; 128 + }; 129 + 130 + /** 131 + * struct tz_debugfs - Store all mitigation episodes for a thermal zone 132 + * 133 + * The tz_debugfs structure contains the list of the mitigation 134 + * episodes and has to track which trip point has been crossed in 135 + * order to handle correctly nested trip point mitigation episodes. 136 + * 137 + * We keep the history of the trip point crossed in an array and as we 138 + * can go back and forth inside this history, eg. trip 0,1,2,1,2,1,0, 139 + * we keep track of the current position in the history array. 140 + * 141 + * @tz_episodes: a list of thermal mitigation episodes 142 + * @trips_crossed: an array of trip points crossed by id 143 + * @nr_trips: the number of trip points currently being crossed 144 + */ 145 + struct tz_debugfs { 146 + struct list_head tz_episodes; 147 + int *trips_crossed; 148 + int nr_trips; 149 + }; 150 + 151 + /** 152 + * struct thermal_debugfs - High level structure for a thermal object in debugfs 153 + * 154 + * The thermal_debugfs structure is the common structure used by the 155 + * cooling device or the thermal zone to store the statistics. 156 + * 157 + * @d_top: top directory of the thermal object directory 158 + * @lock: per object lock to protect the internals 159 + * 160 + * @cdev_dbg: a cooling device debug structure 161 + * @tz_dbg: a thermal zone debug structure 162 + */ 163 + struct thermal_debugfs { 164 + struct dentry *d_top; 165 + struct mutex lock; 166 + union { 167 + struct cdev_debugfs cdev_dbg; 168 + struct tz_debugfs tz_dbg; 169 + }; 170 + }; 171 + 172 + void thermal_debug_init(void) 173 + { 174 + d_root = debugfs_create_dir("thermal", NULL); 175 + if (!d_root) 176 + return; 177 + 178 + d_cdev = debugfs_create_dir("cooling_devices", d_root); 179 + if (!d_cdev) 180 + return; 181 + 182 + d_tz = debugfs_create_dir("thermal_zones", d_root); 183 + } 184 + 185 + static struct thermal_debugfs *thermal_debugfs_add_id(struct dentry *d, int id) 186 + { 187 + struct thermal_debugfs *thermal_dbg; 188 + char ids[IDSLENGTH]; 189 + 190 + thermal_dbg = kzalloc(sizeof(*thermal_dbg), GFP_KERNEL); 191 + if (!thermal_dbg) 192 + return NULL; 193 + 194 + mutex_init(&thermal_dbg->lock); 195 + 196 + snprintf(ids, IDSLENGTH, "%d", id); 197 + 198 + thermal_dbg->d_top = debugfs_create_dir(ids, d); 199 + if (!thermal_dbg->d_top) { 200 + kfree(thermal_dbg); 201 + return NULL; 202 + } 203 + 204 + return thermal_dbg; 205 + } 206 + 207 + static void thermal_debugfs_remove_id(struct thermal_debugfs *thermal_dbg) 208 + { 209 + if (!thermal_dbg) 210 + return; 211 + 212 + debugfs_remove(thermal_dbg->d_top); 213 + 214 + kfree(thermal_dbg); 215 + } 216 + 217 + static struct cdev_record * 218 + thermal_debugfs_cdev_record_alloc(struct thermal_debugfs *thermal_dbg, 219 + struct list_head *lists, int id) 220 + { 221 + struct cdev_record *cdev_record; 222 + 223 + cdev_record = kzalloc(sizeof(*cdev_record), GFP_KERNEL); 224 + if (!cdev_record) 225 + return NULL; 226 + 227 + cdev_record->id = id; 228 + INIT_LIST_HEAD(&cdev_record->node); 229 + list_add_tail(&cdev_record->node, 230 + &lists[cdev_record->id % CDEVSTATS_HASH_SIZE]); 231 + 232 + return cdev_record; 233 + } 234 + 235 + static struct cdev_record * 236 + thermal_debugfs_cdev_record_find(struct thermal_debugfs *thermal_dbg, 237 + struct list_head *lists, int id) 238 + { 239 + struct cdev_record *entry; 240 + 241 + list_for_each_entry(entry, &lists[id % CDEVSTATS_HASH_SIZE], node) 242 + if (entry->id == id) 243 + return entry; 244 + 245 + return NULL; 246 + } 247 + 248 + static struct cdev_record * 249 + thermal_debugfs_cdev_record_get(struct thermal_debugfs *thermal_dbg, 250 + struct list_head *lists, int id) 251 + { 252 + struct cdev_record *cdev_record; 253 + 254 + cdev_record = thermal_debugfs_cdev_record_find(thermal_dbg, lists, id); 255 + if (cdev_record) 256 + return cdev_record; 257 + 258 + return thermal_debugfs_cdev_record_alloc(thermal_dbg, lists, id); 259 + } 260 + 261 + static void thermal_debugfs_cdev_clear(struct cdev_debugfs *cdev_dbg) 262 + { 263 + int i; 264 + struct cdev_record *entry, *tmp; 265 + 266 + for (i = 0; i < CDEVSTATS_HASH_SIZE; i++) { 267 + 268 + list_for_each_entry_safe(entry, tmp, 269 + &cdev_dbg->transitions[i], node) { 270 + list_del(&entry->node); 271 + kfree(entry); 272 + } 273 + 274 + list_for_each_entry_safe(entry, tmp, 275 + &cdev_dbg->durations[i], node) { 276 + list_del(&entry->node); 277 + kfree(entry); 278 + } 279 + } 280 + 281 + cdev_dbg->total = 0; 282 + } 283 + 284 + static void *cdev_seq_start(struct seq_file *s, loff_t *pos) 285 + { 286 + struct thermal_debugfs *thermal_dbg = s->private; 287 + 288 + mutex_lock(&thermal_dbg->lock); 289 + 290 + return (*pos < CDEVSTATS_HASH_SIZE) ? pos : NULL; 291 + } 292 + 293 + static void *cdev_seq_next(struct seq_file *s, void *v, loff_t *pos) 294 + { 295 + (*pos)++; 296 + 297 + return (*pos < CDEVSTATS_HASH_SIZE) ? pos : NULL; 298 + } 299 + 300 + static void cdev_seq_stop(struct seq_file *s, void *v) 301 + { 302 + struct thermal_debugfs *thermal_dbg = s->private; 303 + 304 + mutex_unlock(&thermal_dbg->lock); 305 + } 306 + 307 + static int cdev_tt_seq_show(struct seq_file *s, void *v) 308 + { 309 + struct thermal_debugfs *thermal_dbg = s->private; 310 + struct cdev_debugfs *cdev_dbg = &thermal_dbg->cdev_dbg; 311 + struct list_head *transitions = cdev_dbg->transitions; 312 + struct cdev_record *entry; 313 + int i = *(loff_t *)v; 314 + 315 + if (!i) 316 + seq_puts(s, "Transition\tOccurences\n"); 317 + 318 + list_for_each_entry(entry, &transitions[i], node) { 319 + /* 320 + * Assuming maximum cdev states is 1024, the longer 321 + * string for a transition would be "1024->1024\0" 322 + */ 323 + char buffer[11]; 324 + 325 + snprintf(buffer, ARRAY_SIZE(buffer), "%d->%d", 326 + entry->id >> 16, entry->id & 0xFFFF); 327 + 328 + seq_printf(s, "%-10s\t%-10llu\n", buffer, entry->count); 329 + } 330 + 331 + return 0; 332 + } 333 + 334 + static const struct seq_operations tt_sops = { 335 + .start = cdev_seq_start, 336 + .next = cdev_seq_next, 337 + .stop = cdev_seq_stop, 338 + .show = cdev_tt_seq_show, 339 + }; 340 + 341 + DEFINE_SEQ_ATTRIBUTE(tt); 342 + 343 + static int cdev_dt_seq_show(struct seq_file *s, void *v) 344 + { 345 + struct thermal_debugfs *thermal_dbg = s->private; 346 + struct cdev_debugfs *cdev_dbg = &thermal_dbg->cdev_dbg; 347 + struct list_head *durations = cdev_dbg->durations; 348 + struct cdev_record *entry; 349 + int i = *(loff_t *)v; 350 + 351 + if (!i) 352 + seq_puts(s, "State\tResidency\n"); 353 + 354 + list_for_each_entry(entry, &durations[i], node) { 355 + s64 duration = ktime_to_ms(entry->residency); 356 + 357 + if (entry->id == cdev_dbg->current_state) 358 + duration += ktime_ms_delta(ktime_get(), 359 + cdev_dbg->timestamp); 360 + 361 + seq_printf(s, "%-5d\t%-10llu\n", entry->id, duration); 362 + } 363 + 364 + return 0; 365 + } 366 + 367 + static const struct seq_operations dt_sops = { 368 + .start = cdev_seq_start, 369 + .next = cdev_seq_next, 370 + .stop = cdev_seq_stop, 371 + .show = cdev_dt_seq_show, 372 + }; 373 + 374 + DEFINE_SEQ_ATTRIBUTE(dt); 375 + 376 + static int cdev_clear_set(void *data, u64 val) 377 + { 378 + struct thermal_debugfs *thermal_dbg = data; 379 + 380 + if (!val) 381 + return -EINVAL; 382 + 383 + mutex_lock(&thermal_dbg->lock); 384 + 385 + thermal_debugfs_cdev_clear(&thermal_dbg->cdev_dbg); 386 + 387 + mutex_unlock(&thermal_dbg->lock); 388 + 389 + return 0; 390 + } 391 + 392 + DEFINE_DEBUGFS_ATTRIBUTE(cdev_clear_fops, NULL, cdev_clear_set, "%llu\n"); 393 + 394 + /** 395 + * thermal_debug_cdev_state_update - Update a cooling device state change 396 + * 397 + * Computes a transition and the duration of the previous state residency. 398 + * 399 + * @cdev : a pointer to a cooling device 400 + * @new_state: an integer corresponding to the new cooling device state 401 + */ 402 + void thermal_debug_cdev_state_update(const struct thermal_cooling_device *cdev, 403 + int new_state) 404 + { 405 + struct thermal_debugfs *thermal_dbg = cdev->debugfs; 406 + struct cdev_debugfs *cdev_dbg; 407 + struct cdev_record *cdev_record; 408 + int transition, old_state; 409 + 410 + if (!thermal_dbg || (thermal_dbg->cdev_dbg.current_state == new_state)) 411 + return; 412 + 413 + mutex_lock(&thermal_dbg->lock); 414 + 415 + cdev_dbg = &thermal_dbg->cdev_dbg; 416 + 417 + old_state = cdev_dbg->current_state; 418 + 419 + /* 420 + * Get the old state information in the durations list. If 421 + * this one does not exist, a new allocated one will be 422 + * returned. Recompute the total duration in the old state and 423 + * get a new timestamp for the new state. 424 + */ 425 + cdev_record = thermal_debugfs_cdev_record_get(thermal_dbg, 426 + cdev_dbg->durations, 427 + old_state); 428 + if (cdev_record) { 429 + ktime_t now = ktime_get(); 430 + ktime_t delta = ktime_sub(now, cdev_dbg->timestamp); 431 + cdev_record->residency = ktime_add(cdev_record->residency, delta); 432 + cdev_dbg->timestamp = now; 433 + } 434 + 435 + cdev_dbg->current_state = new_state; 436 + transition = (old_state << 16) | new_state; 437 + 438 + /* 439 + * Get the transition in the transitions list. If this one 440 + * does not exist, a new allocated one will be returned. 441 + * Increment the occurrence of this transition which is stored 442 + * in the value field. 443 + */ 444 + cdev_record = thermal_debugfs_cdev_record_get(thermal_dbg, 445 + cdev_dbg->transitions, 446 + transition); 447 + if (cdev_record) 448 + cdev_record->count++; 449 + 450 + cdev_dbg->total++; 451 + 452 + mutex_unlock(&thermal_dbg->lock); 453 + } 454 + 455 + /** 456 + * thermal_debug_cdev_add - Add a cooling device debugfs entry 457 + * 458 + * Allocates a cooling device object for debug, initializes the 459 + * statistics and create the entries in sysfs. 460 + * @cdev: a pointer to a cooling device 461 + */ 462 + void thermal_debug_cdev_add(struct thermal_cooling_device *cdev) 463 + { 464 + struct thermal_debugfs *thermal_dbg; 465 + struct cdev_debugfs *cdev_dbg; 466 + int i; 467 + 468 + thermal_dbg = thermal_debugfs_add_id(d_cdev, cdev->id); 469 + if (!thermal_dbg) 470 + return; 471 + 472 + cdev_dbg = &thermal_dbg->cdev_dbg; 473 + 474 + for (i = 0; i < CDEVSTATS_HASH_SIZE; i++) { 475 + INIT_LIST_HEAD(&cdev_dbg->transitions[i]); 476 + INIT_LIST_HEAD(&cdev_dbg->durations[i]); 477 + } 478 + 479 + cdev_dbg->current_state = 0; 480 + cdev_dbg->timestamp = ktime_get(); 481 + 482 + debugfs_create_file("trans_table", 0400, thermal_dbg->d_top, 483 + thermal_dbg, &tt_fops); 484 + 485 + debugfs_create_file("time_in_state_ms", 0400, thermal_dbg->d_top, 486 + thermal_dbg, &dt_fops); 487 + 488 + debugfs_create_file("clear", 0200, thermal_dbg->d_top, 489 + thermal_dbg, &cdev_clear_fops); 490 + 491 + debugfs_create_u32("total_trans", 0400, thermal_dbg->d_top, 492 + &cdev_dbg->total); 493 + 494 + cdev->debugfs = thermal_dbg; 495 + } 496 + 497 + /** 498 + * thermal_debug_cdev_remove - Remove a cooling device debugfs entry 499 + * 500 + * Frees the statistics memory data and remove the debugfs entry 501 + * 502 + * @cdev: a pointer to a cooling device 503 + */ 504 + void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev) 505 + { 506 + struct thermal_debugfs *thermal_dbg = cdev->debugfs; 507 + 508 + if (!thermal_dbg) 509 + return; 510 + 511 + mutex_lock(&thermal_dbg->lock); 512 + 513 + thermal_debugfs_cdev_clear(&thermal_dbg->cdev_dbg); 514 + cdev->debugfs = NULL; 515 + 516 + mutex_unlock(&thermal_dbg->lock); 517 + 518 + thermal_debugfs_remove_id(thermal_dbg); 519 + } 520 + 521 + static struct tz_episode *thermal_debugfs_tz_event_alloc(struct thermal_zone_device *tz, 522 + ktime_t now) 523 + { 524 + struct tz_episode *tze; 525 + int i; 526 + 527 + tze = kzalloc(struct_size(tze, trip_stats, tz->num_trips), GFP_KERNEL); 528 + if (!tze) 529 + return NULL; 530 + 531 + INIT_LIST_HEAD(&tze->node); 532 + tze->timestamp = now; 533 + 534 + for (i = 0; i < tz->num_trips; i++) { 535 + tze->trip_stats[i].min = INT_MAX; 536 + tze->trip_stats[i].max = INT_MIN; 537 + } 538 + 539 + return tze; 540 + } 541 + 542 + void thermal_debug_tz_trip_up(struct thermal_zone_device *tz, 543 + const struct thermal_trip *trip) 544 + { 545 + struct tz_episode *tze; 546 + struct tz_debugfs *tz_dbg; 547 + struct thermal_debugfs *thermal_dbg = tz->debugfs; 548 + int temperature = tz->temperature; 549 + int trip_id = thermal_zone_trip_id(tz, trip); 550 + ktime_t now = ktime_get(); 551 + 552 + if (!thermal_dbg) 553 + return; 554 + 555 + mutex_lock(&thermal_dbg->lock); 556 + 557 + tz_dbg = &thermal_dbg->tz_dbg; 558 + 559 + /* 560 + * The mitigation is starting. A mitigation can contain 561 + * several episodes where each of them is related to a 562 + * temperature crossing a trip point. The episodes are 563 + * nested. That means when the temperature is crossing the 564 + * first trip point, the duration begins to be measured. If 565 + * the temperature continues to increase and reaches the 566 + * second trip point, the duration of the first trip must be 567 + * also accumulated. 568 + * 569 + * eg. 570 + * 571 + * temp 572 + * ^ 573 + * | -------- 574 + * trip 2 / \ ------ 575 + * | /| |\ /| |\ 576 + * trip 1 / | | `---- | | \ 577 + * | /| | | | | |\ 578 + * trip 0 / | | | | | | \ 579 + * | /| | | | | | | |\ 580 + * | / | | | | | | | | `-- 581 + * | / | | | | | | | | 582 + * |----- | | | | | | | | 583 + * | | | | | | | | | 584 + * --------|-|-|--------|--------|------|-|-|------------------> time 585 + * | | |<--t2-->| |<-t2'>| | | 586 + * | | | | 587 + * | |<------------t1------------>| | 588 + * | | 589 + * |<-------------t0--------------->| 590 + * 591 + */ 592 + if (!tz_dbg->nr_trips) { 593 + tze = thermal_debugfs_tz_event_alloc(tz, now); 594 + if (!tze) 595 + goto unlock; 596 + 597 + list_add(&tze->node, &tz_dbg->tz_episodes); 598 + } 599 + 600 + /* 601 + * Each time a trip point is crossed the way up, the trip_id 602 + * is stored in the trip_crossed array and the nr_trips is 603 + * incremented. A nr_trips equal to zero means we are entering 604 + * a mitigation episode. 605 + * 606 + * The trip ids may not be in the ascending order but the 607 + * result in the array trips_crossed will be in the ascending 608 + * temperature order. The function detecting when a trip point 609 + * is crossed the way down will handle the very rare case when 610 + * the trip points may have been reordered during this 611 + * mitigation episode. 612 + */ 613 + tz_dbg->trips_crossed[tz_dbg->nr_trips++] = trip_id; 614 + 615 + tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node); 616 + tze->trip_stats[trip_id].timestamp = now; 617 + tze->trip_stats[trip_id].max = max(tze->trip_stats[trip_id].max, temperature); 618 + tze->trip_stats[trip_id].min = min(tze->trip_stats[trip_id].min, temperature); 619 + tze->trip_stats[trip_id].avg = tze->trip_stats[trip_id].avg + 620 + (temperature - tze->trip_stats[trip_id].avg) / 621 + tze->trip_stats[trip_id].count; 622 + 623 + unlock: 624 + mutex_unlock(&thermal_dbg->lock); 625 + } 626 + 627 + void thermal_debug_tz_trip_down(struct thermal_zone_device *tz, 628 + const struct thermal_trip *trip) 629 + { 630 + struct thermal_debugfs *thermal_dbg = tz->debugfs; 631 + struct tz_episode *tze; 632 + struct tz_debugfs *tz_dbg; 633 + ktime_t delta, now = ktime_get(); 634 + int trip_id = thermal_zone_trip_id(tz, trip); 635 + int i; 636 + 637 + if (!thermal_dbg) 638 + return; 639 + 640 + mutex_lock(&thermal_dbg->lock); 641 + 642 + tz_dbg = &thermal_dbg->tz_dbg; 643 + 644 + /* 645 + * The temperature crosses the way down but there was not 646 + * mitigation detected before. That may happen when the 647 + * temperature is greater than a trip point when registering a 648 + * thermal zone, which is a common use case as the kernel has 649 + * no mitigation mechanism yet at boot time. 650 + */ 651 + if (!tz_dbg->nr_trips) 652 + goto out; 653 + 654 + for (i = tz_dbg->nr_trips - 1; i >= 0; i--) { 655 + if (tz_dbg->trips_crossed[i] == trip_id) 656 + break; 657 + } 658 + 659 + if (i < 0) 660 + goto out; 661 + 662 + tz_dbg->nr_trips--; 663 + 664 + if (i < tz_dbg->nr_trips) 665 + tz_dbg->trips_crossed[i] = tz_dbg->trips_crossed[tz_dbg->nr_trips]; 666 + 667 + tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node); 668 + 669 + delta = ktime_sub(now, tze->trip_stats[trip_id].timestamp); 670 + 671 + tze->trip_stats[trip_id].duration = 672 + ktime_add(delta, tze->trip_stats[trip_id].duration); 673 + 674 + /* 675 + * This event closes the mitigation as we are crossing the 676 + * last trip point the way down. 677 + */ 678 + if (!tz_dbg->nr_trips) 679 + tze->duration = ktime_sub(now, tze->timestamp); 680 + 681 + out: 682 + mutex_unlock(&thermal_dbg->lock); 683 + } 684 + 685 + void thermal_debug_update_temp(struct thermal_zone_device *tz) 686 + { 687 + struct thermal_debugfs *thermal_dbg = tz->debugfs; 688 + struct tz_episode *tze; 689 + struct tz_debugfs *tz_dbg; 690 + int trip_id, i; 691 + 692 + if (!thermal_dbg) 693 + return; 694 + 695 + mutex_lock(&thermal_dbg->lock); 696 + 697 + tz_dbg = &thermal_dbg->tz_dbg; 698 + 699 + if (!tz_dbg->nr_trips) 700 + goto out; 701 + 702 + for (i = 0; i < tz_dbg->nr_trips; i++) { 703 + trip_id = tz_dbg->trips_crossed[i]; 704 + tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node); 705 + tze->trip_stats[trip_id].count++; 706 + tze->trip_stats[trip_id].max = max(tze->trip_stats[trip_id].max, tz->temperature); 707 + tze->trip_stats[trip_id].min = min(tze->trip_stats[trip_id].min, tz->temperature); 708 + tze->trip_stats[trip_id].avg = tze->trip_stats[trip_id].avg + 709 + (tz->temperature - tze->trip_stats[trip_id].avg) / 710 + tze->trip_stats[trip_id].count; 711 + } 712 + out: 713 + mutex_unlock(&thermal_dbg->lock); 714 + } 715 + 716 + static void *tze_seq_start(struct seq_file *s, loff_t *pos) 717 + { 718 + struct thermal_zone_device *tz = s->private; 719 + struct thermal_debugfs *thermal_dbg = tz->debugfs; 720 + struct tz_debugfs *tz_dbg = &thermal_dbg->tz_dbg; 721 + 722 + mutex_lock(&thermal_dbg->lock); 723 + 724 + return seq_list_start(&tz_dbg->tz_episodes, *pos); 725 + } 726 + 727 + static void *tze_seq_next(struct seq_file *s, void *v, loff_t *pos) 728 + { 729 + struct thermal_zone_device *tz = s->private; 730 + struct thermal_debugfs *thermal_dbg = tz->debugfs; 731 + struct tz_debugfs *tz_dbg = &thermal_dbg->tz_dbg; 732 + 733 + return seq_list_next(v, &tz_dbg->tz_episodes, pos); 734 + } 735 + 736 + static void tze_seq_stop(struct seq_file *s, void *v) 737 + { 738 + struct thermal_zone_device *tz = s->private; 739 + struct thermal_debugfs *thermal_dbg = tz->debugfs; 740 + 741 + mutex_unlock(&thermal_dbg->lock); 742 + } 743 + 744 + static int tze_seq_show(struct seq_file *s, void *v) 745 + { 746 + struct thermal_zone_device *tz = s->private; 747 + struct thermal_trip *trip; 748 + struct tz_episode *tze; 749 + const char *type; 750 + int trip_id; 751 + 752 + tze = list_entry((struct list_head *)v, struct tz_episode, node); 753 + 754 + seq_printf(s, ",-Mitigation at %lluus, duration=%llums\n", 755 + ktime_to_us(tze->timestamp), 756 + ktime_to_ms(tze->duration)); 757 + 758 + seq_printf(s, "| trip | type | temp(°mC) | hyst(°mC) | duration | avg(°mC) | min(°mC) | max(°mC) |\n"); 759 + 760 + for_each_trip(tz, trip) { 761 + /* 762 + * There is no possible mitigation happening at the 763 + * critical trip point, so the stats will be always 764 + * zero, skip this trip point 765 + */ 766 + if (trip->type == THERMAL_TRIP_CRITICAL) 767 + continue; 768 + 769 + if (trip->type == THERMAL_TRIP_PASSIVE) 770 + type = "passive"; 771 + else if (trip->type == THERMAL_TRIP_ACTIVE) 772 + type = "active"; 773 + else 774 + type = "hot"; 775 + 776 + trip_id = thermal_zone_trip_id(tz, trip); 777 + 778 + seq_printf(s, "| %*d | %*s | %*d | %*d | %*lld | %*d | %*d | %*d |\n", 779 + 4 , trip_id, 780 + 8, type, 781 + 9, trip->temperature, 782 + 9, trip->hysteresis, 783 + 10, ktime_to_ms(tze->trip_stats[trip_id].duration), 784 + 9, tze->trip_stats[trip_id].avg, 785 + 9, tze->trip_stats[trip_id].min, 786 + 9, tze->trip_stats[trip_id].max); 787 + } 788 + 789 + return 0; 790 + } 791 + 792 + static const struct seq_operations tze_sops = { 793 + .start = tze_seq_start, 794 + .next = tze_seq_next, 795 + .stop = tze_seq_stop, 796 + .show = tze_seq_show, 797 + }; 798 + 799 + DEFINE_SEQ_ATTRIBUTE(tze); 800 + 801 + void thermal_debug_tz_add(struct thermal_zone_device *tz) 802 + { 803 + struct thermal_debugfs *thermal_dbg; 804 + struct tz_debugfs *tz_dbg; 805 + 806 + thermal_dbg = thermal_debugfs_add_id(d_tz, tz->id); 807 + if (!thermal_dbg) 808 + return; 809 + 810 + tz_dbg = &thermal_dbg->tz_dbg; 811 + 812 + tz_dbg->trips_crossed = kzalloc(sizeof(int) * tz->num_trips, GFP_KERNEL); 813 + if (!tz_dbg->trips_crossed) { 814 + thermal_debugfs_remove_id(thermal_dbg); 815 + return; 816 + } 817 + 818 + INIT_LIST_HEAD(&tz_dbg->tz_episodes); 819 + 820 + debugfs_create_file("mitigations", 0400, thermal_dbg->d_top, tz, &tze_fops); 821 + 822 + tz->debugfs = thermal_dbg; 823 + } 824 + 825 + void thermal_debug_tz_remove(struct thermal_zone_device *tz) 826 + { 827 + struct thermal_debugfs *thermal_dbg = tz->debugfs; 828 + 829 + if (!thermal_dbg) 830 + return; 831 + 832 + mutex_lock(&thermal_dbg->lock); 833 + 834 + tz->debugfs = NULL; 835 + 836 + mutex_unlock(&thermal_dbg->lock); 837 + 838 + thermal_debugfs_remove_id(thermal_dbg); 839 + }
+28
drivers/thermal/thermal_debugfs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifdef CONFIG_THERMAL_DEBUGFS 4 + void thermal_debug_init(void); 5 + void thermal_debug_cdev_add(struct thermal_cooling_device *cdev); 6 + void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev); 7 + void thermal_debug_cdev_state_update(const struct thermal_cooling_device *cdev, int state); 8 + void thermal_debug_tz_add(struct thermal_zone_device *tz); 9 + void thermal_debug_tz_remove(struct thermal_zone_device *tz); 10 + void thermal_debug_tz_trip_up(struct thermal_zone_device *tz, 11 + const struct thermal_trip *trip); 12 + void thermal_debug_tz_trip_down(struct thermal_zone_device *tz, 13 + const struct thermal_trip *trip); 14 + void thermal_debug_update_temp(struct thermal_zone_device *tz); 15 + #else 16 + static inline void thermal_debug_init(void) {} 17 + static inline void thermal_debug_cdev_add(struct thermal_cooling_device *cdev) {} 18 + static inline void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev) {} 19 + static inline void thermal_debug_cdev_state_update(const struct thermal_cooling_device *cdev, 20 + int state) {} 21 + static inline void thermal_debug_tz_add(struct thermal_zone_device *tz) {} 22 + static inline void thermal_debug_tz_remove(struct thermal_zone_device *tz) {} 23 + static inline void thermal_debug_tz_trip_up(struct thermal_zone_device *tz, 24 + const struct thermal_trip *trip) {}; 25 + static inline void thermal_debug_tz_trip_down(struct thermal_zone_device *tz, 26 + const struct thermal_trip *trip) {} 27 + static inline void thermal_debug_update_temp(struct thermal_zone_device *tz) {} 28 + #endif /* CONFIG_THERMAL_DEBUGFS */
+15 -6
drivers/thermal/thermal_helpers.c
··· 146 146 } 147 147 EXPORT_SYMBOL_GPL(thermal_zone_get_temp); 148 148 149 - static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev, 150 - int target) 149 + static int thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev, int state) 151 150 { 152 - if (cdev->ops->set_cur_state(cdev, target)) 153 - return; 151 + int ret; 154 152 155 - thermal_notify_cdev_state_update(cdev->id, target); 156 - thermal_cooling_device_stats_update(cdev, target); 153 + /* 154 + * No check is needed for the ops->set_cur_state as the 155 + * registering function checked the ops are correctly set 156 + */ 157 + ret = cdev->ops->set_cur_state(cdev, state); 158 + if (ret) 159 + return ret; 160 + 161 + thermal_notify_cdev_state_update(cdev, state); 162 + thermal_cooling_device_stats_update(cdev, state); 163 + thermal_debug_cdev_state_update(cdev, state); 164 + 165 + return 0; 157 166 } 158 167 159 168 void __thermal_cdev_update(struct thermal_cooling_device *cdev)
+37 -58
drivers/thermal/thermal_netlink.c
··· 148 148 return 0; 149 149 } 150 150 151 - static int thermal_genl_event_tz_trip_add(struct param *p) 151 + static int thermal_genl_event_tz_trip_change(struct param *p) 152 152 { 153 153 if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 154 154 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) || 155 155 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) || 156 156 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) || 157 157 nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst)) 158 - return -EMSGSIZE; 159 - 160 - return 0; 161 - } 162 - 163 - static int thermal_genl_event_tz_trip_delete(struct param *p) 164 - { 165 - if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || 166 - nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id)) 167 158 return -EMSGSIZE; 168 159 169 160 return 0; ··· 249 258 int thermal_genl_event_tz_trip_down(struct param *p) 250 259 __attribute__((alias("thermal_genl_event_tz_trip_up"))); 251 260 252 - int thermal_genl_event_tz_trip_change(struct param *p) 253 - __attribute__((alias("thermal_genl_event_tz_trip_add"))); 254 - 255 261 static cb_t event_cb[] = { 256 262 [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create, 257 263 [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete, ··· 257 269 [THERMAL_GENL_EVENT_TZ_TRIP_UP] = thermal_genl_event_tz_trip_up, 258 270 [THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = thermal_genl_event_tz_trip_down, 259 271 [THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = thermal_genl_event_tz_trip_change, 260 - [THERMAL_GENL_EVENT_TZ_TRIP_ADD] = thermal_genl_event_tz_trip_add, 261 - [THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = thermal_genl_event_tz_trip_delete, 262 272 [THERMAL_GENL_EVENT_CDEV_ADD] = thermal_genl_event_cdev_add, 263 273 [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete, 264 274 [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update, ··· 304 318 return ret; 305 319 } 306 320 307 - int thermal_notify_tz_create(int tz_id, const char *name) 321 + int thermal_notify_tz_create(const struct thermal_zone_device *tz) 308 322 { 309 - struct param p = { .tz_id = tz_id, .name = name }; 323 + struct param p = { .tz_id = tz->id, .name = tz->type }; 310 324 311 325 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p); 312 326 } 313 327 314 - int thermal_notify_tz_delete(int tz_id) 328 + int thermal_notify_tz_delete(const struct thermal_zone_device *tz) 315 329 { 316 - struct param p = { .tz_id = tz_id }; 330 + struct param p = { .tz_id = tz->id }; 317 331 318 332 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p); 319 333 } 320 334 321 - int thermal_notify_tz_enable(int tz_id) 335 + int thermal_notify_tz_enable(const struct thermal_zone_device *tz) 322 336 { 323 - struct param p = { .tz_id = tz_id }; 337 + struct param p = { .tz_id = tz->id }; 324 338 325 339 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p); 326 340 } 327 341 328 - int thermal_notify_tz_disable(int tz_id) 342 + int thermal_notify_tz_disable(const struct thermal_zone_device *tz) 329 343 { 330 - struct param p = { .tz_id = tz_id }; 344 + struct param p = { .tz_id = tz->id }; 331 345 332 346 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p); 333 347 } 334 348 335 - int thermal_notify_tz_trip_down(int tz_id, int trip_id, int temp) 349 + int thermal_notify_tz_trip_down(const struct thermal_zone_device *tz, 350 + const struct thermal_trip *trip) 336 351 { 337 - struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp }; 352 + struct param p = { .tz_id = tz->id, 353 + .trip_id = thermal_zone_trip_id(tz, trip), 354 + .temp = tz->temperature }; 338 355 339 356 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p); 340 357 } 341 358 342 - int thermal_notify_tz_trip_up(int tz_id, int trip_id, int temp) 359 + int thermal_notify_tz_trip_up(const struct thermal_zone_device *tz, 360 + const struct thermal_trip *trip) 343 361 { 344 - struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp }; 362 + struct param p = { .tz_id = tz->id, 363 + .trip_id = thermal_zone_trip_id(tz, trip), 364 + .temp = tz->temperature }; 345 365 346 366 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p); 347 367 } 348 368 349 - int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type, 350 - int trip_temp, int trip_hyst) 369 + int thermal_notify_tz_trip_change(const struct thermal_zone_device *tz, 370 + const struct thermal_trip *trip) 351 371 { 352 - struct param p = { .tz_id = tz_id, .trip_id = trip_id, 353 - .trip_type = trip_type, .trip_temp = trip_temp, 354 - .trip_hyst = trip_hyst }; 355 - 356 - return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p); 357 - } 358 - 359 - int thermal_notify_tz_trip_delete(int tz_id, int trip_id) 360 - { 361 - struct param p = { .tz_id = tz_id, .trip_id = trip_id }; 362 - 363 - return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p); 364 - } 365 - 366 - int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type, 367 - int trip_temp, int trip_hyst) 368 - { 369 - struct param p = { .tz_id = tz_id, .trip_id = trip_id, 370 - .trip_type = trip_type, .trip_temp = trip_temp, 371 - .trip_hyst = trip_hyst }; 372 + struct param p = { .tz_id = tz->id, 373 + .trip_id = thermal_zone_trip_id(tz, trip), 374 + .trip_type = trip->type, 375 + .trip_temp = trip->temperature, 376 + .trip_hyst = trip->hysteresis }; 372 377 373 378 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p); 374 379 } 375 380 376 - int thermal_notify_cdev_state_update(int cdev_id, int cdev_state) 381 + int thermal_notify_cdev_state_update(const struct thermal_cooling_device *cdev, 382 + int state) 377 383 { 378 - struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state }; 384 + struct param p = { .cdev_id = cdev->id, .cdev_state = state }; 379 385 380 386 return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p); 381 387 } 382 388 383 - int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state) 389 + int thermal_notify_cdev_add(const struct thermal_cooling_device *cdev) 384 390 { 385 - struct param p = { .cdev_id = cdev_id, .name = name, 386 - .cdev_max_state = cdev_max_state }; 391 + struct param p = { .cdev_id = cdev->id, .name = cdev->type, 392 + .cdev_max_state = cdev->max_state }; 387 393 388 394 return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p); 389 395 } 390 396 391 - int thermal_notify_cdev_delete(int cdev_id) 397 + int thermal_notify_cdev_delete(const struct thermal_cooling_device *cdev) 392 398 { 393 - struct param p = { .cdev_id = cdev_id }; 399 + struct param p = { .cdev_id = cdev->id }; 394 400 395 401 return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p); 396 402 } 397 403 398 - int thermal_notify_tz_gov_change(int tz_id, const char *name) 404 + int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz, 405 + const char *name) 399 406 { 400 - struct param p = { .tz_id = tz_id, .name = name }; 407 + struct param p = { .tz_id = tz->id, .name = name }; 401 408 402 409 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p); 403 410 }
+36 -39
drivers/thermal/thermal_netlink.h
··· 10 10 int efficiency; 11 11 }; 12 12 13 + struct thermal_zone_device; 14 + struct thermal_trip; 15 + struct thermal_cooling_device; 16 + 13 17 /* Netlink notification function */ 14 18 #ifdef CONFIG_THERMAL_NETLINK 15 19 int __init thermal_netlink_init(void); 16 20 void __init thermal_netlink_exit(void); 17 - int thermal_notify_tz_create(int tz_id, const char *name); 18 - int thermal_notify_tz_delete(int tz_id); 19 - int thermal_notify_tz_enable(int tz_id); 20 - int thermal_notify_tz_disable(int tz_id); 21 - int thermal_notify_tz_trip_down(int tz_id, int id, int temp); 22 - int thermal_notify_tz_trip_up(int tz_id, int id, int temp); 23 - int thermal_notify_tz_trip_delete(int tz_id, int id); 24 - int thermal_notify_tz_trip_add(int tz_id, int id, int type, 25 - int temp, int hyst); 26 - int thermal_notify_tz_trip_change(int tz_id, int id, int type, 27 - int temp, int hyst); 28 - int thermal_notify_cdev_state_update(int cdev_id, int state); 29 - int thermal_notify_cdev_add(int cdev_id, const char *name, int max_state); 30 - int thermal_notify_cdev_delete(int cdev_id); 31 - int thermal_notify_tz_gov_change(int tz_id, const char *name); 21 + int thermal_notify_tz_create(const struct thermal_zone_device *tz); 22 + int thermal_notify_tz_delete(const struct thermal_zone_device *tz); 23 + int thermal_notify_tz_enable(const struct thermal_zone_device *tz); 24 + int thermal_notify_tz_disable(const struct thermal_zone_device *tz); 25 + int thermal_notify_tz_trip_down(const struct thermal_zone_device *tz, 26 + const struct thermal_trip *trip); 27 + int thermal_notify_tz_trip_up(const struct thermal_zone_device *tz, 28 + const struct thermal_trip *trip); 29 + int thermal_notify_tz_trip_change(const struct thermal_zone_device *tz, 30 + const struct thermal_trip *trip); 31 + int thermal_notify_cdev_state_update(const struct thermal_cooling_device *cdev, 32 + int state); 33 + int thermal_notify_cdev_add(const struct thermal_cooling_device *cdev); 34 + int thermal_notify_cdev_delete(const struct thermal_cooling_device *cdev); 35 + int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz, 36 + const char *name); 32 37 int thermal_genl_sampling_temp(int id, int temp); 33 38 int thermal_genl_cpu_capability_event(int count, 34 39 struct thermal_genl_cpu_caps *caps); ··· 43 38 return 0; 44 39 } 45 40 46 - static inline int thermal_notify_tz_create(int tz_id, const char *name) 41 + static inline int thermal_notify_tz_create(const struct thermal_zone_device *tz) 47 42 { 48 43 return 0; 49 44 } 50 45 51 - static inline int thermal_notify_tz_delete(int tz_id) 46 + static inline int thermal_notify_tz_delete(const struct thermal_zone_device *tz) 52 47 { 53 48 return 0; 54 49 } 55 50 56 - static inline int thermal_notify_tz_enable(int tz_id) 51 + static inline int thermal_notify_tz_enable(const struct thermal_zone_device *tz) 57 52 { 58 53 return 0; 59 54 } 60 55 61 - static inline int thermal_notify_tz_disable(int tz_id) 56 + static inline int thermal_notify_tz_disable(const struct thermal_zone_device *tz) 62 57 { 63 58 return 0; 64 59 } 65 60 66 - static inline int thermal_notify_tz_trip_down(int tz_id, int id, int temp) 61 + static inline int thermal_notify_tz_trip_down(const struct thermal_zone_device *tz, 62 + const struct thermal_trip *trip) 67 63 { 68 64 return 0; 69 65 } 70 66 71 - static inline int thermal_notify_tz_trip_up(int tz_id, int id, int temp) 67 + static inline int thermal_notify_tz_trip_up(const struct thermal_zone_device *tz, 68 + const struct thermal_trip *trip) 72 69 { 73 70 return 0; 74 71 } 75 72 76 - static inline int thermal_notify_tz_trip_delete(int tz_id, int id) 73 + static inline int thermal_notify_tz_trip_change(const struct thermal_zone_device *tz, 74 + const struct thermal_trip *trip) 77 75 { 78 76 return 0; 79 77 } 80 78 81 - static inline int thermal_notify_tz_trip_add(int tz_id, int id, int type, 82 - int temp, int hyst) 79 + static inline int thermal_notify_cdev_state_update(const struct thermal_cooling_device *cdev, 80 + int state) 83 81 { 84 82 return 0; 85 83 } 86 84 87 - static inline int thermal_notify_tz_trip_change(int tz_id, int id, int type, 88 - int temp, int hyst) 85 + static inline int thermal_notify_cdev_add(const struct thermal_cooling_device *cdev) 89 86 { 90 87 return 0; 91 88 } 92 89 93 - static inline int thermal_notify_cdev_state_update(int cdev_id, int state) 90 + static inline int thermal_notify_cdev_delete(const struct thermal_cooling_device *cdev) 94 91 { 95 92 return 0; 96 93 } 97 94 98 - static inline int thermal_notify_cdev_add(int cdev_id, const char *name, 99 - int max_state) 100 - { 101 - return 0; 102 - } 103 - 104 - static inline int thermal_notify_cdev_delete(int cdev_id) 105 - { 106 - return 0; 107 - } 108 - 109 - static inline int thermal_notify_tz_gov_change(int tz_id, const char *name) 95 + static inline int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz, 96 + const char *name) 110 97 { 111 98 return 0; 112 99 }
+2 -6
drivers/thermal/thermal_trip.c
··· 155 155 void thermal_zone_trip_updated(struct thermal_zone_device *tz, 156 156 const struct thermal_trip *trip) 157 157 { 158 - thermal_notify_tz_trip_change(tz->id, thermal_zone_trip_id(tz, trip), 159 - trip->type, trip->temperature, 160 - trip->hysteresis); 158 + thermal_notify_tz_trip_change(tz, trip); 161 159 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); 162 160 } 163 161 ··· 166 168 return; 167 169 168 170 trip->temperature = temp; 169 - thermal_notify_tz_trip_change(tz->id, thermal_zone_trip_id(tz, trip), 170 - trip->type, trip->temperature, 171 - trip->hysteresis); 171 + thermal_notify_tz_trip_change(tz, trip); 172 172 } 173 173 EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp);
+8 -1
include/linux/thermal.h
··· 32 32 struct thermal_zone_device; 33 33 struct thermal_cooling_device; 34 34 struct thermal_instance; 35 + struct thermal_debugfs; 35 36 struct thermal_attr; 36 37 37 38 enum thermal_trend { ··· 103 102 104 103 struct thermal_cooling_device { 105 104 int id; 106 - char *type; 105 + const char *type; 107 106 unsigned long max_state; 108 107 struct device device; 109 108 struct device_node *np; ··· 114 113 struct mutex lock; /* protect thermal_instances list */ 115 114 struct list_head thermal_instances; 116 115 struct list_head node; 116 + #ifdef CONFIG_THERMAL_DEBUGFS 117 + struct thermal_debugfs *debugfs; 118 + #endif 117 119 }; 118 120 119 121 /** ··· 193 189 struct list_head node; 194 190 struct delayed_work poll_queue; 195 191 enum thermal_notify_event notify_event; 192 + #ifdef CONFIG_THERMAL_DEBUGFS 193 + struct thermal_debugfs *debugfs; 194 + #endif 196 195 bool suspended; 197 196 }; 198 197