From 102a0743326a03cd1a1202ceda21e175b7d3575c Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:20:52 +0000
Subject: [PATCH] add new system file
---
kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c | 134 ++++++++++++++++++++++----------------------
1 files changed, 68 insertions(+), 66 deletions(-)
diff --git a/kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c b/kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c
index 551bf44..865f526 100644
--- a/kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c
+++ b/kernel/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_pm_metrics.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
*
- * (C) COPYRIGHT 2011-2021 ARM Limited. All rights reserved.
+ * (C) COPYRIGHT 2011-2022 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@@ -24,6 +24,7 @@
*/
#include <mali_kbase.h>
+#include <mali_kbase_config_defaults.h>
#include <mali_kbase_pm.h>
#include <backend/gpu/mali_kbase_pm_internal.h>
@@ -37,38 +38,64 @@
#include <backend/gpu/mali_kbase_pm_defs.h>
#include <mali_linux_trace.h>
+#if defined(CONFIG_MALI_BIFROST_DEVFREQ) || defined(CONFIG_MALI_BIFROST_DVFS) || !MALI_USE_CSF
/* Shift used for kbasep_pm_metrics_data.time_busy/idle - units of (1 << 8) ns
* This gives a maximum period between samples of 2^(32+8)/100 ns = slightly
* under 11s. Exceeding this will cause overflow
*/
#define KBASE_PM_TIME_SHIFT 8
+#endif
#if MALI_USE_CSF
/* To get the GPU_ACTIVE value in nano seconds unit */
#define GPU_ACTIVE_SCALING_FACTOR ((u64)1E9)
#endif
+/*
+ * Possible state transitions
+ * ON -> ON | OFF | STOPPED
+ * STOPPED -> ON | OFF
+ * OFF -> ON
+ *
+ *
+ * ┌─e─┐┌────────────f─────────────┐
+ * │ v│ v
+ * └───ON ──a──> STOPPED ──b──> OFF
+ * ^^ │ │
+ * │└──────c─────┘ │
+ * │ │
+ * └─────────────d─────────────┘
+ *
+ * Transition effects:
+ * a. None
+ * b. Timer expires without restart
+ * c. Timer is not stopped, timer period is unaffected
+ * d. Timer must be restarted
+ * e. Callback is executed and the timer is restarted
+ * f. Timer is cancelled, or the callback is waited on if currently executing. This is called during
+ * tear-down and should not be subject to a race from an OFF->ON transition
+ */
+enum dvfs_metric_timer_state { TIMER_OFF, TIMER_STOPPED, TIMER_ON };
+
#ifdef CONFIG_MALI_BIFROST_DVFS
static enum hrtimer_restart dvfs_callback(struct hrtimer *timer)
{
- unsigned long flags;
struct kbasep_pm_metrics_state *metrics;
- KBASE_DEBUG_ASSERT(timer != NULL);
+ if (WARN_ON(!timer))
+ return HRTIMER_NORESTART;
metrics = container_of(timer, struct kbasep_pm_metrics_state, timer);
+
+ /* Transition (b) to fully off if timer was stopped, don't restart the timer in this case */
+ if (atomic_cmpxchg(&metrics->timer_state, TIMER_STOPPED, TIMER_OFF) != TIMER_ON)
+ return HRTIMER_NORESTART;
+
kbase_pm_get_dvfs_action(metrics->kbdev);
- spin_lock_irqsave(&metrics->lock, flags);
-
- if (metrics->timer_active)
- hrtimer_start(timer,
- HR_TIMER_DELAY_MSEC(metrics->kbdev->pm.dvfs_period),
- HRTIMER_MODE_REL);
-
- spin_unlock_irqrestore(&metrics->lock, flags);
-
- return HRTIMER_NORESTART;
+ /* Set the new expiration time and restart (transition e) */
+ hrtimer_forward_now(timer, HR_TIMER_DELAY_MSEC(metrics->kbdev->pm.dvfs_period));
+ return HRTIMER_RESTART;
}
#endif /* CONFIG_MALI_BIFROST_DVFS */
@@ -83,7 +110,7 @@
KBASE_DEBUG_ASSERT(kbdev != NULL);
kbdev->pm.backend.metrics.kbdev = kbdev;
- kbdev->pm.backend.metrics.time_period_start = ktime_get();
+ kbdev->pm.backend.metrics.time_period_start = ktime_get_raw();
kbdev->pm.backend.metrics.values.time_busy = 0;
kbdev->pm.backend.metrics.values.time_idle = 0;
kbdev->pm.backend.metrics.values.time_in_protm = 0;
@@ -111,7 +138,7 @@
#else
KBASE_DEBUG_ASSERT(kbdev != NULL);
kbdev->pm.backend.metrics.kbdev = kbdev;
- kbdev->pm.backend.metrics.time_period_start = ktime_get();
+ kbdev->pm.backend.metrics.time_period_start = ktime_get_raw();
kbdev->pm.backend.metrics.gpu_active = false;
kbdev->pm.backend.metrics.active_cl_ctx[0] = 0;
@@ -134,6 +161,7 @@
HRTIMER_MODE_REL);
kbdev->pm.backend.metrics.timer.function = dvfs_callback;
kbdev->pm.backend.metrics.initialized = true;
+ atomic_set(&kbdev->pm.backend.metrics.timer_state, TIMER_OFF);
kbase_pm_metrics_start(kbdev);
#endif /* CONFIG_MALI_BIFROST_DVFS */
@@ -152,16 +180,12 @@
void kbasep_pm_metrics_term(struct kbase_device *kbdev)
{
#ifdef CONFIG_MALI_BIFROST_DVFS
- unsigned long flags;
-
KBASE_DEBUG_ASSERT(kbdev != NULL);
- spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
- kbdev->pm.backend.metrics.timer_active = false;
- spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
-
- hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
+ /* Cancel the timer, and block if the callback is currently executing (transition f) */
kbdev->pm.backend.metrics.initialized = false;
+ atomic_set(&kbdev->pm.backend.metrics.timer_state, TIMER_OFF);
+ hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
#endif /* CONFIG_MALI_BIFROST_DVFS */
#if MALI_USE_CSF
@@ -199,7 +223,7 @@
* elapsed time. The lock taken inside kbase_ipa_control_query()
* function can cause lot of variation.
*/
- now = ktime_get();
+ now = ktime_get_raw();
if (err) {
dev_err(kbdev->dev,
@@ -231,11 +255,14 @@
* time.
*/
if (!kbdev->pm.backend.metrics.skip_gpu_active_sanity_check) {
- /* Use a margin value that is approximately 1% of the time
- * difference.
+ /* The margin is scaled to allow for the worst-case
+ * scenario where the samples are maximally separated,
+ * plus a small offset for sampling errors.
*/
- u64 margin_ns = diff_ns >> 6;
- if (gpu_active_counter > (diff_ns + margin_ns)) {
+ u64 const MARGIN_NS =
+ IPA_CONTROL_TIMER_DEFAULT_VALUE_MS * NSEC_PER_MSEC * 3 / 2;
+
+ if (gpu_active_counter > (diff_ns + MARGIN_NS)) {
dev_info(
kbdev->dev,
"GPU activity takes longer than time interval: %llu ns > %llu ns",
@@ -330,7 +357,7 @@
#if MALI_USE_CSF
kbase_pm_get_dvfs_utilisation_calc(kbdev);
#else
- kbase_pm_get_dvfs_utilisation_calc(kbdev, ktime_get());
+ kbase_pm_get_dvfs_utilisation_calc(kbdev, ktime_get_raw());
#endif
memset(diff, 0, sizeof(*diff));
@@ -395,57 +422,33 @@
bool kbase_pm_metrics_is_active(struct kbase_device *kbdev)
{
- bool isactive;
- unsigned long flags;
-
KBASE_DEBUG_ASSERT(kbdev != NULL);
- spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
- isactive = kbdev->pm.backend.metrics.timer_active;
- spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
-
- return isactive;
+ return atomic_read(&kbdev->pm.backend.metrics.timer_state) == TIMER_ON;
}
KBASE_EXPORT_TEST_API(kbase_pm_metrics_is_active);
void kbase_pm_metrics_start(struct kbase_device *kbdev)
{
- unsigned long flags;
- bool update = true;
+ struct kbasep_pm_metrics_state *metrics = &kbdev->pm.backend.metrics;
- if (unlikely(!kbdev->pm.backend.metrics.initialized))
+ if (unlikely(!metrics->initialized))
return;
- spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
- if (!kbdev->pm.backend.metrics.timer_active)
- kbdev->pm.backend.metrics.timer_active = true;
- else
- update = false;
- spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
-
- if (update)
- hrtimer_start(&kbdev->pm.backend.metrics.timer,
- HR_TIMER_DELAY_MSEC(kbdev->pm.dvfs_period),
- HRTIMER_MODE_REL);
+ /* Transition to ON, from a stopped state (transition c) */
+ if (atomic_xchg(&metrics->timer_state, TIMER_ON) == TIMER_OFF)
+ /* Start the timer only if it's been fully stopped (transition d)*/
+ hrtimer_start(&metrics->timer, HR_TIMER_DELAY_MSEC(kbdev->pm.dvfs_period),
+ HRTIMER_MODE_REL);
}
void kbase_pm_metrics_stop(struct kbase_device *kbdev)
{
- unsigned long flags;
- bool update = true;
-
if (unlikely(!kbdev->pm.backend.metrics.initialized))
return;
- spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
- if (kbdev->pm.backend.metrics.timer_active)
- kbdev->pm.backend.metrics.timer_active = false;
- else
- update = false;
- spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
-
- if (update)
- hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
+ /* Timer is Stopped if its currently on (transition a) */
+ atomic_cmpxchg(&kbdev->pm.backend.metrics.timer_state, TIMER_ON, TIMER_STOPPED);
}
@@ -461,7 +464,7 @@
*/
static void kbase_pm_metrics_active_calc(struct kbase_device *kbdev)
{
- int js;
+ unsigned int js;
lockdep_assert_held(&kbdev->pm.backend.metrics.lock);
@@ -488,8 +491,7 @@
BASE_JD_REQ_SPECIFIC_COHERENT_GROUP)
? katom->device_nr : 0;
if (!WARN_ON(device_nr >= 2))
- kbdev->pm.backend.metrics.
- active_cl_ctx[device_nr] = 1;
+ kbdev->pm.backend.metrics.active_cl_ctx[device_nr] = 1;
} else {
kbdev->pm.backend.metrics.active_gl_ctx[js] = 1;
trace_sysgraph(SGR_ACTIVE, 0, js);
@@ -512,7 +514,7 @@
spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
if (!timestamp) {
- now = ktime_get();
+ now = ktime_get_raw();
timestamp = &now;
}
--
Gitblit v1.6.2