hc
2024-05-16 8d2a02b24d66aa359e83eebc1ed3c0f85367a1cb
kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c
....@@ -1,7 +1,7 @@
11 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
22 /*
33 *
4
- * (C) COPYRIGHT 2011-2021 ARM Limited. All rights reserved.
4
+ * (C) COPYRIGHT 2011-2022 ARM Limited. All rights reserved.
55 *
66 * This program is free software and is provided to you under the terms of the
77 * GNU General Public License version 2 as published by the Free Software
....@@ -24,6 +24,7 @@
2424 */
2525
2626 #include <mali_kbase.h>
27
+#include <mali_kbase_config_defaults.h>
2728 #include <mali_kbase_pm.h>
2829 #include <backend/gpu/mali_kbase_pm_internal.h>
2930
....@@ -37,38 +38,64 @@
3738 #include <backend/gpu/mali_kbase_pm_defs.h>
3839 #include <mali_linux_trace.h>
3940
41
+#if defined(CONFIG_MALI_BIFROST_DEVFREQ) || defined(CONFIG_MALI_BIFROST_DVFS) || !MALI_USE_CSF
4042 /* Shift used for kbasep_pm_metrics_data.time_busy/idle - units of (1 << 8) ns
4143 * This gives a maximum period between samples of 2^(32+8)/100 ns = slightly
4244 * under 11s. Exceeding this will cause overflow
4345 */
4446 #define KBASE_PM_TIME_SHIFT 8
47
+#endif
4548
4649 #if MALI_USE_CSF
4750 /* To get the GPU_ACTIVE value in nano seconds unit */
4851 #define GPU_ACTIVE_SCALING_FACTOR ((u64)1E9)
4952 #endif
5053
54
+/*
55
+ * Possible state transitions
56
+ * ON -> ON | OFF | STOPPED
57
+ * STOPPED -> ON | OFF
58
+ * OFF -> ON
59
+ *
60
+ *
61
+ * ┌─e─┐┌────────────f─────────────┐
62
+ * │ v│ v
63
+ * └───ON ──a──> STOPPED ──b──> OFF
64
+ * ^^ │ │
65
+ * │└──────c─────┘ │
66
+ * │ │
67
+ * └─────────────d─────────────┘
68
+ *
69
+ * Transition effects:
70
+ * a. None
71
+ * b. Timer expires without restart
72
+ * c. Timer is not stopped, timer period is unaffected
73
+ * d. Timer must be restarted
74
+ * e. Callback is executed and the timer is restarted
75
+ * f. Timer is cancelled, or the callback is waited on if currently executing. This is called during
76
+ * tear-down and should not be subject to a race from an OFF->ON transition
77
+ */
78
+enum dvfs_metric_timer_state { TIMER_OFF, TIMER_STOPPED, TIMER_ON };
79
+
5180 #ifdef CONFIG_MALI_BIFROST_DVFS
5281 static enum hrtimer_restart dvfs_callback(struct hrtimer *timer)
5382 {
54
- unsigned long flags;
5583 struct kbasep_pm_metrics_state *metrics;
5684
57
- KBASE_DEBUG_ASSERT(timer != NULL);
85
+ if (WARN_ON(!timer))
86
+ return HRTIMER_NORESTART;
5887
5988 metrics = container_of(timer, struct kbasep_pm_metrics_state, timer);
89
+
90
+ /* Transition (b) to fully off if timer was stopped, don't restart the timer in this case */
91
+ if (atomic_cmpxchg(&metrics->timer_state, TIMER_STOPPED, TIMER_OFF) != TIMER_ON)
92
+ return HRTIMER_NORESTART;
93
+
6094 kbase_pm_get_dvfs_action(metrics->kbdev);
6195
62
- spin_lock_irqsave(&metrics->lock, flags);
63
-
64
- if (metrics->timer_active)
65
- hrtimer_start(timer,
66
- HR_TIMER_DELAY_MSEC(metrics->kbdev->pm.dvfs_period),
67
- HRTIMER_MODE_REL);
68
-
69
- spin_unlock_irqrestore(&metrics->lock, flags);
70
-
71
- return HRTIMER_NORESTART;
96
+ /* Set the new expiration time and restart (transition e) */
97
+ hrtimer_forward_now(timer, HR_TIMER_DELAY_MSEC(metrics->kbdev->pm.dvfs_period));
98
+ return HRTIMER_RESTART;
7299 }
73100 #endif /* CONFIG_MALI_BIFROST_DVFS */
74101
....@@ -83,7 +110,7 @@
83110
84111 KBASE_DEBUG_ASSERT(kbdev != NULL);
85112 kbdev->pm.backend.metrics.kbdev = kbdev;
86
- kbdev->pm.backend.metrics.time_period_start = ktime_get();
113
+ kbdev->pm.backend.metrics.time_period_start = ktime_get_raw();
87114 kbdev->pm.backend.metrics.values.time_busy = 0;
88115 kbdev->pm.backend.metrics.values.time_idle = 0;
89116 kbdev->pm.backend.metrics.values.time_in_protm = 0;
....@@ -111,7 +138,7 @@
111138 #else
112139 KBASE_DEBUG_ASSERT(kbdev != NULL);
113140 kbdev->pm.backend.metrics.kbdev = kbdev;
114
- kbdev->pm.backend.metrics.time_period_start = ktime_get();
141
+ kbdev->pm.backend.metrics.time_period_start = ktime_get_raw();
115142
116143 kbdev->pm.backend.metrics.gpu_active = false;
117144 kbdev->pm.backend.metrics.active_cl_ctx[0] = 0;
....@@ -134,6 +161,7 @@
134161 HRTIMER_MODE_REL);
135162 kbdev->pm.backend.metrics.timer.function = dvfs_callback;
136163 kbdev->pm.backend.metrics.initialized = true;
164
+ atomic_set(&kbdev->pm.backend.metrics.timer_state, TIMER_OFF);
137165 kbase_pm_metrics_start(kbdev);
138166 #endif /* CONFIG_MALI_BIFROST_DVFS */
139167
....@@ -152,16 +180,12 @@
152180 void kbasep_pm_metrics_term(struct kbase_device *kbdev)
153181 {
154182 #ifdef CONFIG_MALI_BIFROST_DVFS
155
- unsigned long flags;
156
-
157183 KBASE_DEBUG_ASSERT(kbdev != NULL);
158184
159
- spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
160
- kbdev->pm.backend.metrics.timer_active = false;
161
- spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
162
-
163
- hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
185
+ /* Cancel the timer, and block if the callback is currently executing (transition f) */
164186 kbdev->pm.backend.metrics.initialized = false;
187
+ atomic_set(&kbdev->pm.backend.metrics.timer_state, TIMER_OFF);
188
+ hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
165189 #endif /* CONFIG_MALI_BIFROST_DVFS */
166190
167191 #if MALI_USE_CSF
....@@ -199,7 +223,7 @@
199223 * elapsed time. The lock taken inside kbase_ipa_control_query()
200224 * function can cause lot of variation.
201225 */
202
- now = ktime_get();
226
+ now = ktime_get_raw();
203227
204228 if (err) {
205229 dev_err(kbdev->dev,
....@@ -231,11 +255,14 @@
231255 * time.
232256 */
233257 if (!kbdev->pm.backend.metrics.skip_gpu_active_sanity_check) {
234
- /* Use a margin value that is approximately 1% of the time
235
- * difference.
258
+ /* The margin is scaled to allow for the worst-case
259
+ * scenario where the samples are maximally separated,
260
+ * plus a small offset for sampling errors.
236261 */
237
- u64 margin_ns = diff_ns >> 6;
238
- if (gpu_active_counter > (diff_ns + margin_ns)) {
262
+ u64 const MARGIN_NS =
263
+ IPA_CONTROL_TIMER_DEFAULT_VALUE_MS * NSEC_PER_MSEC * 3 / 2;
264
+
265
+ if (gpu_active_counter > (diff_ns + MARGIN_NS)) {
239266 dev_info(
240267 kbdev->dev,
241268 "GPU activity takes longer than time interval: %llu ns > %llu ns",
....@@ -330,7 +357,7 @@
330357 #if MALI_USE_CSF
331358 kbase_pm_get_dvfs_utilisation_calc(kbdev);
332359 #else
333
- kbase_pm_get_dvfs_utilisation_calc(kbdev, ktime_get());
360
+ kbase_pm_get_dvfs_utilisation_calc(kbdev, ktime_get_raw());
334361 #endif
335362
336363 memset(diff, 0, sizeof(*diff));
....@@ -395,57 +422,33 @@
395422
396423 bool kbase_pm_metrics_is_active(struct kbase_device *kbdev)
397424 {
398
- bool isactive;
399
- unsigned long flags;
400
-
401425 KBASE_DEBUG_ASSERT(kbdev != NULL);
402426
403
- spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
404
- isactive = kbdev->pm.backend.metrics.timer_active;
405
- spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
406
-
407
- return isactive;
427
+ return atomic_read(&kbdev->pm.backend.metrics.timer_state) == TIMER_ON;
408428 }
409429 KBASE_EXPORT_TEST_API(kbase_pm_metrics_is_active);
410430
411431 void kbase_pm_metrics_start(struct kbase_device *kbdev)
412432 {
413
- unsigned long flags;
414
- bool update = true;
433
+ struct kbasep_pm_metrics_state *metrics = &kbdev->pm.backend.metrics;
415434
416
- if (unlikely(!kbdev->pm.backend.metrics.initialized))
435
+ if (unlikely(!metrics->initialized))
417436 return;
418437
419
- spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
420
- if (!kbdev->pm.backend.metrics.timer_active)
421
- kbdev->pm.backend.metrics.timer_active = true;
422
- else
423
- update = false;
424
- spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
425
-
426
- if (update)
427
- hrtimer_start(&kbdev->pm.backend.metrics.timer,
428
- HR_TIMER_DELAY_MSEC(kbdev->pm.dvfs_period),
429
- HRTIMER_MODE_REL);
438
+ /* Transition to ON, from a stopped state (transition c) */
439
+ if (atomic_xchg(&metrics->timer_state, TIMER_ON) == TIMER_OFF)
440
+ /* Start the timer only if it's been fully stopped (transition d)*/
441
+ hrtimer_start(&metrics->timer, HR_TIMER_DELAY_MSEC(kbdev->pm.dvfs_period),
442
+ HRTIMER_MODE_REL);
430443 }
431444
432445 void kbase_pm_metrics_stop(struct kbase_device *kbdev)
433446 {
434
- unsigned long flags;
435
- bool update = true;
436
-
437447 if (unlikely(!kbdev->pm.backend.metrics.initialized))
438448 return;
439449
440
- spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
441
- if (kbdev->pm.backend.metrics.timer_active)
442
- kbdev->pm.backend.metrics.timer_active = false;
443
- else
444
- update = false;
445
- spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
446
-
447
- if (update)
448
- hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
450
+ /* Timer is Stopped if its currently on (transition a) */
451
+ atomic_cmpxchg(&kbdev->pm.backend.metrics.timer_state, TIMER_ON, TIMER_STOPPED);
449452 }
450453
451454
....@@ -461,7 +464,7 @@
461464 */
462465 static void kbase_pm_metrics_active_calc(struct kbase_device *kbdev)
463466 {
464
- int js;
467
+ unsigned int js;
465468
466469 lockdep_assert_held(&kbdev->pm.backend.metrics.lock);
467470
....@@ -488,8 +491,7 @@
488491 BASE_JD_REQ_SPECIFIC_COHERENT_GROUP)
489492 ? katom->device_nr : 0;
490493 if (!WARN_ON(device_nr >= 2))
491
- kbdev->pm.backend.metrics.
492
- active_cl_ctx[device_nr] = 1;
494
+ kbdev->pm.backend.metrics.active_cl_ctx[device_nr] = 1;
493495 } else {
494496 kbdev->pm.backend.metrics.active_gl_ctx[js] = 1;
495497 trace_sysgraph(SGR_ACTIVE, 0, js);
....@@ -512,7 +514,7 @@
512514 spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
513515
514516 if (!timestamp) {
515
- now = ktime_get();
517
+ now = ktime_get_raw();
516518 timestamp = &now;
517519 }
518520