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