]> Git Repo - linux.git/blob - drivers/thermal/thermal_debugfs.c
x86/kaslr: Expose and use the end of the physical memory address space
[linux.git] / drivers / thermal / thermal_debugfs.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2023 Linaro Limited
4  *
5  * Author: Daniel Lezcano <[email protected]>
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  * @trip_temp: trip temperature at mitigation start
95  * @trip_hyst: trip hysteresis at mitigation start
96  * @count: the number of times the zone temperature was above the trip point
97  * @min: minimum recorded temperature above the trip point
98  * @avg: average temperature above the trip point
99  */
100 struct trip_stats {
101         ktime_t timestamp;
102         ktime_t duration;
103         int trip_temp;
104         int trip_hyst;
105         int count;
106         int min;
107         int avg;
108 };
109
110 /**
111  * struct tz_episode - A mitigation episode information
112  *
113  * The tz_episode structure describes a mitigation episode. A
114  * mitigation episode begins the trip point with the lower temperature
115  * is crossed the way up and ends when it is crossed the way
116  * down. During this episode we can have multiple trip points crossed
117  * the way up and down if there are multiple trip described in the
118  * firmware after the lowest temperature trip point.
119  *
120  * @timestamp: first trip point crossed the way up
121  * @duration: total duration of the mitigation episode
122  * @node: a list element to be added to the list of tz events
123  * @max_temp: maximum zone temperature during this episode
124  * @trip_stats: per trip point statistics, flexible array
125  */
126 struct tz_episode {
127         ktime_t timestamp;
128         ktime_t duration;
129         struct list_head node;
130         int max_temp;
131         struct trip_stats trip_stats[];
132 };
133
134 /**
135  * struct tz_debugfs - Store all mitigation episodes for a thermal zone
136  *
137  * The tz_debugfs structure contains the list of the mitigation
138  * episodes and has to track which trip point has been crossed in
139  * order to handle correctly nested trip point mitigation episodes.
140  *
141  * We keep the history of the trip point crossed in an array and as we
142  * can go back and forth inside this history, eg. trip 0,1,2,1,2,1,0,
143  * we keep track of the current position in the history array.
144  *
145  * @tz_episodes: a list of thermal mitigation episodes
146  * @tz: thermal zone this object belongs to
147  * @trips_crossed: an array of trip points crossed by id
148  * @nr_trips: the number of trip points currently being crossed
149  */
150 struct tz_debugfs {
151         struct list_head tz_episodes;
152         struct thermal_zone_device *tz;
153         int *trips_crossed;
154         int nr_trips;
155 };
156
157 /**
158  * struct thermal_debugfs - High level structure for a thermal object in debugfs
159  *
160  * The thermal_debugfs structure is the common structure used by the
161  * cooling device or the thermal zone to store the statistics.
162  *
163  * @d_top: top directory of the thermal object directory
164  * @lock: per object lock to protect the internals
165  *
166  * @cdev_dbg: a cooling device debug structure
167  * @tz_dbg: a thermal zone debug structure
168  */
169 struct thermal_debugfs {
170         struct dentry *d_top;
171         struct mutex lock;
172         union {
173                 struct cdev_debugfs cdev_dbg;
174                 struct tz_debugfs tz_dbg;
175         };
176 };
177
178 void thermal_debug_init(void)
179 {
180         d_root = debugfs_create_dir("thermal", NULL);
181         if (!d_root)
182                 return;
183
184         d_cdev = debugfs_create_dir("cooling_devices", d_root);
185         if (!d_cdev)
186                 return;
187
188         d_tz = debugfs_create_dir("thermal_zones", d_root);
189 }
190
191 static struct thermal_debugfs *thermal_debugfs_add_id(struct dentry *d, int id)
192 {
193         struct thermal_debugfs *thermal_dbg;
194         char ids[IDSLENGTH];
195
196         thermal_dbg = kzalloc(sizeof(*thermal_dbg), GFP_KERNEL);
197         if (!thermal_dbg)
198                 return NULL;
199
200         mutex_init(&thermal_dbg->lock);
201
202         snprintf(ids, IDSLENGTH, "%d", id);
203
204         thermal_dbg->d_top = debugfs_create_dir(ids, d);
205         if (!thermal_dbg->d_top) {
206                 kfree(thermal_dbg);
207                 return NULL;
208         }
209
210         return thermal_dbg;
211 }
212
213 static void thermal_debugfs_remove_id(struct thermal_debugfs *thermal_dbg)
214 {
215         if (!thermal_dbg)
216                 return;
217
218         debugfs_remove(thermal_dbg->d_top);
219
220         kfree(thermal_dbg);
221 }
222
223 static struct cdev_record *
224 thermal_debugfs_cdev_record_alloc(struct thermal_debugfs *thermal_dbg,
225                                   struct list_head *lists, int id)
226 {
227         struct cdev_record *cdev_record;
228
229         cdev_record = kzalloc(sizeof(*cdev_record), GFP_KERNEL);
230         if (!cdev_record)
231                 return NULL;
232
233         cdev_record->id = id;
234         INIT_LIST_HEAD(&cdev_record->node);
235         list_add_tail(&cdev_record->node,
236                       &lists[cdev_record->id % CDEVSTATS_HASH_SIZE]);
237
238         return cdev_record;
239 }
240
241 static struct cdev_record *
242 thermal_debugfs_cdev_record_find(struct thermal_debugfs *thermal_dbg,
243                                  struct list_head *lists, int id)
244 {
245         struct cdev_record *entry;
246
247         list_for_each_entry(entry, &lists[id % CDEVSTATS_HASH_SIZE], node)
248                 if (entry->id == id)
249                         return entry;
250
251         return NULL;
252 }
253
254 static struct cdev_record *
255 thermal_debugfs_cdev_record_get(struct thermal_debugfs *thermal_dbg,
256                                 struct list_head *lists, int id)
257 {
258         struct cdev_record *cdev_record;
259
260         cdev_record = thermal_debugfs_cdev_record_find(thermal_dbg, lists, id);
261         if (cdev_record)
262                 return cdev_record;
263
264         return thermal_debugfs_cdev_record_alloc(thermal_dbg, lists, id);
265 }
266
267 static void thermal_debugfs_cdev_clear(struct cdev_debugfs *cdev_dbg)
268 {
269         int i;
270         struct cdev_record *entry, *tmp;
271
272         for (i = 0; i < CDEVSTATS_HASH_SIZE; i++) {
273
274                 list_for_each_entry_safe(entry, tmp,
275                                          &cdev_dbg->transitions[i], node) {
276                         list_del(&entry->node);
277                         kfree(entry);
278                 }
279
280                 list_for_each_entry_safe(entry, tmp,
281                                          &cdev_dbg->durations[i], node) {
282                         list_del(&entry->node);
283                         kfree(entry);
284                 }
285         }
286
287         cdev_dbg->total = 0;
288 }
289
290 static void *cdev_seq_start(struct seq_file *s, loff_t *pos)
291 {
292         struct thermal_debugfs *thermal_dbg = s->private;
293
294         mutex_lock(&thermal_dbg->lock);
295
296         return (*pos < CDEVSTATS_HASH_SIZE) ? pos : NULL;
297 }
298
299 static void *cdev_seq_next(struct seq_file *s, void *v, loff_t *pos)
300 {
301         (*pos)++;
302
303         return (*pos < CDEVSTATS_HASH_SIZE) ? pos : NULL;
304 }
305
306 static void cdev_seq_stop(struct seq_file *s, void *v)
307 {
308         struct thermal_debugfs *thermal_dbg = s->private;
309
310         mutex_unlock(&thermal_dbg->lock);
311 }
312
313 static int cdev_tt_seq_show(struct seq_file *s, void *v)
314 {
315         struct thermal_debugfs *thermal_dbg = s->private;
316         struct cdev_debugfs *cdev_dbg = &thermal_dbg->cdev_dbg;
317         struct list_head *transitions = cdev_dbg->transitions;
318         struct cdev_record *entry;
319         int i = *(loff_t *)v;
320
321         if (!i)
322                 seq_puts(s, "Transition\tOccurences\n");
323
324         list_for_each_entry(entry, &transitions[i], node) {
325                 /*
326                  * Assuming maximum cdev states is 1024, the longer
327                  * string for a transition would be "1024->1024\0"
328                  */
329                 char buffer[11];
330
331                 snprintf(buffer, ARRAY_SIZE(buffer), "%d->%d",
332                          entry->id >> 16, entry->id & 0xFFFF);
333
334                 seq_printf(s, "%-10s\t%-10llu\n", buffer, entry->count);
335         }
336
337         return 0;
338 }
339
340 static const struct seq_operations tt_sops = {
341         .start = cdev_seq_start,
342         .next = cdev_seq_next,
343         .stop = cdev_seq_stop,
344         .show = cdev_tt_seq_show,
345 };
346
347 DEFINE_SEQ_ATTRIBUTE(tt);
348
349 static int cdev_dt_seq_show(struct seq_file *s, void *v)
350 {
351         struct thermal_debugfs *thermal_dbg = s->private;
352         struct cdev_debugfs *cdev_dbg = &thermal_dbg->cdev_dbg;
353         struct list_head *durations = cdev_dbg->durations;
354         struct cdev_record *entry;
355         int i = *(loff_t *)v;
356
357         if (!i)
358                 seq_puts(s, "State\tResidency\n");
359
360         list_for_each_entry(entry, &durations[i], node) {
361                 s64 duration = ktime_to_ms(entry->residency);
362
363                 if (entry->id == cdev_dbg->current_state)
364                         duration += ktime_ms_delta(ktime_get(),
365                                                    cdev_dbg->timestamp);
366
367                 seq_printf(s, "%-5d\t%-10llu\n", entry->id, duration);
368         }
369
370         return 0;
371 }
372
373 static const struct seq_operations dt_sops = {
374         .start = cdev_seq_start,
375         .next = cdev_seq_next,
376         .stop = cdev_seq_stop,
377         .show = cdev_dt_seq_show,
378 };
379
380 DEFINE_SEQ_ATTRIBUTE(dt);
381
382 static int cdev_clear_set(void *data, u64 val)
383 {
384         struct thermal_debugfs *thermal_dbg = data;
385
386         if (!val)
387                 return -EINVAL;
388
389         mutex_lock(&thermal_dbg->lock);
390
391         thermal_debugfs_cdev_clear(&thermal_dbg->cdev_dbg);
392
393         mutex_unlock(&thermal_dbg->lock);
394
395         return 0;
396 }
397
398 DEFINE_DEBUGFS_ATTRIBUTE(cdev_clear_fops, NULL, cdev_clear_set, "%llu\n");
399
400 /**
401  * thermal_debug_cdev_state_update - Update a cooling device state change
402  *
403  * Computes a transition and the duration of the previous state residency.
404  *
405  * @cdev : a pointer to a cooling device
406  * @new_state: an integer corresponding to the new cooling device state
407  */
408 void thermal_debug_cdev_state_update(const struct thermal_cooling_device *cdev,
409                                      int new_state)
410 {
411         struct thermal_debugfs *thermal_dbg = cdev->debugfs;
412         struct cdev_debugfs *cdev_dbg;
413         struct cdev_record *cdev_record;
414         int transition, old_state;
415
416         if (!thermal_dbg || (thermal_dbg->cdev_dbg.current_state == new_state))
417                 return;
418
419         mutex_lock(&thermal_dbg->lock);
420
421         cdev_dbg = &thermal_dbg->cdev_dbg;
422
423         old_state = cdev_dbg->current_state;
424
425         /*
426          * Get the old state information in the durations list. If
427          * this one does not exist, a new allocated one will be
428          * returned. Recompute the total duration in the old state and
429          * get a new timestamp for the new state.
430          */
431         cdev_record = thermal_debugfs_cdev_record_get(thermal_dbg,
432                                                       cdev_dbg->durations,
433                                                       old_state);
434         if (cdev_record) {
435                 ktime_t now = ktime_get();
436                 ktime_t delta = ktime_sub(now, cdev_dbg->timestamp);
437                 cdev_record->residency = ktime_add(cdev_record->residency, delta);
438                 cdev_dbg->timestamp = now;
439         }
440
441         cdev_dbg->current_state = new_state;
442
443         /*
444          * Create a record for the new state if it is not there, so its
445          * duration will be printed by cdev_dt_seq_show() as expected if it
446          * runs before the next state transition.
447          */
448         thermal_debugfs_cdev_record_get(thermal_dbg, cdev_dbg->durations, new_state);
449
450         transition = (old_state << 16) | new_state;
451
452         /*
453          * Get the transition in the transitions list. If this one
454          * does not exist, a new allocated one will be returned.
455          * Increment the occurrence of this transition which is stored
456          * in the value field.
457          */
458         cdev_record = thermal_debugfs_cdev_record_get(thermal_dbg,
459                                                       cdev_dbg->transitions,
460                                                       transition);
461         if (cdev_record)
462                 cdev_record->count++;
463
464         cdev_dbg->total++;
465
466         mutex_unlock(&thermal_dbg->lock);
467 }
468
469 /**
470  * thermal_debug_cdev_add - Add a cooling device debugfs entry
471  *
472  * Allocates a cooling device object for debug, initializes the
473  * statistics and create the entries in sysfs.
474  * @cdev: a pointer to a cooling device
475  * @state: current state of the cooling device
476  */
477 void thermal_debug_cdev_add(struct thermal_cooling_device *cdev, int state)
478 {
479         struct thermal_debugfs *thermal_dbg;
480         struct cdev_debugfs *cdev_dbg;
481         int i;
482
483         thermal_dbg = thermal_debugfs_add_id(d_cdev, cdev->id);
484         if (!thermal_dbg)
485                 return;
486
487         cdev_dbg = &thermal_dbg->cdev_dbg;
488
489         for (i = 0; i < CDEVSTATS_HASH_SIZE; i++) {
490                 INIT_LIST_HEAD(&cdev_dbg->transitions[i]);
491                 INIT_LIST_HEAD(&cdev_dbg->durations[i]);
492         }
493
494         cdev_dbg->current_state = state;
495         cdev_dbg->timestamp = ktime_get();
496
497         /*
498          * Create a record for the initial cooling device state, so its
499          * duration will be printed by cdev_dt_seq_show() as expected if it
500          * runs before the first state transition.
501          */
502         thermal_debugfs_cdev_record_get(thermal_dbg, cdev_dbg->durations, state);
503
504         debugfs_create_file("trans_table", 0400, thermal_dbg->d_top,
505                             thermal_dbg, &tt_fops);
506
507         debugfs_create_file("time_in_state_ms", 0400, thermal_dbg->d_top,
508                             thermal_dbg, &dt_fops);
509
510         debugfs_create_file("clear", 0200, thermal_dbg->d_top,
511                             thermal_dbg, &cdev_clear_fops);
512
513         debugfs_create_u32("total_trans", 0400, thermal_dbg->d_top,
514                            &cdev_dbg->total);
515
516         cdev->debugfs = thermal_dbg;
517 }
518
519 /**
520  * thermal_debug_cdev_remove - Remove a cooling device debugfs entry
521  *
522  * Frees the statistics memory data and remove the debugfs entry
523  *
524  * @cdev: a pointer to a cooling device
525  */
526 void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev)
527 {
528         struct thermal_debugfs *thermal_dbg;
529
530         mutex_lock(&cdev->lock);
531
532         thermal_dbg = cdev->debugfs;
533         if (!thermal_dbg) {
534                 mutex_unlock(&cdev->lock);
535                 return;
536         }
537
538         cdev->debugfs = NULL;
539
540         mutex_unlock(&cdev->lock);
541
542         mutex_lock(&thermal_dbg->lock);
543
544         thermal_debugfs_cdev_clear(&thermal_dbg->cdev_dbg);
545
546         mutex_unlock(&thermal_dbg->lock);
547
548         thermal_debugfs_remove_id(thermal_dbg);
549 }
550
551 static struct tz_episode *thermal_debugfs_tz_event_alloc(struct thermal_zone_device *tz,
552                                                         ktime_t now)
553 {
554         struct tz_episode *tze;
555         int i;
556
557         tze = kzalloc(struct_size(tze, trip_stats, tz->num_trips), GFP_KERNEL);
558         if (!tze)
559                 return NULL;
560
561         INIT_LIST_HEAD(&tze->node);
562         tze->timestamp = now;
563         tze->duration = KTIME_MIN;
564         tze->max_temp = INT_MIN;
565
566         for (i = 0; i < tz->num_trips; i++) {
567                 tze->trip_stats[i].trip_temp = THERMAL_TEMP_INVALID;
568                 tze->trip_stats[i].min = INT_MAX;
569         }
570
571         return tze;
572 }
573
574 void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
575                               const struct thermal_trip *trip)
576 {
577         struct thermal_debugfs *thermal_dbg = tz->debugfs;
578         int trip_id = thermal_zone_trip_id(tz, trip);
579         ktime_t now = ktime_get();
580         struct trip_stats *trip_stats;
581         struct tz_debugfs *tz_dbg;
582         struct tz_episode *tze;
583
584         if (!thermal_dbg)
585                 return;
586
587         tz_dbg = &thermal_dbg->tz_dbg;
588
589         mutex_lock(&thermal_dbg->lock);
590
591         /*
592          * The mitigation is starting. A mitigation can contain
593          * several episodes where each of them is related to a
594          * temperature crossing a trip point. The episodes are
595          * nested. That means when the temperature is crossing the
596          * first trip point, the duration begins to be measured. If
597          * the temperature continues to increase and reaches the
598          * second trip point, the duration of the first trip must be
599          * also accumulated.
600          *
601          * eg.
602          *
603          * temp
604          *   ^
605          *   |             --------
606          * trip 2         /        \         ------
607          *   |           /|        |\      /|      |\
608          * trip 1       / |        | `----  |      | \
609          *   |         /| |        |        |      | |\
610          * trip 0     / | |        |        |      | | \
611          *   |       /| | |        |        |      | | |\
612          *   |      / | | |        |        |      | | | `--
613          *   |     /  | | |        |        |      | | |
614          *   |-----   | | |        |        |      | | |
615          *   |        | | |        |        |      | | |
616          *    --------|-|-|--------|--------|------|-|-|------------------> time
617          *            | | |<--t2-->|        |<-t2'>| | |
618          *            | |                            | |
619          *            | |<------------t1------------>| |
620          *            |                                |
621          *            |<-------------t0--------------->|
622          *
623          */
624         if (!tz_dbg->nr_trips) {
625                 tze = thermal_debugfs_tz_event_alloc(tz, now);
626                 if (!tze)
627                         goto unlock;
628
629                 list_add(&tze->node, &tz_dbg->tz_episodes);
630         }
631
632         /*
633          * Each time a trip point is crossed the way up, the trip_id
634          * is stored in the trip_crossed array and the nr_trips is
635          * incremented. A nr_trips equal to zero means we are entering
636          * a mitigation episode.
637          *
638          * The trip ids may not be in the ascending order but the
639          * result in the array trips_crossed will be in the ascending
640          * temperature order. The function detecting when a trip point
641          * is crossed the way down will handle the very rare case when
642          * the trip points may have been reordered during this
643          * mitigation episode.
644          */
645         tz_dbg->trips_crossed[tz_dbg->nr_trips++] = trip_id;
646
647         tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
648         trip_stats = &tze->trip_stats[trip_id];
649         trip_stats->trip_temp = trip->temperature;
650         trip_stats->trip_hyst = trip->hysteresis;
651         trip_stats->timestamp = now;
652
653 unlock:
654         mutex_unlock(&thermal_dbg->lock);
655 }
656
657 static void tz_episode_close_trip(struct tz_episode *tze, int trip_id, ktime_t now)
658 {
659         struct trip_stats *trip_stats = &tze->trip_stats[trip_id];
660         ktime_t delta = ktime_sub(now, trip_stats->timestamp);
661
662         trip_stats->duration = ktime_add(delta, trip_stats->duration);
663         /* Mark the end of mitigation for this trip point. */
664         trip_stats->timestamp = KTIME_MAX;
665 }
666
667 void thermal_debug_tz_trip_down(struct thermal_zone_device *tz,
668                                 const struct thermal_trip *trip)
669 {
670         struct thermal_debugfs *thermal_dbg = tz->debugfs;
671         int trip_id = thermal_zone_trip_id(tz, trip);
672         ktime_t now = ktime_get();
673         struct tz_episode *tze;
674         struct tz_debugfs *tz_dbg;
675         int i;
676
677         if (!thermal_dbg)
678                 return;
679
680         tz_dbg = &thermal_dbg->tz_dbg;
681
682         mutex_lock(&thermal_dbg->lock);
683
684         /*
685          * The temperature crosses the way down but there was not
686          * mitigation detected before. That may happen when the
687          * temperature is greater than a trip point when registering a
688          * thermal zone, which is a common use case as the kernel has
689          * no mitigation mechanism yet at boot time.
690          */
691         if (!tz_dbg->nr_trips)
692                 goto out;
693
694         for (i = tz_dbg->nr_trips - 1; i >= 0; i--) {
695                 if (tz_dbg->trips_crossed[i] == trip_id)
696                         break;
697         }
698
699         if (i < 0)
700                 goto out;
701
702         tz_dbg->nr_trips--;
703
704         if (i < tz_dbg->nr_trips)
705                 tz_dbg->trips_crossed[i] = tz_dbg->trips_crossed[tz_dbg->nr_trips];
706
707         tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
708
709         tz_episode_close_trip(tze, trip_id, now);
710
711         /*
712          * This event closes the mitigation as we are crossing the
713          * last trip point the way down.
714          */
715         if (!tz_dbg->nr_trips)
716                 tze->duration = ktime_sub(now, tze->timestamp);
717
718 out:
719         mutex_unlock(&thermal_dbg->lock);
720 }
721
722 void thermal_debug_update_trip_stats(struct thermal_zone_device *tz)
723 {
724         struct thermal_debugfs *thermal_dbg = tz->debugfs;
725         struct tz_debugfs *tz_dbg;
726         struct tz_episode *tze;
727         int i;
728
729         if (!thermal_dbg)
730                 return;
731
732         tz_dbg = &thermal_dbg->tz_dbg;
733
734         mutex_lock(&thermal_dbg->lock);
735
736         if (!tz_dbg->nr_trips)
737                 goto out;
738
739         tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
740
741         if (tz->temperature > tze->max_temp)
742                 tze->max_temp = tz->temperature;
743
744         for (i = 0; i < tz_dbg->nr_trips; i++) {
745                 int trip_id = tz_dbg->trips_crossed[i];
746                 struct trip_stats *trip_stats = &tze->trip_stats[trip_id];
747
748                 trip_stats->min = min(trip_stats->min, tz->temperature);
749                 trip_stats->avg += (tz->temperature - trip_stats->avg) /
750                                         ++trip_stats->count;
751         }
752 out:
753         mutex_unlock(&thermal_dbg->lock);
754 }
755
756 static void *tze_seq_start(struct seq_file *s, loff_t *pos)
757 {
758         struct thermal_debugfs *thermal_dbg = s->private;
759         struct tz_debugfs *tz_dbg = &thermal_dbg->tz_dbg;
760
761         mutex_lock(&thermal_dbg->lock);
762
763         return seq_list_start(&tz_dbg->tz_episodes, *pos);
764 }
765
766 static void *tze_seq_next(struct seq_file *s, void *v, loff_t *pos)
767 {
768         struct thermal_debugfs *thermal_dbg = s->private;
769         struct tz_debugfs *tz_dbg = &thermal_dbg->tz_dbg;
770
771         return seq_list_next(v, &tz_dbg->tz_episodes, pos);
772 }
773
774 static void tze_seq_stop(struct seq_file *s, void *v)
775 {
776         struct thermal_debugfs *thermal_dbg = s->private;
777
778         mutex_unlock(&thermal_dbg->lock);
779 }
780
781 static int tze_seq_show(struct seq_file *s, void *v)
782 {
783         struct thermal_debugfs *thermal_dbg = s->private;
784         struct thermal_zone_device *tz = thermal_dbg->tz_dbg.tz;
785         struct thermal_trip_desc *td;
786         struct tz_episode *tze;
787         u64 duration_ms;
788         int trip_id;
789         char c;
790
791         tze = list_entry((struct list_head *)v, struct tz_episode, node);
792
793         if (tze->duration == KTIME_MIN) {
794                 /* Mitigation in progress. */
795                 duration_ms = ktime_to_ms(ktime_sub(ktime_get(), tze->timestamp));
796                 c = '>';
797         } else {
798                 duration_ms = ktime_to_ms(tze->duration);
799                 c = '=';
800         }
801
802         seq_printf(s, ",-Mitigation at %llums, duration%c%llums, max. temp=%dm°C\n",
803                    ktime_to_ms(tze->timestamp), c, duration_ms, tze->max_temp);
804
805         seq_printf(s, "| trip |     type | temp(m°C) | hyst(m°C) | duration(ms) |  avg(m°C) |  min(m°C) |\n");
806
807         for_each_trip_desc(tz, td) {
808                 const struct thermal_trip *trip = &td->trip;
809                 struct trip_stats *trip_stats;
810
811                 /*
812                  * There is no possible mitigation happening at the
813                  * critical trip point, so the stats will be always
814                  * zero, skip this trip point
815                  */
816                 if (trip->type == THERMAL_TRIP_CRITICAL)
817                         continue;
818
819                 trip_id = thermal_zone_trip_id(tz, trip);
820                 trip_stats = &tze->trip_stats[trip_id];
821
822                 /* Skip trips without any stats. */
823                 if (trip_stats->trip_temp == THERMAL_TEMP_INVALID)
824                         continue;
825
826                 if (trip_stats->timestamp != KTIME_MAX) {
827                         /* Mitigation in progress. */
828                         ktime_t delta = ktime_sub(ktime_get(),
829                                                   trip_stats->timestamp);
830
831                         delta = ktime_add(delta, trip_stats->duration);
832                         duration_ms = ktime_to_ms(delta);
833                         c = '>';
834                 } else {
835                         duration_ms = ktime_to_ms(trip_stats->duration);
836                         c = ' ';
837                 }
838
839                 seq_printf(s, "| %*d | %*s | %*d | %*d | %c%*lld | %*d | %*d |\n",
840                            4 , trip_id,
841                            8, thermal_trip_type_name(trip->type),
842                            9, trip_stats->trip_temp,
843                            9, trip_stats->trip_hyst,
844                            c, 11, duration_ms,
845                            9, trip_stats->avg,
846                            9, trip_stats->min);
847         }
848
849         return 0;
850 }
851
852 static const struct seq_operations tze_sops = {
853         .start = tze_seq_start,
854         .next = tze_seq_next,
855         .stop = tze_seq_stop,
856         .show = tze_seq_show,
857 };
858
859 DEFINE_SEQ_ATTRIBUTE(tze);
860
861 void thermal_debug_tz_add(struct thermal_zone_device *tz)
862 {
863         struct thermal_debugfs *thermal_dbg;
864         struct tz_debugfs *tz_dbg;
865
866         thermal_dbg = thermal_debugfs_add_id(d_tz, tz->id);
867         if (!thermal_dbg)
868                 return;
869
870         tz_dbg = &thermal_dbg->tz_dbg;
871
872         tz_dbg->tz = tz;
873
874         tz_dbg->trips_crossed = kzalloc(sizeof(int) * tz->num_trips, GFP_KERNEL);
875         if (!tz_dbg->trips_crossed) {
876                 thermal_debugfs_remove_id(thermal_dbg);
877                 return;
878         }
879
880         INIT_LIST_HEAD(&tz_dbg->tz_episodes);
881
882         debugfs_create_file("mitigations", 0400, thermal_dbg->d_top,
883                             thermal_dbg, &tze_fops);
884
885         tz->debugfs = thermal_dbg;
886 }
887
888 void thermal_debug_tz_remove(struct thermal_zone_device *tz)
889 {
890         struct thermal_debugfs *thermal_dbg;
891         struct tz_episode *tze, *tmp;
892         struct tz_debugfs *tz_dbg;
893         int *trips_crossed;
894
895         mutex_lock(&tz->lock);
896
897         thermal_dbg = tz->debugfs;
898         if (!thermal_dbg) {
899                 mutex_unlock(&tz->lock);
900                 return;
901         }
902
903         tz->debugfs = NULL;
904
905         mutex_unlock(&tz->lock);
906
907         tz_dbg = &thermal_dbg->tz_dbg;
908
909         mutex_lock(&thermal_dbg->lock);
910
911         trips_crossed = tz_dbg->trips_crossed;
912
913         list_for_each_entry_safe(tze, tmp, &tz_dbg->tz_episodes, node) {
914                 list_del(&tze->node);
915                 kfree(tze);
916         }
917
918         mutex_unlock(&thermal_dbg->lock);
919
920         thermal_debugfs_remove_id(thermal_dbg);
921         kfree(trips_crossed);
922 }
923
924 void thermal_debug_tz_resume(struct thermal_zone_device *tz)
925 {
926         struct thermal_debugfs *thermal_dbg = tz->debugfs;
927         ktime_t now = ktime_get();
928         struct tz_debugfs *tz_dbg;
929         struct tz_episode *tze;
930         int i;
931
932         if (!thermal_dbg)
933                 return;
934
935         mutex_lock(&thermal_dbg->lock);
936
937         tz_dbg = &thermal_dbg->tz_dbg;
938
939         if (!tz_dbg->nr_trips)
940                 goto out;
941
942         /*
943          * A mitigation episode was in progress before the preceding system
944          * suspend transition, so close it because the zone handling is starting
945          * over from scratch.
946          */
947         tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
948
949         for (i = 0; i < tz_dbg->nr_trips; i++)
950                 tz_episode_close_trip(tze, tz_dbg->trips_crossed[i], now);
951
952         tze->duration = ktime_sub(now, tze->timestamp);
953
954         tz_dbg->nr_trips = 0;
955
956 out:
957         mutex_unlock(&thermal_dbg->lock);
958 }
This page took 0.08548 seconds and 4 git commands to generate.