1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2023 Linaro Limited
5 * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
7 * Thermal subsystem debug support
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>
16 #include "thermal_core.h"
18 static struct dentry
*d_root
;
19 static struct dentry
*d_cdev
;
20 static struct dentry
*d_tz
;
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.
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.
37 #define CDEVSTATS_HASH_SIZE 16
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
47 * Every transition updates the current_state and the timestamp. The
48 * transitions and the durations are stored in lists.
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
60 struct list_head transitions
[CDEVSTATS_HASH_SIZE
];
61 struct list_head durations
[CDEVSTATS_HASH_SIZE
];
65 * struct cdev_record - Common structure for cooling device entry
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.
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
78 struct list_head node
;
87 * struct trip_stats - Thermal trip statistics
89 * The trip_stats structure has the relevant information to show the
90 * statistics related to temperature going above a trip point.
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
111 * struct tz_episode - A mitigation episode information
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.
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
129 struct list_head node
;
131 struct trip_stats trip_stats
[];
135 * struct tz_debugfs - Store all mitigation episodes for a thermal zone
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.
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.
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
151 struct list_head tz_episodes
;
152 struct thermal_zone_device
*tz
;
158 * struct thermal_debugfs - High level structure for a thermal object in debugfs
160 * The thermal_debugfs structure is the common structure used by the
161 * cooling device or the thermal zone to store the statistics.
163 * @d_top: top directory of the thermal object directory
164 * @lock: per object lock to protect the internals
166 * @cdev_dbg: a cooling device debug structure
167 * @tz_dbg: a thermal zone debug structure
169 struct thermal_debugfs
{
170 struct dentry
*d_top
;
173 struct cdev_debugfs cdev_dbg
;
174 struct tz_debugfs tz_dbg
;
178 void thermal_debug_init(void)
180 d_root
= debugfs_create_dir("thermal", NULL
);
184 d_cdev
= debugfs_create_dir("cooling_devices", d_root
);
188 d_tz
= debugfs_create_dir("thermal_zones", d_root
);
191 static struct thermal_debugfs
*thermal_debugfs_add_id(struct dentry
*d
, int id
)
193 struct thermal_debugfs
*thermal_dbg
;
196 thermal_dbg
= kzalloc(sizeof(*thermal_dbg
), GFP_KERNEL
);
200 mutex_init(&thermal_dbg
->lock
);
202 snprintf(ids
, IDSLENGTH
, "%d", id
);
204 thermal_dbg
->d_top
= debugfs_create_dir(ids
, d
);
205 if (IS_ERR(thermal_dbg
->d_top
)) {
213 static void thermal_debugfs_remove_id(struct thermal_debugfs
*thermal_dbg
)
218 debugfs_remove(thermal_dbg
->d_top
);
223 static struct cdev_record
*
224 thermal_debugfs_cdev_record_alloc(struct thermal_debugfs
*thermal_dbg
,
225 struct list_head
*lists
, int id
)
227 struct cdev_record
*cdev_record
;
229 cdev_record
= kzalloc(sizeof(*cdev_record
), GFP_KERNEL
);
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
]);
241 static struct cdev_record
*
242 thermal_debugfs_cdev_record_find(struct thermal_debugfs
*thermal_dbg
,
243 struct list_head
*lists
, int id
)
245 struct cdev_record
*entry
;
247 list_for_each_entry(entry
, &lists
[id
% CDEVSTATS_HASH_SIZE
], node
)
254 static struct cdev_record
*
255 thermal_debugfs_cdev_record_get(struct thermal_debugfs
*thermal_dbg
,
256 struct list_head
*lists
, int id
)
258 struct cdev_record
*cdev_record
;
260 cdev_record
= thermal_debugfs_cdev_record_find(thermal_dbg
, lists
, id
);
264 return thermal_debugfs_cdev_record_alloc(thermal_dbg
, lists
, id
);
267 static void thermal_debugfs_cdev_clear(struct cdev_debugfs
*cdev_dbg
)
270 struct cdev_record
*entry
, *tmp
;
272 for (i
= 0; i
< CDEVSTATS_HASH_SIZE
; i
++) {
274 list_for_each_entry_safe(entry
, tmp
,
275 &cdev_dbg
->transitions
[i
], node
) {
276 list_del(&entry
->node
);
280 list_for_each_entry_safe(entry
, tmp
,
281 &cdev_dbg
->durations
[i
], node
) {
282 list_del(&entry
->node
);
290 static void *cdev_seq_start(struct seq_file
*s
, loff_t
*pos
)
292 struct thermal_debugfs
*thermal_dbg
= s
->private;
294 mutex_lock(&thermal_dbg
->lock
);
296 return (*pos
< CDEVSTATS_HASH_SIZE
) ? pos
: NULL
;
299 static void *cdev_seq_next(struct seq_file
*s
, void *v
, loff_t
*pos
)
303 return (*pos
< CDEVSTATS_HASH_SIZE
) ? pos
: NULL
;
306 static void cdev_seq_stop(struct seq_file
*s
, void *v
)
308 struct thermal_debugfs
*thermal_dbg
= s
->private;
310 mutex_unlock(&thermal_dbg
->lock
);
313 static int cdev_tt_seq_show(struct seq_file
*s
, void *v
)
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
;
322 seq_puts(s
, "Transition\tOccurences\n");
324 list_for_each_entry(entry
, &transitions
[i
], node
) {
326 * Assuming maximum cdev states is 1024, the longer
327 * string for a transition would be "1024->1024\0"
331 snprintf(buffer
, ARRAY_SIZE(buffer
), "%d->%d",
332 entry
->id
>> 16, entry
->id
& 0xFFFF);
334 seq_printf(s
, "%-10s\t%-10llu\n", buffer
, entry
->count
);
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
,
347 DEFINE_SEQ_ATTRIBUTE(tt
);
349 static int cdev_dt_seq_show(struct seq_file
*s
, void *v
)
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
;
358 seq_puts(s
, "State\tResidency\n");
360 list_for_each_entry(entry
, &durations
[i
], node
) {
361 s64 duration
= ktime_to_ms(entry
->residency
);
363 if (entry
->id
== cdev_dbg
->current_state
)
364 duration
+= ktime_ms_delta(ktime_get(),
365 cdev_dbg
->timestamp
);
367 seq_printf(s
, "%-5d\t%-10llu\n", entry
->id
, duration
);
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
,
380 DEFINE_SEQ_ATTRIBUTE(dt
);
382 static int cdev_clear_set(void *data
, u64 val
)
384 struct thermal_debugfs
*thermal_dbg
= data
;
389 mutex_lock(&thermal_dbg
->lock
);
391 thermal_debugfs_cdev_clear(&thermal_dbg
->cdev_dbg
);
393 mutex_unlock(&thermal_dbg
->lock
);
398 DEFINE_DEBUGFS_ATTRIBUTE(cdev_clear_fops
, NULL
, cdev_clear_set
, "%llu\n");
401 * thermal_debug_cdev_state_update - Update a cooling device state change
403 * Computes a transition and the duration of the previous state residency.
405 * @cdev : a pointer to a cooling device
406 * @new_state: an integer corresponding to the new cooling device state
408 void thermal_debug_cdev_state_update(const struct thermal_cooling_device
*cdev
,
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
;
416 if (!thermal_dbg
|| (thermal_dbg
->cdev_dbg
.current_state
== new_state
))
419 mutex_lock(&thermal_dbg
->lock
);
421 cdev_dbg
= &thermal_dbg
->cdev_dbg
;
423 old_state
= cdev_dbg
->current_state
;
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.
431 cdev_record
= thermal_debugfs_cdev_record_get(thermal_dbg
,
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
;
441 cdev_dbg
->current_state
= new_state
;
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.
448 thermal_debugfs_cdev_record_get(thermal_dbg
, cdev_dbg
->durations
, new_state
);
450 transition
= (old_state
<< 16) | new_state
;
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.
458 cdev_record
= thermal_debugfs_cdev_record_get(thermal_dbg
,
459 cdev_dbg
->transitions
,
462 cdev_record
->count
++;
466 mutex_unlock(&thermal_dbg
->lock
);
470 * thermal_debug_cdev_add - Add a cooling device debugfs entry
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
477 void thermal_debug_cdev_add(struct thermal_cooling_device
*cdev
, int state
)
479 struct thermal_debugfs
*thermal_dbg
;
480 struct cdev_debugfs
*cdev_dbg
;
483 thermal_dbg
= thermal_debugfs_add_id(d_cdev
, cdev
->id
);
487 cdev_dbg
= &thermal_dbg
->cdev_dbg
;
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
]);
494 cdev_dbg
->current_state
= state
;
495 cdev_dbg
->timestamp
= ktime_get();
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.
502 thermal_debugfs_cdev_record_get(thermal_dbg
, cdev_dbg
->durations
, state
);
504 debugfs_create_file("trans_table", 0400, thermal_dbg
->d_top
,
505 thermal_dbg
, &tt_fops
);
507 debugfs_create_file("time_in_state_ms", 0400, thermal_dbg
->d_top
,
508 thermal_dbg
, &dt_fops
);
510 debugfs_create_file("clear", 0200, thermal_dbg
->d_top
,
511 thermal_dbg
, &cdev_clear_fops
);
513 debugfs_create_u32("total_trans", 0400, thermal_dbg
->d_top
,
516 cdev
->debugfs
= thermal_dbg
;
519 static struct thermal_debugfs
*thermal_debug_cdev_clear(struct thermal_cooling_device
*cdev
)
521 struct thermal_debugfs
*thermal_dbg
;
523 guard(cooling_dev
)(cdev
);
525 thermal_dbg
= cdev
->debugfs
;
527 cdev
->debugfs
= NULL
;
533 * thermal_debug_cdev_remove - Remove a cooling device debugfs entry
535 * Frees the statistics memory data and remove the debugfs entry
537 * @cdev: a pointer to a cooling device
539 void thermal_debug_cdev_remove(struct thermal_cooling_device
*cdev
)
541 struct thermal_debugfs
*thermal_dbg
;
543 thermal_dbg
= thermal_debug_cdev_clear(cdev
);
547 mutex_lock(&thermal_dbg
->lock
);
549 thermal_debugfs_cdev_clear(&thermal_dbg
->cdev_dbg
);
551 mutex_unlock(&thermal_dbg
->lock
);
553 thermal_debugfs_remove_id(thermal_dbg
);
556 static struct tz_episode
*thermal_debugfs_tz_event_alloc(struct thermal_zone_device
*tz
,
559 struct tz_episode
*tze
;
562 tze
= kzalloc(struct_size(tze
, trip_stats
, tz
->num_trips
), GFP_KERNEL
);
566 INIT_LIST_HEAD(&tze
->node
);
567 tze
->timestamp
= now
;
568 tze
->duration
= KTIME_MIN
;
569 tze
->max_temp
= INT_MIN
;
571 for (i
= 0; i
< tz
->num_trips
; i
++) {
572 tze
->trip_stats
[i
].trip_temp
= THERMAL_TEMP_INVALID
;
573 tze
->trip_stats
[i
].min
= INT_MAX
;
579 void thermal_debug_tz_trip_up(struct thermal_zone_device
*tz
,
580 const struct thermal_trip
*trip
)
582 struct thermal_debugfs
*thermal_dbg
= tz
->debugfs
;
583 int trip_id
= thermal_zone_trip_id(tz
, trip
);
584 ktime_t now
= ktime_get();
585 struct trip_stats
*trip_stats
;
586 struct tz_debugfs
*tz_dbg
;
587 struct tz_episode
*tze
;
592 tz_dbg
= &thermal_dbg
->tz_dbg
;
594 mutex_lock(&thermal_dbg
->lock
);
597 * The mitigation is starting. A mitigation can contain
598 * several episodes where each of them is related to a
599 * temperature crossing a trip point. The episodes are
600 * nested. That means when the temperature is crossing the
601 * first trip point, the duration begins to be measured. If
602 * the temperature continues to increase and reaches the
603 * second trip point, the duration of the first trip must be
613 * trip 1 / | | `---- | | \
615 * trip 0 / | | | | | | \
616 * | /| | | | | | | |\
617 * | / | | | | | | | | `--
618 * | / | | | | | | | |
619 * |----- | | | | | | | |
621 * --------|-|-|--------|--------|------|-|-|------------------> time
622 * | | |<--t2-->| |<-t2'>| | |
624 * | |<------------t1------------>| |
626 * |<-------------t0--------------->|
629 if (!tz_dbg
->nr_trips
) {
630 tze
= thermal_debugfs_tz_event_alloc(tz
, now
);
634 list_add(&tze
->node
, &tz_dbg
->tz_episodes
);
638 * Each time a trip point is crossed the way up, the trip_id
639 * is stored in the trip_crossed array and the nr_trips is
640 * incremented. A nr_trips equal to zero means we are entering
641 * a mitigation episode.
643 * The trip ids may not be in the ascending order but the
644 * result in the array trips_crossed will be in the ascending
645 * temperature order. The function detecting when a trip point
646 * is crossed the way down will handle the very rare case when
647 * the trip points may have been reordered during this
648 * mitigation episode.
650 tz_dbg
->trips_crossed
[tz_dbg
->nr_trips
++] = trip_id
;
652 tze
= list_first_entry(&tz_dbg
->tz_episodes
, struct tz_episode
, node
);
653 trip_stats
= &tze
->trip_stats
[trip_id
];
654 trip_stats
->trip_temp
= trip
->temperature
;
655 trip_stats
->trip_hyst
= trip
->hysteresis
;
656 trip_stats
->timestamp
= now
;
659 mutex_unlock(&thermal_dbg
->lock
);
662 static void tz_episode_close_trip(struct tz_episode
*tze
, int trip_id
, ktime_t now
)
664 struct trip_stats
*trip_stats
= &tze
->trip_stats
[trip_id
];
665 ktime_t delta
= ktime_sub(now
, trip_stats
->timestamp
);
667 trip_stats
->duration
= ktime_add(delta
, trip_stats
->duration
);
668 /* Mark the end of mitigation for this trip point. */
669 trip_stats
->timestamp
= KTIME_MAX
;
672 void thermal_debug_tz_trip_down(struct thermal_zone_device
*tz
,
673 const struct thermal_trip
*trip
)
675 struct thermal_debugfs
*thermal_dbg
= tz
->debugfs
;
676 int trip_id
= thermal_zone_trip_id(tz
, trip
);
677 ktime_t now
= ktime_get();
678 struct tz_episode
*tze
;
679 struct tz_debugfs
*tz_dbg
;
685 tz_dbg
= &thermal_dbg
->tz_dbg
;
687 mutex_lock(&thermal_dbg
->lock
);
690 * The temperature crosses the way down but there was not
691 * mitigation detected before. That may happen when the
692 * temperature is greater than a trip point when registering a
693 * thermal zone, which is a common use case as the kernel has
694 * no mitigation mechanism yet at boot time.
696 if (!tz_dbg
->nr_trips
)
699 for (i
= tz_dbg
->nr_trips
- 1; i
>= 0; i
--) {
700 if (tz_dbg
->trips_crossed
[i
] == trip_id
)
709 if (i
< tz_dbg
->nr_trips
)
710 tz_dbg
->trips_crossed
[i
] = tz_dbg
->trips_crossed
[tz_dbg
->nr_trips
];
712 tze
= list_first_entry(&tz_dbg
->tz_episodes
, struct tz_episode
, node
);
714 tz_episode_close_trip(tze
, trip_id
, now
);
717 * This event closes the mitigation as we are crossing the
718 * last trip point the way down.
720 if (!tz_dbg
->nr_trips
)
721 tze
->duration
= ktime_sub(now
, tze
->timestamp
);
724 mutex_unlock(&thermal_dbg
->lock
);
727 void thermal_debug_update_trip_stats(struct thermal_zone_device
*tz
)
729 struct thermal_debugfs
*thermal_dbg
= tz
->debugfs
;
730 struct tz_debugfs
*tz_dbg
;
731 struct tz_episode
*tze
;
737 tz_dbg
= &thermal_dbg
->tz_dbg
;
739 mutex_lock(&thermal_dbg
->lock
);
741 if (!tz_dbg
->nr_trips
)
744 tze
= list_first_entry(&tz_dbg
->tz_episodes
, struct tz_episode
, node
);
746 if (tz
->temperature
> tze
->max_temp
)
747 tze
->max_temp
= tz
->temperature
;
749 for (i
= 0; i
< tz_dbg
->nr_trips
; i
++) {
750 int trip_id
= tz_dbg
->trips_crossed
[i
];
751 struct trip_stats
*trip_stats
= &tze
->trip_stats
[trip_id
];
753 trip_stats
->min
= min(trip_stats
->min
, tz
->temperature
);
754 trip_stats
->avg
+= (tz
->temperature
- trip_stats
->avg
) /
758 mutex_unlock(&thermal_dbg
->lock
);
761 static void *tze_seq_start(struct seq_file
*s
, loff_t
*pos
)
763 struct thermal_debugfs
*thermal_dbg
= s
->private;
764 struct tz_debugfs
*tz_dbg
= &thermal_dbg
->tz_dbg
;
766 mutex_lock(&thermal_dbg
->lock
);
768 return seq_list_start(&tz_dbg
->tz_episodes
, *pos
);
771 static void *tze_seq_next(struct seq_file
*s
, void *v
, loff_t
*pos
)
773 struct thermal_debugfs
*thermal_dbg
= s
->private;
774 struct tz_debugfs
*tz_dbg
= &thermal_dbg
->tz_dbg
;
776 return seq_list_next(v
, &tz_dbg
->tz_episodes
, pos
);
779 static void tze_seq_stop(struct seq_file
*s
, void *v
)
781 struct thermal_debugfs
*thermal_dbg
= s
->private;
783 mutex_unlock(&thermal_dbg
->lock
);
786 static int tze_seq_show(struct seq_file
*s
, void *v
)
788 struct thermal_debugfs
*thermal_dbg
= s
->private;
789 struct thermal_zone_device
*tz
= thermal_dbg
->tz_dbg
.tz
;
790 struct thermal_trip_desc
*td
;
791 struct tz_episode
*tze
;
796 tze
= list_entry((struct list_head
*)v
, struct tz_episode
, node
);
798 if (tze
->duration
== KTIME_MIN
) {
799 /* Mitigation in progress. */
800 duration_ms
= ktime_to_ms(ktime_sub(ktime_get(), tze
->timestamp
));
803 duration_ms
= ktime_to_ms(tze
->duration
);
807 seq_printf(s
, ",-Mitigation at %llums, duration%c%llums, max. temp=%dm°C\n",
808 ktime_to_ms(tze
->timestamp
), c
, duration_ms
, tze
->max_temp
);
810 seq_printf(s
, "| trip | type | temp(m°C) | hyst(m°C) | duration(ms) | avg(m°C) | min(m°C) |\n");
812 for_each_trip_desc(tz
, td
) {
813 const struct thermal_trip
*trip
= &td
->trip
;
814 struct trip_stats
*trip_stats
;
817 * There is no possible mitigation happening at the
818 * critical trip point, so the stats will be always
819 * zero, skip this trip point
821 if (trip
->type
== THERMAL_TRIP_CRITICAL
)
824 trip_id
= thermal_zone_trip_id(tz
, trip
);
825 trip_stats
= &tze
->trip_stats
[trip_id
];
827 /* Skip trips without any stats. */
828 if (trip_stats
->trip_temp
== THERMAL_TEMP_INVALID
)
831 if (trip_stats
->timestamp
!= KTIME_MAX
) {
832 /* Mitigation in progress. */
833 ktime_t delta
= ktime_sub(ktime_get(),
834 trip_stats
->timestamp
);
836 delta
= ktime_add(delta
, trip_stats
->duration
);
837 duration_ms
= ktime_to_ms(delta
);
840 duration_ms
= ktime_to_ms(trip_stats
->duration
);
844 seq_printf(s
, "| %*d | %*s | %*d | %*d | %c%*lld | %*d | %*d |\n",
846 8, thermal_trip_type_name(trip
->type
),
847 9, trip_stats
->trip_temp
,
848 9, trip_stats
->trip_hyst
,
857 static const struct seq_operations tze_sops
= {
858 .start
= tze_seq_start
,
859 .next
= tze_seq_next
,
860 .stop
= tze_seq_stop
,
861 .show
= tze_seq_show
,
864 DEFINE_SEQ_ATTRIBUTE(tze
);
866 void thermal_debug_tz_add(struct thermal_zone_device
*tz
)
868 struct thermal_debugfs
*thermal_dbg
;
869 struct tz_debugfs
*tz_dbg
;
871 thermal_dbg
= thermal_debugfs_add_id(d_tz
, tz
->id
);
875 tz_dbg
= &thermal_dbg
->tz_dbg
;
879 tz_dbg
->trips_crossed
= kzalloc(sizeof(int) * tz
->num_trips
, GFP_KERNEL
);
880 if (!tz_dbg
->trips_crossed
) {
881 thermal_debugfs_remove_id(thermal_dbg
);
885 INIT_LIST_HEAD(&tz_dbg
->tz_episodes
);
887 debugfs_create_file("mitigations", 0400, thermal_dbg
->d_top
,
888 thermal_dbg
, &tze_fops
);
890 tz
->debugfs
= thermal_dbg
;
893 static struct thermal_debugfs
*thermal_debug_tz_clear(struct thermal_zone_device
*tz
)
895 struct thermal_debugfs
*thermal_dbg
;
897 guard(thermal_zone
)(tz
);
899 thermal_dbg
= tz
->debugfs
;
906 void thermal_debug_tz_remove(struct thermal_zone_device
*tz
)
908 struct thermal_debugfs
*thermal_dbg
;
909 struct tz_episode
*tze
, *tmp
;
910 struct tz_debugfs
*tz_dbg
;
913 thermal_dbg
= thermal_debug_tz_clear(tz
);
917 tz_dbg
= &thermal_dbg
->tz_dbg
;
919 mutex_lock(&thermal_dbg
->lock
);
921 trips_crossed
= tz_dbg
->trips_crossed
;
923 list_for_each_entry_safe(tze
, tmp
, &tz_dbg
->tz_episodes
, node
) {
924 list_del(&tze
->node
);
928 mutex_unlock(&thermal_dbg
->lock
);
930 thermal_debugfs_remove_id(thermal_dbg
);
931 kfree(trips_crossed
);
934 void thermal_debug_tz_resume(struct thermal_zone_device
*tz
)
936 struct thermal_debugfs
*thermal_dbg
= tz
->debugfs
;
937 ktime_t now
= ktime_get();
938 struct tz_debugfs
*tz_dbg
;
939 struct tz_episode
*tze
;
945 mutex_lock(&thermal_dbg
->lock
);
947 tz_dbg
= &thermal_dbg
->tz_dbg
;
949 if (!tz_dbg
->nr_trips
)
953 * A mitigation episode was in progress before the preceding system
954 * suspend transition, so close it because the zone handling is starting
957 tze
= list_first_entry(&tz_dbg
->tz_episodes
, struct tz_episode
, node
);
959 for (i
= 0; i
< tz_dbg
->nr_trips
; i
++)
960 tz_episode_close_trip(tze
, tz_dbg
->trips_crossed
[i
], now
);
962 tze
->duration
= ktime_sub(now
, tze
->timestamp
);
964 tz_dbg
->nr_trips
= 0;
967 mutex_unlock(&thermal_dbg
->lock
);