From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/gpu/arm/bifrost/csf/ipa_control/mali_kbase_csf_ipa_control.c | 352 ++++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 245 insertions(+), 107 deletions(-)
diff --git a/kernel/drivers/gpu/arm/bifrost/csf/ipa_control/mali_kbase_csf_ipa_control.c b/kernel/drivers/gpu/arm/bifrost/csf/ipa_control/mali_kbase_csf_ipa_control.c
index e23d681..c81d0a5 100644
--- a/kernel/drivers/gpu/arm/bifrost/csf/ipa_control/mali_kbase_csf_ipa_control.c
+++ b/kernel/drivers/gpu/arm/bifrost/csf/ipa_control/mali_kbase_csf_ipa_control.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
*
- * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved.
+ * (C) COPYRIGHT 2020-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
@@ -20,6 +20,7 @@
*/
#include <mali_kbase.h>
+#include <mali_kbase_config_defaults.h>
#include "backend/gpu/mali_kbase_clk_rate_trace_mgr.h"
#include "mali_kbase_csf_ipa_control.h"
@@ -27,8 +28,6 @@
* Status flags from the STATUS register of the IPA Control interface.
*/
#define STATUS_COMMAND_ACTIVE ((u32)1 << 0)
-#define STATUS_TIMER_ACTIVE ((u32)1 << 1)
-#define STATUS_AUTO_ACTIVE ((u32)1 << 2)
#define STATUS_PROTECTED_MODE ((u32)1 << 8)
#define STATUS_RESET ((u32)1 << 9)
#define STATUS_TIMER_ENABLED ((u32)1 << 31)
@@ -36,39 +35,27 @@
/*
* Commands for the COMMAND register of the IPA Control interface.
*/
-#define COMMAND_NOP ((u32)0)
#define COMMAND_APPLY ((u32)1)
-#define COMMAND_CLEAR ((u32)2)
#define COMMAND_SAMPLE ((u32)3)
#define COMMAND_PROTECTED_ACK ((u32)4)
#define COMMAND_RESET_ACK ((u32)5)
-/**
- * Default value for the TIMER register of the IPA Control interface,
- * expressed in milliseconds.
- *
- * The chosen value is a trade off between two requirements: the IPA Control
- * interface should sample counters with a resolution in the order of
- * milliseconds, while keeping GPU overhead as limited as possible.
- */
-#define TIMER_DEFAULT_VALUE_MS ((u32)10) /* 10 milliseconds */
-
-/**
+/*
* Number of timer events per second.
*/
-#define TIMER_EVENTS_PER_SECOND ((u32)1000 / TIMER_DEFAULT_VALUE_MS)
+#define TIMER_EVENTS_PER_SECOND ((u32)1000 / IPA_CONTROL_TIMER_DEFAULT_VALUE_MS)
-/**
+/*
* Maximum number of loops polling the GPU before we assume the GPU has hung.
*/
-#define IPA_INACTIVE_MAX_LOOPS ((unsigned int)8000000)
+#define IPA_INACTIVE_MAX_LOOPS (8000000U)
-/**
+/*
* Number of bits used to configure a performance counter in SELECT registers.
*/
#define IPA_CONTROL_SELECT_BITS_PER_CNT ((u64)8)
-/**
+/*
* Maximum value of a performance counter.
*/
#define MAX_PRFCNT_VALUE (((u64)1 << 48) - 1)
@@ -146,8 +133,12 @@
ret = wait_status(kbdev, STATUS_COMMAND_ACTIVE);
- if (!ret)
+ if (!ret) {
kbase_reg_write(kbdev, IPA_CONTROL_REG(COMMAND), COMMAND_APPLY);
+ ret = wait_status(kbdev, STATUS_COMMAND_ACTIVE);
+ } else {
+ dev_err(kbdev->dev, "Wait for the pending command failed");
+ }
return ret;
}
@@ -215,6 +206,17 @@
}
}
+static int update_select_registers(struct kbase_device *kbdev)
+{
+ u64 select_config[KBASE_IPA_CORE_TYPE_NUM];
+
+ lockdep_assert_held(&kbdev->csf.ipa_control.lock);
+
+ build_select_config(&kbdev->csf.ipa_control, select_config);
+
+ return apply_select_config(kbdev, select_config);
+}
+
static inline void calc_prfcnt_delta(struct kbase_device *kbdev,
struct kbase_ipa_control_prfcnt *prfcnt,
bool gpu_ready)
@@ -236,9 +238,15 @@
delta_value *= prfcnt->scaling_factor;
- if (!WARN_ON_ONCE(kbdev->csf.ipa_control.cur_gpu_rate == 0))
- if (prfcnt->gpu_norm)
- delta_value /= kbdev->csf.ipa_control.cur_gpu_rate;
+ if (kbdev->csf.ipa_control.cur_gpu_rate == 0) {
+ static bool warned;
+
+ if (!warned) {
+ dev_warn(kbdev->dev, "%s: GPU freq is unexpectedly 0", __func__);
+ warned = true;
+ }
+ } else if (prfcnt->gpu_norm)
+ delta_value = div_u64(delta_value, kbdev->csf.ipa_control.cur_gpu_rate);
prfcnt->latest_raw_value = raw_value;
@@ -285,17 +293,20 @@
/* Interrupts are already disabled and interrupt state is also saved */
spin_lock(&ipa_ctrl->lock);
- for (i = 0; i < ipa_ctrl->num_active_sessions; i++) {
- size_t j;
+ for (i = 0; i < KBASE_IPA_CONTROL_MAX_SESSIONS; i++) {
struct kbase_ipa_control_session *session = &ipa_ctrl->sessions[i];
- for (j = 0; j < session->num_prfcnts; j++) {
- struct kbase_ipa_control_prfcnt *prfcnt =
- &session->prfcnts[j];
+ if (session->active) {
+ size_t j;
- if (prfcnt->gpu_norm)
- calc_prfcnt_delta(kbdev, prfcnt, true);
- }
+ for (j = 0; j < session->num_prfcnts; j++) {
+ struct kbase_ipa_control_prfcnt *prfcnt =
+ &session->prfcnts[j];
+
+ if (prfcnt->gpu_norm)
+ calc_prfcnt_delta(kbdev, prfcnt, true);
+ }
+ }
}
ipa_ctrl->cur_gpu_rate = clk_rate_hz;
@@ -332,9 +343,8 @@
spin_lock_init(&ipa_ctrl->lock);
ipa_ctrl->num_active_sessions = 0;
- for (i = 0; i < KBASE_IPA_CONTROL_MAX_SESSIONS; i++) {
+ for (i = 0; i < KBASE_IPA_CONTROL_MAX_SESSIONS; i++)
ipa_ctrl->sessions[i].active = false;
- }
listener_data = kmalloc(sizeof(struct kbase_ipa_control_listener_data),
GFP_KERNEL);
@@ -377,6 +387,115 @@
}
KBASE_EXPORT_TEST_API(kbase_ipa_control_term);
+/** session_read_raw_values - Read latest raw values for a sessions
+ * @kbdev: Pointer to kbase device.
+ * @session: Pointer to the session whose performance counters shall be read.
+ *
+ * Read and update the latest raw values of all the performance counters
+ * belonging to a given session.
+ */
+static void session_read_raw_values(struct kbase_device *kbdev,
+ struct kbase_ipa_control_session *session)
+{
+ size_t i;
+
+ lockdep_assert_held(&kbdev->csf.ipa_control.lock);
+
+ for (i = 0; i < session->num_prfcnts; i++) {
+ struct kbase_ipa_control_prfcnt *prfcnt = &session->prfcnts[i];
+ u64 raw_value = read_value_cnt(kbdev, (u8)prfcnt->type,
+ prfcnt->select_idx);
+
+ prfcnt->latest_raw_value = raw_value;
+ }
+}
+
+/** session_gpu_start - Start one or all sessions
+ * @kbdev: Pointer to kbase device.
+ * @ipa_ctrl: Pointer to IPA_CONTROL descriptor.
+ * @session: Pointer to the session to initialize, or NULL to initialize
+ * all sessions.
+ *
+ * This function starts one or all sessions by capturing a manual sample,
+ * reading the latest raw value of performance counters and possibly enabling
+ * the timer for automatic sampling if necessary.
+ *
+ * If a single session is given, it is assumed to be active, regardless of
+ * the number of active sessions. The number of performance counters belonging
+ * to the session shall be set in advance.
+ *
+ * If no session is given, the function shall start all sessions.
+ * The function does nothing if there are no active sessions.
+ *
+ * Return: 0 on success, or error code on failure.
+ */
+static int session_gpu_start(struct kbase_device *kbdev,
+ struct kbase_ipa_control *ipa_ctrl,
+ struct kbase_ipa_control_session *session)
+{
+ bool first_start =
+ (session != NULL) && (ipa_ctrl->num_active_sessions == 0);
+ int ret = 0;
+
+ lockdep_assert_held(&kbdev->csf.ipa_control.lock);
+
+ /*
+ * Exit immediately if the caller intends to start all sessions
+ * but there are no active sessions. It's important that no operation
+ * is done on the IPA_CONTROL interface in that case.
+ */
+ if (!session && ipa_ctrl->num_active_sessions == 0)
+ return ret;
+
+ /*
+ * Take a manual sample unconditionally if the caller intends
+ * to start all sessions. Otherwise, only take a manual sample
+ * if this is the first session to be initialized, for accumulator
+ * registers are empty and no timer has been configured for automatic
+ * sampling.
+ */
+ if (!session || first_start) {
+ kbase_reg_write(kbdev, IPA_CONTROL_REG(COMMAND),
+ COMMAND_SAMPLE);
+ ret = wait_status(kbdev, STATUS_COMMAND_ACTIVE);
+ if (ret)
+ dev_err(kbdev->dev, "%s: failed to sample new counters",
+ __func__);
+ kbase_reg_write(kbdev, IPA_CONTROL_REG(TIMER),
+ timer_value(ipa_ctrl->cur_gpu_rate));
+ }
+
+ /*
+ * Read current raw value to start the session.
+ * This is necessary to put the first query in condition
+ * to generate a correct value by calculating the difference
+ * from the beginning of the session. This consideration
+ * is true regardless of the number of sessions the caller
+ * intends to start.
+ */
+ if (!ret) {
+ if (session) {
+ /* On starting a session, value read is required for
+ * IPA power model's calculation initialization.
+ */
+ session_read_raw_values(kbdev, session);
+ } else {
+ size_t session_idx;
+
+ for (session_idx = 0;
+ session_idx < KBASE_IPA_CONTROL_MAX_SESSIONS;
+ session_idx++) {
+ struct kbase_ipa_control_session *session_to_check = &ipa_ctrl->sessions[session_idx];
+
+ if (session_to_check->active)
+ session_read_raw_values(kbdev, session_to_check);
+ }
+ }
+ }
+
+ return ret;
+}
+
int kbase_ipa_control_register(
struct kbase_device *kbdev,
const struct kbase_ipa_control_perf_counter *perf_counters,
@@ -390,8 +509,10 @@
struct kbase_ipa_control_session *session = NULL;
unsigned long flags;
- if (WARN_ON(kbdev == NULL) || WARN_ON(perf_counters == NULL) ||
- WARN_ON(client == NULL) ||
+ if (WARN_ON(unlikely(kbdev == NULL)))
+ return -ENODEV;
+
+ if (WARN_ON(perf_counters == NULL) || WARN_ON(client == NULL) ||
WARN_ON(num_counters > KBASE_IPA_CONTROL_MAX_COUNTERS)) {
dev_err(kbdev->dev, "%s: wrong input arguments", __func__);
return -EINVAL;
@@ -468,9 +589,10 @@
*/
for (session_idx = 0; session_idx < KBASE_IPA_CONTROL_MAX_SESSIONS;
session_idx++) {
- session = &ipa_ctrl->sessions[session_idx];
- if (!session->active)
+ if (!ipa_ctrl->sessions[session_idx].active) {
+ session = &ipa_ctrl->sessions[session_idx];
break;
+ }
}
if (!session) {
@@ -525,7 +647,7 @@
/* Reports to this client for GPU time spent in protected mode
* should begin from the point of registration.
*/
- session->last_query_time = ktime_get_ns();
+ session->last_query_time = ktime_get_raw_ns();
/* Initially, no time has been spent in protected mode */
session->protm_time = 0;
@@ -539,56 +661,22 @@
* before applying the new configuration.
*/
if (new_config) {
- u64 select_config[KBASE_IPA_CORE_TYPE_NUM];
-
- build_select_config(ipa_ctrl, select_config);
- ret = apply_select_config(kbdev, select_config);
+ ret = update_select_registers(kbdev);
if (ret)
dev_err(kbdev->dev,
- "%s: failed to apply SELECT configuration",
+ "%s: failed to apply new SELECT configuration",
__func__);
}
if (!ret) {
- /* Accumulator registers don't contain any sample if the timer
- * has not been enabled first. Take a sample manually before
- * enabling the timer.
- */
- if (ipa_ctrl->num_active_sessions == 0) {
- kbase_reg_write(kbdev, IPA_CONTROL_REG(COMMAND),
- COMMAND_SAMPLE);
- ret = wait_status(kbdev, STATUS_COMMAND_ACTIVE);
- if (!ret) {
- kbase_reg_write(
- kbdev, IPA_CONTROL_REG(TIMER),
- timer_value(ipa_ctrl->cur_gpu_rate));
- } else {
- dev_err(kbdev->dev,
- "%s: failed to sample new counters",
- __func__);
- }
- }
+ session->num_prfcnts = num_counters;
+ ret = session_gpu_start(kbdev, ipa_ctrl, session);
}
if (!ret) {
- session->num_prfcnts = num_counters;
session->active = true;
ipa_ctrl->num_active_sessions++;
*client = session;
-
- /*
- * Read current raw value to initialize the session.
- * This is necessary to put the first query in condition
- * to generate a correct value by calculating the difference
- * from the beginning of the session.
- */
- for (i = 0; i < session->num_prfcnts; i++) {
- struct kbase_ipa_control_prfcnt *prfcnt =
- &session->prfcnts[i];
- u64 raw_value = read_value_cnt(kbdev, (u8)prfcnt->type,
- prfcnt->select_idx);
- prfcnt->latest_raw_value = raw_value;
- }
}
exit:
@@ -607,7 +695,10 @@
unsigned long flags;
bool new_config = false, valid_session = false;
- if (WARN_ON(kbdev == NULL) || WARN_ON(client == NULL)) {
+ if (WARN_ON(unlikely(kbdev == NULL)))
+ return -ENODEV;
+
+ if (WARN_ON(client == NULL)) {
dev_err(kbdev->dev, "%s: wrong input arguments", __func__);
return -EINVAL;
}
@@ -662,10 +753,7 @@
}
if (new_config) {
- u64 select_config[KBASE_IPA_CORE_TYPE_NUM];
-
- build_select_config(ipa_ctrl, select_config);
- ret = apply_select_config(kbdev, select_config);
+ ret = update_select_registers(kbdev);
if (ret)
dev_err(kbdev->dev,
"%s: failed to apply SELECT configuration",
@@ -692,14 +780,22 @@
unsigned long flags;
bool gpu_ready;
- if (WARN_ON(kbdev == NULL) || WARN_ON(client == NULL) ||
- WARN_ON(values == NULL)) {
+ if (WARN_ON(unlikely(kbdev == NULL)))
+ return -ENODEV;
+
+ if (WARN_ON(client == NULL) || WARN_ON(values == NULL)) {
dev_err(kbdev->dev, "%s: wrong input arguments", __func__);
return -EINVAL;
}
ipa_ctrl = &kbdev->csf.ipa_control;
session = (struct kbase_ipa_control_session *)client;
+
+ if (!session->active) {
+ dev_err(kbdev->dev,
+ "%s: attempt to query inactive session", __func__);
+ return -EINVAL;
+ }
if (WARN_ON(num_values < session->num_prfcnts)) {
dev_err(kbdev->dev,
@@ -721,7 +817,7 @@
}
if (protected_time) {
- u64 time_now = ktime_get_ns();
+ u64 time_now = ktime_get_raw_ns();
/* This is the amount of protected-mode time spent prior to
* the current protm period.
@@ -778,20 +874,23 @@
ret);
}
- for (session_idx = 0; session_idx < ipa_ctrl->num_active_sessions;
+ for (session_idx = 0; session_idx < KBASE_IPA_CONTROL_MAX_SESSIONS;
session_idx++) {
+
struct kbase_ipa_control_session *session =
&ipa_ctrl->sessions[session_idx];
- size_t i;
- for (i = 0; i < session->num_prfcnts; i++) {
- struct kbase_ipa_control_prfcnt *prfcnt =
- &session->prfcnts[i];
+ if (session->active) {
+ size_t i;
- calc_prfcnt_delta(kbdev, prfcnt, true);
+ for (i = 0; i < session->num_prfcnts; i++) {
+ struct kbase_ipa_control_prfcnt *prfcnt =
+ &session->prfcnts[i];
+
+ calc_prfcnt_delta(kbdev, prfcnt, true);
+ }
}
}
-
spin_unlock(&ipa_ctrl->lock);
}
@@ -808,18 +907,16 @@
/* Interrupts are already disabled and interrupt state is also saved */
spin_lock(&ipa_ctrl->lock);
- /* Re-issue the APPLY command, this is actually needed only for CSHW */
- kbase_reg_write(kbdev, IPA_CONTROL_REG(COMMAND), COMMAND_APPLY);
- ret = wait_status(kbdev, STATUS_COMMAND_ACTIVE);
+ ret = update_select_registers(kbdev);
if (ret) {
dev_err(kbdev->dev,
- "Wait for the completion of apply command failed: %d",
- ret);
+ "Failed to reconfigure the select registers: %d", ret);
}
- /* Re-enable the timer for periodic sampling */
- kbase_reg_write(kbdev, IPA_CONTROL_REG(TIMER),
- timer_value(ipa_ctrl->cur_gpu_rate));
+ /* Accumulator registers would not contain any sample after GPU power
+ * cycle if the timer has not been enabled first. Initialize all sessions.
+ */
+ ret = session_gpu_start(kbdev, ipa_ctrl, NULL);
spin_unlock(&ipa_ctrl->lock);
}
@@ -864,6 +961,43 @@
}
KBASE_EXPORT_TEST_API(kbase_ipa_control_handle_gpu_reset_post);
+#ifdef KBASE_PM_RUNTIME
+void kbase_ipa_control_handle_gpu_sleep_enter(struct kbase_device *kbdev)
+{
+ lockdep_assert_held(&kbdev->hwaccess_lock);
+
+ if (kbdev->pm.backend.mcu_state == KBASE_MCU_IN_SLEEP) {
+ /* GPU Sleep is treated as a power down */
+ kbase_ipa_control_handle_gpu_power_off(kbdev);
+
+ /* SELECT_CSHW register needs to be cleared to prevent any
+ * IPA control message to be sent to the top level GPU HWCNT.
+ */
+ kbase_reg_write(kbdev, IPA_CONTROL_REG(SELECT_CSHW_LO), 0);
+ kbase_reg_write(kbdev, IPA_CONTROL_REG(SELECT_CSHW_HI), 0);
+
+ /* No need to issue the APPLY command here */
+ }
+}
+KBASE_EXPORT_TEST_API(kbase_ipa_control_handle_gpu_sleep_enter);
+
+void kbase_ipa_control_handle_gpu_sleep_exit(struct kbase_device *kbdev)
+{
+ lockdep_assert_held(&kbdev->hwaccess_lock);
+
+ if (kbdev->pm.backend.mcu_state == KBASE_MCU_IN_SLEEP) {
+ /* To keep things simple, currently exit from
+ * GPU Sleep is treated as a power on event where
+ * all 4 SELECT registers are reconfigured.
+ * On exit from sleep, reconfiguration is needed
+ * only for the SELECT_CSHW register.
+ */
+ kbase_ipa_control_handle_gpu_power_on(kbdev);
+ }
+}
+KBASE_EXPORT_TEST_API(kbase_ipa_control_handle_gpu_sleep_exit);
+#endif
+
#if MALI_UNIT_TEST
void kbase_ipa_control_rate_change_notify_test(struct kbase_device *kbdev,
u32 clk_index, u32 clk_rate_hz)
@@ -883,25 +1017,29 @@
struct kbase_ipa_control *ipa_ctrl = &kbdev->csf.ipa_control;
lockdep_assert_held(&kbdev->hwaccess_lock);
- ipa_ctrl->protm_start = ktime_get_ns();
+ ipa_ctrl->protm_start = ktime_get_raw_ns();
}
void kbase_ipa_control_protm_exited(struct kbase_device *kbdev)
{
struct kbase_ipa_control *ipa_ctrl = &kbdev->csf.ipa_control;
size_t i;
- u64 time_now = ktime_get_ns();
+ u64 time_now = ktime_get_raw_ns();
u32 status;
lockdep_assert_held(&kbdev->hwaccess_lock);
- for (i = 0; i < ipa_ctrl->num_active_sessions; i++) {
+ for (i = 0; i < KBASE_IPA_CONTROL_MAX_SESSIONS; i++) {
+
struct kbase_ipa_control_session *session =
&ipa_ctrl->sessions[i];
- u64 protm_time = time_now - MAX(session->last_query_time,
- ipa_ctrl->protm_start);
- session->protm_time += protm_time;
+ if (session->active) {
+ u64 protm_time = time_now - MAX(session->last_query_time,
+ ipa_ctrl->protm_start);
+
+ session->protm_time += protm_time;
+ }
}
/* Acknowledge the protected_mode bit in the IPA_CONTROL STATUS
--
Gitblit v1.6.2