summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Wagner <jorwag@google.com>2023-08-31 17:27:24 +0000
committerJörg Wagner <jorwag@google.com>2023-08-31 17:27:24 +0000
commite61eb93296e9f940b32d4ad4b0c3a5557cbeaf17 (patch)
tree4c649cc9f5a08e8362f9d564f121f46b07d89ecd
parentdacf004cc8a4b35f5a0fb5fb67246f9cc8fdaafb (diff)
downloadgpu-e61eb93296e9f940b32d4ad4b0c3a5557cbeaf17.tar.gz
Update KMD to 'mini release: update r44p1-00dev2 to r44p1-00dev3'
Provenance: ipdelivery@5c8fdf6c071d63537e87949cfb4845079a669a0b Change-Id: Icc06581f804bf59be5fe923349318e703f02d5a3
-rw-r--r--mali_kbase/Kbuild2
-rw-r--r--mali_kbase/backend/gpu/mali_kbase_clk_rate_trace_mgr.c6
-rw-r--r--mali_kbase/backend/gpu/mali_kbase_jm_rb.c48
-rw-r--r--mali_kbase/backend/gpu/mali_kbase_pm_driver.c72
-rw-r--r--mali_kbase/backend/gpu/mali_kbase_pm_internal.h35
-rw-r--r--mali_kbase/csf/ipa_control/mali_kbase_csf_ipa_control.c136
-rw-r--r--mali_kbase/csf/mali_kbase_csf.c5
-rw-r--r--mali_kbase/csf/mali_kbase_csf.h2
-rw-r--r--mali_kbase/csf/mali_kbase_csf_defs.h29
-rw-r--r--mali_kbase/csf/mali_kbase_csf_firmware.c119
-rw-r--r--mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c2
-rw-r--r--mali_kbase/csf/mali_kbase_csf_firmware_log.c2
-rw-r--r--mali_kbase/csf/mali_kbase_csf_firmware_no_mali.c45
-rw-r--r--mali_kbase/csf/mali_kbase_csf_registers.h28
-rw-r--r--mali_kbase/csf/mali_kbase_csf_reset_gpu.c2
-rw-r--r--mali_kbase/csf/mali_kbase_csf_scheduler.c68
-rw-r--r--mali_kbase/csf/mali_kbase_csf_scheduler.h16
-rw-r--r--mali_kbase/csf/mali_kbase_csf_timeout.c2
-rw-r--r--mali_kbase/device/backend/mali_kbase_device_hw_csf.c3
-rw-r--r--mali_kbase/gpu/backend/mali_kbase_gpu_regmap_csf.h13
-rw-r--r--mali_kbase/gpu/mali_kbase_gpu_regmap.h1
-rw-r--r--mali_kbase/jm/mali_kbase_jm_defs.h5
-rw-r--r--mali_kbase/mali_base_hwconfig_issues.h10
-rw-r--r--mali_kbase/mali_kbase_core_linux.c155
-rw-r--r--mali_kbase/mali_kbase_ctx_sched.c3
-rw-r--r--mali_kbase/mali_kbase_defs.h17
-rw-r--r--mali_kbase/mali_kbase_gpu_metrics.c38
-rw-r--r--mali_kbase/mali_kbase_mem.c2
-rw-r--r--mali_kbase/mmu/backend/mali_kbase_mmu_csf.c3
-rw-r--r--mali_kbase/mmu/backend/mali_kbase_mmu_jm.c3
-rw-r--r--mali_kbase/mmu/mali_kbase_mmu_hw_direct.c25
31 files changed, 629 insertions, 268 deletions
diff --git a/mali_kbase/Kbuild b/mali_kbase/Kbuild
index d211f00..ba184d8 100644
--- a/mali_kbase/Kbuild
+++ b/mali_kbase/Kbuild
@@ -69,7 +69,7 @@ endif
#
# Driver version string which is returned to userspace via an ioctl
-MALI_RELEASE_NAME ?= '"r44p1-00dev2"'
+MALI_RELEASE_NAME ?= '"r44p1-01bet1"'
# Set up defaults if not defined by build system
ifeq ($(CONFIG_MALI_DEBUG), y)
MALI_UNIT_TEST = 1
diff --git a/mali_kbase/backend/gpu/mali_kbase_clk_rate_trace_mgr.c b/mali_kbase/backend/gpu/mali_kbase_clk_rate_trace_mgr.c
index 912bac5..cca4f74 100644
--- a/mali_kbase/backend/gpu/mali_kbase_clk_rate_trace_mgr.c
+++ b/mali_kbase/backend/gpu/mali_kbase_clk_rate_trace_mgr.c
@@ -243,8 +243,7 @@ void kbase_clk_rate_trace_manager_gpu_active(struct kbase_device *kbdev)
if (!clk_rtm->clk_rate_trace_ops)
return;
- spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
- spin_lock(&clk_rtm->lock);
+ spin_lock_irqsave(&clk_rtm->lock, flags);
for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) {
struct kbase_clk_data *clk_data = clk_rtm->clks[i];
@@ -260,8 +259,7 @@ void kbase_clk_rate_trace_manager_gpu_active(struct kbase_device *kbdev)
}
clk_rtm->gpu_idle = false;
- spin_unlock(&clk_rtm->lock);
- spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
+ spin_unlock_irqrestore(&clk_rtm->lock, flags);
}
void kbase_clk_rate_trace_manager_gpu_idle(struct kbase_device *kbdev)
diff --git a/mali_kbase/backend/gpu/mali_kbase_jm_rb.c b/mali_kbase/backend/gpu/mali_kbase_jm_rb.c
index efef482..decefa4 100644
--- a/mali_kbase/backend/gpu/mali_kbase_jm_rb.c
+++ b/mali_kbase/backend/gpu/mali_kbase_jm_rb.c
@@ -1156,6 +1156,25 @@ kbase_rb_atom_might_depend(const struct kbase_jd_atom *katom_a,
KBASE_KATOM_FLAG_FAIL_BLOCKER)));
}
+static inline void kbase_gpu_remove_atom(struct kbase_device *kbdev,
+ struct kbase_jd_atom *katom,
+ u32 action,
+ bool disjoint)
+{
+ struct kbase_context *kctx = katom->kctx;
+
+ lockdep_assert_held(&kbdev->hwaccess_lock);
+
+ katom->event_code = BASE_JD_EVENT_REMOVED_FROM_NEXT;
+ kbase_gpu_mark_atom_for_return(kbdev, katom);
+ kbase_jsctx_slot_prio_blocked_set(kctx, katom->slot_nr,
+ katom->sched_priority);
+
+ if (disjoint)
+ kbase_job_check_enter_disjoint(kbdev, action, katom->core_req,
+ katom);
+}
+
/**
* kbase_gpu_irq_evict - evict a slot's JSn_HEAD_NEXT atom from the HW if it is
* related to a failed JSn_HEAD atom
@@ -1206,9 +1225,9 @@ bool kbase_gpu_irq_evict(struct kbase_device *kbdev, unsigned int js, u32 comple
kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_HEAD_NEXT_HI)) != 0)) {
kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT),
JS_COMMAND_NOP);
- next_katom->gpu_rb_state = KBASE_ATOM_GPU_RB_READY;
if (completion_code == BASE_JD_EVENT_STOPPED) {
+ kbase_gpu_remove_atom(kbdev, next_katom, JS_COMMAND_SOFT_STOP, false);
KBASE_TLSTREAM_TL_NRET_ATOM_LPU(kbdev, next_katom,
&kbdev->gpu_props.props.raw_props.js_features
[next_katom->slot_nr]);
@@ -1217,10 +1236,12 @@ bool kbase_gpu_irq_evict(struct kbase_device *kbdev, unsigned int js, u32 comple
KBASE_TLSTREAM_TL_NRET_CTX_LPU(kbdev, next_katom->kctx,
&kbdev->gpu_props.props.raw_props.js_features
[next_katom->slot_nr]);
- }
+ } else {
+ next_katom->gpu_rb_state = KBASE_ATOM_GPU_RB_READY;
- if (next_katom->core_req & BASE_JD_REQ_PERMON)
- kbase_pm_release_gpu_cycle_counter_nolock(kbdev);
+ if (next_katom->core_req & BASE_JD_REQ_PERMON)
+ kbase_pm_release_gpu_cycle_counter_nolock(kbdev);
+ }
/* On evicting the next_katom, the last submission kctx on the
* given job slot then reverts back to the one that owns katom.
@@ -1605,25 +1626,6 @@ static inline void kbase_gpu_stop_atom(struct kbase_device *kbdev, unsigned int
kbase_jsctx_slot_prio_blocked_set(kctx, js, katom->sched_priority);
}
-static inline void kbase_gpu_remove_atom(struct kbase_device *kbdev,
- struct kbase_jd_atom *katom,
- u32 action,
- bool disjoint)
-{
- struct kbase_context *kctx = katom->kctx;
-
- lockdep_assert_held(&kbdev->hwaccess_lock);
-
- katom->event_code = BASE_JD_EVENT_REMOVED_FROM_NEXT;
- kbase_gpu_mark_atom_for_return(kbdev, katom);
- kbase_jsctx_slot_prio_blocked_set(kctx, katom->slot_nr,
- katom->sched_priority);
-
- if (disjoint)
- kbase_job_check_enter_disjoint(kbdev, action, katom->core_req,
- katom);
-}
-
static int should_stop_x_dep_slot(struct kbase_jd_atom *katom)
{
if (katom->x_post_dep) {
diff --git a/mali_kbase/backend/gpu/mali_kbase_pm_driver.c b/mali_kbase/backend/gpu/mali_kbase_pm_driver.c
index aab4106..b1b53e7 100644
--- a/mali_kbase/backend/gpu/mali_kbase_pm_driver.c
+++ b/mali_kbase/backend/gpu/mali_kbase_pm_driver.c
@@ -2414,7 +2414,7 @@ int kbase_pm_wait_for_l2_powered(struct kbase_device *kbdev)
return err;
}
-int kbase_pm_wait_for_desired_state(struct kbase_device *kbdev)
+static int pm_wait_for_desired_state(struct kbase_device *kbdev, bool killable_wait)
{
unsigned long flags;
long remaining;
@@ -2432,26 +2432,37 @@ int kbase_pm_wait_for_desired_state(struct kbase_device *kbdev)
/* Wait for cores */
#if KERNEL_VERSION(4, 13, 1) <= LINUX_VERSION_CODE
- remaining = wait_event_killable_timeout(
- kbdev->pm.backend.gpu_in_desired_state_wait,
- kbase_pm_is_in_desired_state(kbdev), timeout);
+ if (killable_wait)
+ remaining = wait_event_killable_timeout(kbdev->pm.backend.gpu_in_desired_state_wait,
+ kbase_pm_is_in_desired_state(kbdev),
+ timeout);
#else
- remaining = wait_event_timeout(
- kbdev->pm.backend.gpu_in_desired_state_wait,
- kbase_pm_is_in_desired_state(kbdev), timeout);
+ killable_wait = false;
#endif
-
+ if (!killable_wait)
+ remaining = wait_event_timeout(kbdev->pm.backend.gpu_in_desired_state_wait,
+ kbase_pm_is_in_desired_state(kbdev), timeout);
if (!remaining) {
kbase_pm_timed_out(kbdev, "Wait for power transition timed out");
err = -ETIMEDOUT;
} else if (remaining < 0) {
- dev_info(kbdev->dev,
- "Wait for power transition got interrupted");
+ WARN_ON_ONCE(!killable_wait);
+ dev_info(kbdev->dev, "Wait for power transition got interrupted");
err = (int)remaining;
}
return err;
}
+
+int kbase_pm_killable_wait_for_desired_state(struct kbase_device *kbdev)
+{
+ return pm_wait_for_desired_state(kbdev, true);
+}
+
+int kbase_pm_wait_for_desired_state(struct kbase_device *kbdev)
+{
+ return pm_wait_for_desired_state(kbdev, false);
+}
KBASE_EXPORT_TEST_API(kbase_pm_wait_for_desired_state);
#if MALI_USE_CSF
@@ -2526,7 +2537,7 @@ static bool is_poweroff_wait_in_progress(struct kbase_device *kbdev)
return ret;
}
-int kbase_pm_wait_for_poweroff_work_complete(struct kbase_device *kbdev)
+static int pm_wait_for_poweroff_work_complete(struct kbase_device *kbdev, bool killable_wait)
{
long remaining;
#if MALI_USE_CSF
@@ -2534,24 +2545,51 @@ int kbase_pm_wait_for_poweroff_work_complete(struct kbase_device *kbdev)
* and so the wait time can't only be the function of GPU frequency.
*/
const unsigned int extra_wait_time_ms = 2000;
- const long timeout =
- kbase_csf_timeout_in_jiffies(kbase_get_timeout_ms(kbdev, CSF_PM_TIMEOUT) +
- extra_wait_time_ms);
+ const long timeout = kbase_csf_timeout_in_jiffies(
+ kbase_get_timeout_ms(kbdev, CSF_PM_TIMEOUT) + extra_wait_time_ms);
+#else
+#ifdef CONFIG_MALI_ARBITER_SUPPORT
+ /* Handling of timeout error isn't supported for arbiter builds */
+ const long timeout = MAX_SCHEDULE_TIMEOUT;
#else
const long timeout = msecs_to_jiffies(PM_TIMEOUT_MS);
#endif
+#endif
int err = 0;
- remaining = wait_event_timeout(
- kbdev->pm.backend.poweroff_wait,
- !is_poweroff_wait_in_progress(kbdev), timeout);
+#if KERNEL_VERSION(4, 13, 1) <= LINUX_VERSION_CODE
+ if (killable_wait)
+ remaining = wait_event_killable_timeout(kbdev->pm.backend.poweroff_wait,
+ !is_poweroff_wait_in_progress(kbdev),
+ timeout);
+#else
+ killable_wait = false;
+#endif
+
+ if (!killable_wait)
+ remaining = wait_event_timeout(kbdev->pm.backend.poweroff_wait,
+ !is_poweroff_wait_in_progress(kbdev), timeout);
if (!remaining) {
kbase_pm_timed_out(kbdev, "Wait for poweroff work timed out");
err = -ETIMEDOUT;
+ } else if (remaining < 0) {
+ WARN_ON_ONCE(!killable_wait);
+ dev_info(kbdev->dev, "Wait for poweroff work got interrupted");
+ err = (int)remaining;
}
return err;
}
+
+int kbase_pm_killable_wait_for_poweroff_work_complete(struct kbase_device *kbdev)
+{
+ return pm_wait_for_poweroff_work_complete(kbdev, true);
+}
+
+int kbase_pm_wait_for_poweroff_work_complete(struct kbase_device *kbdev)
+{
+ return pm_wait_for_poweroff_work_complete(kbdev, false);
+}
KBASE_EXPORT_TEST_API(kbase_pm_wait_for_poweroff_work_complete);
void kbase_pm_enable_interrupts(struct kbase_device *kbdev)
diff --git a/mali_kbase/backend/gpu/mali_kbase_pm_internal.h b/mali_kbase/backend/gpu/mali_kbase_pm_internal.h
index e999f9f..5a64fea 100644
--- a/mali_kbase/backend/gpu/mali_kbase_pm_internal.h
+++ b/mali_kbase/backend/gpu/mali_kbase_pm_internal.h
@@ -224,7 +224,7 @@ void kbase_pm_reset_done(struct kbase_device *kbdev);
* power off in progress and kbase_pm_context_active() was called instead of
* kbase_csf_scheduler_pm_active().
*
- * Return: 0 on success, error code on error
+ * Return: 0 on success, or -ETIMEDOUT code on timeout error.
*/
int kbase_pm_wait_for_desired_state(struct kbase_device *kbdev);
#else
@@ -247,12 +247,27 @@ int kbase_pm_wait_for_desired_state(struct kbase_device *kbdev);
* must ensure that this is not the case by, for example, calling
* kbase_pm_wait_for_poweroff_work_complete()
*
- * Return: 0 on success, error code on error
+ * Return: 0 on success, or -ETIMEDOUT error code on timeout error.
*/
int kbase_pm_wait_for_desired_state(struct kbase_device *kbdev);
#endif
/**
+ * kbase_pm_killable_wait_for_desired_state - Wait for the desired power state to be
+ * reached in a killable state.
+ * @kbdev: The kbase device structure for the device (must be a valid pointer)
+ *
+ * This function is same as kbase_pm_wait_for_desired_state(), expect that it would
+ * allow the SIGKILL signal to interrupt the wait.
+ * This function is supposed to be called from the code that is executed in ioctl or
+ * Userspace context, wherever it is safe to do so.
+ *
+ * Return: 0 on success, or -ETIMEDOUT code on timeout error or -ERESTARTSYS if the
+ * wait was interrupted.
+ */
+int kbase_pm_killable_wait_for_desired_state(struct kbase_device *kbdev);
+
+/**
* kbase_pm_wait_for_l2_powered - Wait for the L2 cache to be powered on
*
* @kbdev: The kbase device structure for the device (must be a valid pointer)
@@ -473,6 +488,22 @@ void kbase_pm_release_gpu_cycle_counter_nolock(struct kbase_device *kbdev);
int kbase_pm_wait_for_poweroff_work_complete(struct kbase_device *kbdev);
/**
+ * kbase_pm_killable_wait_for_poweroff_work_complete - Wait for the poweroff workqueue to
+ * complete in killable state.
+ *
+ * @kbdev: The kbase device structure for the device (must be a valid pointer)
+ *
+ * This function is same as kbase_pm_wait_for_poweroff_work_complete(), expect that
+ * it would allow the SIGKILL signal to interrupt the wait.
+ * This function is supposed to be called from the code that is executed in ioctl or
+ * Userspace context, wherever it is safe to do so.
+ *
+ * Return: 0 on success, or -ETIMEDOUT code on timeout error or -ERESTARTSYS if the
+ * wait was interrupted.
+ */
+int kbase_pm_killable_wait_for_poweroff_work_complete(struct kbase_device *kbdev);
+
+/**
* kbase_pm_wait_for_gpu_power_down - Wait for the GPU power down to complete
*
* @kbdev: The kbase device structure for the device (must be a valid pointer)
diff --git a/mali_kbase/csf/ipa_control/mali_kbase_csf_ipa_control.c b/mali_kbase/csf/ipa_control/mali_kbase_csf_ipa_control.c
index b50911d..bbf2e4e 100644
--- a/mali_kbase/csf/ipa_control/mali_kbase_csf_ipa_control.c
+++ b/mali_kbase/csf/ipa_control/mali_kbase_csf_ipa_control.c
@@ -64,12 +64,19 @@
* struct kbase_ipa_control_listener_data - Data for the GPU clock frequency
* listener
*
- * @listener: GPU clock frequency listener.
- * @kbdev: Pointer to kbase device.
+ * @listener: GPU clock frequency listener.
+ * @kbdev: Pointer to kbase device.
+ * @clk_chg_wq: Dedicated workqueue to process the work item corresponding to
+ * a clock rate notification.
+ * @clk_chg_work: Work item to process the clock rate change
+ * @rate: The latest notified rate change, in unit of Hz
*/
struct kbase_ipa_control_listener_data {
struct kbase_clk_rate_listener listener;
struct kbase_device *kbdev;
+ struct workqueue_struct *clk_chg_wq;
+ struct work_struct clk_chg_work;
+ atomic_t rate;
};
static u32 timer_value(u32 gpu_rate)
@@ -271,52 +278,61 @@ kbase_ipa_control_rate_change_notify(struct kbase_clk_rate_listener *listener,
u32 clk_index, u32 clk_rate_hz)
{
if ((clk_index == KBASE_CLOCK_DOMAIN_TOP) && (clk_rate_hz != 0)) {
- size_t i;
struct kbase_ipa_control_listener_data *listener_data =
- container_of(listener,
- struct kbase_ipa_control_listener_data,
- listener);
- struct kbase_device *kbdev = listener_data->kbdev;
- struct kbase_ipa_control *ipa_ctrl = &kbdev->csf.ipa_control;
-
- lockdep_assert_held(&kbdev->hwaccess_lock);
- if (!kbdev->pm.backend.gpu_ready) {
- dev_err(kbdev->dev,
- "%s: GPU frequency cannot change while GPU is off",
- __func__);
- return;
- }
+ container_of(listener, struct kbase_ipa_control_listener_data, listener);
- /* Interrupts are already disabled and interrupt state is also saved */
- spin_lock(&ipa_ctrl->lock);
+ /* Save the rate and delegate the job to a work item */
+ atomic_set(&listener_data->rate, clk_rate_hz);
+ queue_work(listener_data->clk_chg_wq, &listener_data->clk_chg_work);
+ }
+}
- for (i = 0; i < KBASE_IPA_CONTROL_MAX_SESSIONS; i++) {
- struct kbase_ipa_control_session *session = &ipa_ctrl->sessions[i];
+static void kbase_ipa_ctrl_rate_change_worker(struct work_struct *data)
+{
+ struct kbase_ipa_control_listener_data *listener_data =
+ container_of(data, struct kbase_ipa_control_listener_data, clk_chg_work);
+ struct kbase_device *kbdev = listener_data->kbdev;
+ struct kbase_ipa_control *ipa_ctrl = &kbdev->csf.ipa_control;
+ unsigned long flags;
+ u32 rate;
+ size_t i;
- if (session->active) {
- size_t j;
+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
- for (j = 0; j < session->num_prfcnts; j++) {
- struct kbase_ipa_control_prfcnt *prfcnt =
- &session->prfcnts[j];
+ if (!kbdev->pm.backend.gpu_ready) {
+ dev_err(kbdev->dev, "%s: GPU frequency cannot change while GPU is off", __func__);
+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
+ return;
+ }
- if (prfcnt->gpu_norm)
- calc_prfcnt_delta(kbdev, prfcnt, true);
- }
- }
- }
+ spin_lock(&ipa_ctrl->lock);
+ /* Picking up the latest notified rate */
+ rate = (u32)atomic_read(&listener_data->rate);
- ipa_ctrl->cur_gpu_rate = clk_rate_hz;
+ for (i = 0; i < KBASE_IPA_CONTROL_MAX_SESSIONS; i++) {
+ struct kbase_ipa_control_session *session = &ipa_ctrl->sessions[i];
- /* Update the timer for automatic sampling if active sessions
- * are present. Counters have already been manually sampled.
- */
- if (ipa_ctrl->num_active_sessions > 0) {
- kbase_reg_write(kbdev, IPA_CONTROL_REG(TIMER),
- timer_value(ipa_ctrl->cur_gpu_rate));
+ if (session->active) {
+ size_t j;
+
+ 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);
+ }
}
- spin_unlock(&ipa_ctrl->lock);
}
+
+ ipa_ctrl->cur_gpu_rate = rate;
+ /* Update the timer for automatic sampling if active sessions
+ * are present. Counters have already been manually sampled.
+ */
+ if (ipa_ctrl->num_active_sessions > 0)
+ kbase_reg_write(kbdev, IPA_CONTROL_REG(TIMER), timer_value(rate));
+
+ spin_unlock(&ipa_ctrl->lock);
+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
}
void kbase_ipa_control_init(struct kbase_device *kbdev)
@@ -344,13 +360,27 @@ void kbase_ipa_control_init(struct kbase_device *kbdev)
listener_data = kmalloc(sizeof(struct kbase_ipa_control_listener_data),
GFP_KERNEL);
if (listener_data) {
- spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
- listener_data->listener.notify =
- kbase_ipa_control_rate_change_notify;
- spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
- listener_data->kbdev = kbdev;
- ipa_ctrl->rtm_listener_data = listener_data;
- }
+ listener_data->clk_chg_wq =
+ alloc_workqueue("ipa_ctrl_wq", WQ_HIGHPRI | WQ_UNBOUND, 1);
+ if (listener_data->clk_chg_wq) {
+ INIT_WORK(&listener_data->clk_chg_work, kbase_ipa_ctrl_rate_change_worker);
+ listener_data->listener.notify = kbase_ipa_control_rate_change_notify;
+ listener_data->kbdev = kbdev;
+ ipa_ctrl->rtm_listener_data = listener_data;
+ /* Initialise to 0, which is out of normal notified rates */
+ atomic_set(&listener_data->rate, 0);
+ } else {
+ dev_warn(kbdev->dev,
+ "%s: failed to allocate workqueue, clock rate update disabled",
+ __func__);
+ kfree(listener_data);
+ listener_data = NULL;
+ }
+ } else
+ dev_warn(kbdev->dev,
+ "%s: failed to allocate memory, IPA control clock rate update disabled",
+ __func__);
+
spin_lock_irqsave(&clk_rtm->lock, flags);
if (clk_rtm->clks[KBASE_CLOCK_DOMAIN_TOP])
ipa_ctrl->cur_gpu_rate =
@@ -372,8 +402,10 @@ void kbase_ipa_control_term(struct kbase_device *kbdev)
WARN_ON(ipa_ctrl->num_active_sessions);
- if (listener_data)
+ if (listener_data) {
kbase_clk_rate_trace_manager_unsubscribe(clk_rtm, &listener_data->listener);
+ destroy_workqueue(listener_data->clk_chg_wq);
+ }
kfree(ipa_ctrl->rtm_listener_data);
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
@@ -999,14 +1031,11 @@ void kbase_ipa_control_rate_change_notify_test(struct kbase_device *kbdev,
u32 clk_index, u32 clk_rate_hz)
{
struct kbase_ipa_control *ipa_ctrl = &kbdev->csf.ipa_control;
- struct kbase_ipa_control_listener_data *listener_data =
- ipa_ctrl->rtm_listener_data;
- unsigned long flags;
+ struct kbase_ipa_control_listener_data *listener_data = ipa_ctrl->rtm_listener_data;
- spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
- kbase_ipa_control_rate_change_notify(&listener_data->listener,
- clk_index, clk_rate_hz);
- spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
+ kbase_ipa_control_rate_change_notify(&listener_data->listener, clk_index, clk_rate_hz);
+ /* Ensure the callback has taken effect before returning back to the test caller */
+ flush_work(&listener_data->clk_chg_work);
}
KBASE_EXPORT_TEST_API(kbase_ipa_control_rate_change_notify_test);
#endif
@@ -1059,4 +1088,3 @@ void kbase_ipa_control_protm_exited(struct kbase_device *kbdev)
}
}
}
-
diff --git a/mali_kbase/csf/mali_kbase_csf.c b/mali_kbase/csf/mali_kbase_csf.c
index 505ad35..12bb39b 100644
--- a/mali_kbase/csf/mali_kbase_csf.c
+++ b/mali_kbase/csf/mali_kbase_csf.c
@@ -3083,13 +3083,16 @@ void kbase_csf_interrupt(struct kbase_device *kbdev, u32 val)
do {
unsigned long flags;
u32 csg_interrupts = val & ~JOB_IRQ_GLOBAL_IF;
- struct irq_idle_and_protm_track track = { .protm_grp = NULL, .idle_seq = U32_MAX };
bool glb_idle_irq_received = false;
kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), val);
order_job_irq_clear_with_iface_mem_read();
if (csg_interrupts != 0) {
+ struct irq_idle_and_protm_track track = { .protm_grp = NULL,
+ .idle_seq = U32_MAX,
+ .idle_slot = S8_MAX };
+
kbase_csf_scheduler_spin_lock(kbdev, &flags);
/* Looping through and track the highest idle and protm groups */
while (csg_interrupts != 0) {
diff --git a/mali_kbase/csf/mali_kbase_csf.h b/mali_kbase/csf/mali_kbase_csf.h
index 408ad1f..e3f98e6 100644
--- a/mali_kbase/csf/mali_kbase_csf.h
+++ b/mali_kbase/csf/mali_kbase_csf.h
@@ -48,7 +48,7 @@
*/
#define KBASEP_TICK_PROTM_PEND_SCAN_SEQ_NR_INVALID (U32_MAX)
-#define FIRMWARE_IDLE_HYSTERESIS_TIME_USEC (10000) /* Default 10 milliseconds */
+#define FIRMWARE_IDLE_HYSTERESIS_TIME_NS (10 * 1000 * 1000) /* Default 10 milliseconds */
/* Idle hysteresis time can be scaled down when GPU sleep feature is used */
#define FIRMWARE_IDLE_HYSTERESIS_GPU_SLEEP_SCALER (5)
diff --git a/mali_kbase/csf/mali_kbase_csf_defs.h b/mali_kbase/csf/mali_kbase_csf_defs.h
index c15b4ad..af68d3f 100644
--- a/mali_kbase/csf/mali_kbase_csf_defs.h
+++ b/mali_kbase/csf/mali_kbase_csf_defs.h
@@ -1150,9 +1150,9 @@ struct kbase_csf_scheduler {
GLB_PROGRESS_TIMER_TIMEOUT_SCALE)
/*
- * Default GLB_PWROFF_TIMER_TIMEOUT value in unit of micro-seconds.
+ * Default GLB_PWROFF_TIMER_TIMEOUT value in unit of nanosecond.
*/
-#define DEFAULT_GLB_PWROFF_TIMEOUT_US (800)
+#define DEFAULT_GLB_PWROFF_TIMEOUT_NS (800 * 1000)
/*
* In typical operations, the management of the shader core power transitions
@@ -1574,22 +1574,28 @@ struct kbase_csf_user_reg {
* @fw_error_work: Work item for handling the firmware internal error
* fatal event.
* @ipa_control: IPA Control component manager.
- * @mcu_core_pwroff_dur_us: Sysfs attribute for the glb_pwroff timeout input
- * in unit of micro-seconds. The firmware does not use
+ * @mcu_core_pwroff_dur_ns: Sysfs attribute for the glb_pwroff timeout input
+ * in unit of nanoseconds. The firmware does not use
* it directly.
* @mcu_core_pwroff_dur_count: The counterpart of the glb_pwroff timeout input
* in interface required format, ready to be used
* directly in the firmware.
+ * @mcu_core_pwroff_dur_count_modifier: Update csffw_glb_req_cfg_pwroff_timer
+ * to make the shr(10) modifier conditional
+ * on new flag in GLB_PWROFF_TIMER_CONFIG
* @mcu_core_pwroff_reg_shadow: The actual value that has been programed into
* the glb_pwoff register. This is separated from
* the @p mcu_core_pwroff_dur_count as an update
* to the latter is asynchronous.
- * @gpu_idle_hysteresis_us: Sysfs attribute for the idle hysteresis time
- * window in unit of microseconds. The firmware does not
+ * @gpu_idle_hysteresis_ns: Sysfs attribute for the idle hysteresis time
+ * window in unit of nanoseconds. The firmware does not
* use it directly.
* @gpu_idle_dur_count: The counterpart of the hysteresis time window in
* interface required format, ready to be used
* directly in the firmware.
+ * @gpu_idle_dur_count_modifier: Update csffw_glb_req_idle_enable to make the shr(10)
+ * modifier conditional on the new flag
+ * in GLB_IDLE_TIMER_CONFIG.
* @fw_timeout_ms: Timeout value (in milliseconds) used when waiting
* for any request sent to the firmware.
* @hwcnt: Contain members required for handling the dump of
@@ -1637,11 +1643,13 @@ struct kbase_csf_device {
bool glb_init_request_pending;
struct work_struct fw_error_work;
struct kbase_ipa_control ipa_control;
- u32 mcu_core_pwroff_dur_us;
+ u32 mcu_core_pwroff_dur_ns;
u32 mcu_core_pwroff_dur_count;
+ u32 mcu_core_pwroff_dur_count_modifier;
u32 mcu_core_pwroff_reg_shadow;
- u32 gpu_idle_hysteresis_us;
+ u32 gpu_idle_hysteresis_ns;
u32 gpu_idle_dur_count;
+ u32 gpu_idle_dur_count_modifier;
unsigned int fw_timeout_ms;
struct kbase_csf_hwcnt hwcnt;
struct kbase_csf_mcu_fw fw;
@@ -1676,10 +1684,6 @@ struct kbase_csf_device {
* @bf_data: Data relating to Bus fault.
* @gf_data: Data relating to GPU fault.
* @current_setup: Stores the MMU configuration for this address space.
- * @is_unresponsive: Flag to indicate MMU is not responding.
- * Set if a MMU command isn't completed within
- * &kbase_device:mmu_or_gpu_cache_op_wait_time_ms.
- * Clear by kbase_ctx_sched_restore_all_as() after GPU reset completes.
*/
struct kbase_as {
int number;
@@ -1691,7 +1695,6 @@ struct kbase_as {
struct kbase_fault bf_data;
struct kbase_fault gf_data;
struct kbase_mmu_setup current_setup;
- bool is_unresponsive;
};
#endif /* _KBASE_CSF_DEFS_H_ */
diff --git a/mali_kbase/csf/mali_kbase_csf_firmware.c b/mali_kbase/csf/mali_kbase_csf_firmware.c
index 0a70356..357a154 100644
--- a/mali_kbase/csf/mali_kbase_csf_firmware.c
+++ b/mali_kbase/csf/mali_kbase_csf_firmware.c
@@ -116,7 +116,6 @@ MODULE_PARM_DESC(fw_debug,
#define BUILD_INFO_GIT_SHA_PATTERN "git_sha: "
#define CSF_MAX_FW_STOP_LOOPS (100000)
-#define CSF_MAX_GPU_INACTIVE_LOOPS (1000)
#define CSF_GLB_REQ_CFG_MASK \
(GLB_REQ_CFG_ALLOC_EN_MASK | GLB_REQ_CFG_PROGRESS_TIMER_MASK | \
@@ -233,13 +232,7 @@ void kbase_csf_firmware_disable_mcu(struct kbase_device *kbdev)
{
KBASE_TLSTREAM_TL_KBASE_CSFFW_FW_DISABLING(kbdev, kbase_backend_get_cycle_cnt(kbdev));
- if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_TITANHW_2922)) {
- kbase_reg_write(kbdev, GPU_CONTROL_REG(MCU_CONTROL), MCU_CNTRL_ENABLE);
- kbase_reg_write(kbdev, GPU_CONTROL_MCU_REG(GPU_CTRL_MCU_GPU_COMMAND),
- GPU_COMMAND_FAST_RESET);
- } else {
- kbase_reg_write(kbdev, GPU_CONTROL_REG(MCU_CONTROL), MCU_CNTRL_DISABLE);
- }
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(MCU_CONTROL), MCU_CNTRL_DISABLE);
}
static void wait_for_firmware_stop(struct kbase_device *kbdev)
@@ -252,26 +245,9 @@ static void wait_for_firmware_stop(struct kbase_device *kbdev)
KBASE_TLSTREAM_TL_KBASE_CSFFW_FW_OFF(kbdev, kbase_backend_get_cycle_cnt(kbdev));
}
-static void wait_for_gpu_inactive(struct kbase_device *kbdev)
-{
- u32 max_loops = CSF_MAX_GPU_INACTIVE_LOOPS;
-
- while (--max_loops &&
- (GPU_STATUS_GPU_ACTIVE & kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_STATUS))))
- ;
-
- if (!max_loops)
- dev_err(kbdev->dev, "Wait for GPU inactive failed post Fast Reset.");
-}
-
void kbase_csf_firmware_disable_mcu_wait(struct kbase_device *kbdev)
{
- if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_TITANHW_2922))
- wait_for_gpu_inactive(kbdev);
- else
- wait_for_firmware_stop(kbdev);
-
- KBASE_TLSTREAM_TL_KBASE_CSFFW_FW_OFF(kbdev, kbase_backend_get_cycle_cnt(kbdev));
+ wait_for_firmware_stop(kbdev);
}
static void stop_csf_firmware(struct kbase_device *kbdev)
@@ -279,7 +255,7 @@ static void stop_csf_firmware(struct kbase_device *kbdev)
/* Stop the MCU firmware */
kbase_csf_firmware_disable_mcu(kbdev);
- kbase_csf_firmware_disable_mcu_wait(kbdev);
+ wait_for_firmware_stop(kbdev);
}
static void wait_for_firmware_boot(struct kbase_device *kbdev)
@@ -1733,6 +1709,11 @@ static void enable_shader_poweroff_timer(struct kbase_device *const kbdev,
kbase_csf_firmware_global_input(global_iface, GLB_PWROFF_TIMER,
pwroff_reg);
+
+ kbase_csf_firmware_global_input_mask(global_iface, GLB_PWROFF_TIMER_CONFIG,
+ kbdev->csf.mcu_core_pwroff_dur_count_modifier,
+ GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_MASK);
+
set_global_request(global_iface, GLB_REQ_CFG_PWROFF_TIMER_MASK);
/* Save the programed reg value in its shadow field */
@@ -1759,6 +1740,11 @@ static void enable_gpu_idle_timer(struct kbase_device *const kbdev)
kbase_csf_firmware_global_input(global_iface, GLB_IDLE_TIMER,
kbdev->csf.gpu_idle_dur_count);
+
+ kbase_csf_firmware_global_input_mask(global_iface, GLB_IDLE_TIMER_CONFIG,
+ kbdev->csf.gpu_idle_dur_count_modifier,
+ GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_MASK);
+
kbase_csf_firmware_global_input_mask(global_iface, GLB_REQ, GLB_REQ_REQ_IDLE_ENABLE,
GLB_REQ_IDLE_ENABLE_MASK);
dev_dbg(kbdev->dev, "Enabling GPU idle timer with count-value: 0x%.8x",
@@ -2045,12 +2031,12 @@ void kbase_csf_firmware_reload_completed(struct kbase_device *kbdev)
kbase_pm_update_state(kbdev);
}
-static u32 convert_dur_to_idle_count(struct kbase_device *kbdev, const u32 dur_us)
+static u32 convert_dur_to_idle_count(struct kbase_device *kbdev, const u32 dur_ns, u32 *modifier)
{
#define HYSTERESIS_VAL_UNIT_SHIFT (10)
/* Get the cntfreq_el0 value, which drives the SYSTEM_TIMESTAMP */
u64 freq = arch_timer_get_cntfrq();
- u64 dur_val = dur_us;
+ u64 dur_val = dur_ns;
u32 cnt_val_u32, reg_val_u32;
bool src_system_timestamp = freq > 0;
@@ -2068,9 +2054,15 @@ static u32 convert_dur_to_idle_count(struct kbase_device *kbdev, const u32 dur_u
"Can't get the timestamp frequency, use cycle counter format with firmware idle hysteresis!");
}
- /* Formula for dur_val = ((dur_us/1000000) * freq_HZ) >> 10) */
- dur_val = (dur_val * freq) >> HYSTERESIS_VAL_UNIT_SHIFT;
- dur_val = div_u64(dur_val, 1000000);
+ /* Formula for dur_val = (dur/1e9) * freq_HZ) */
+ dur_val = dur_val * freq;
+ dur_val = div_u64(dur_val, NSEC_PER_SEC);
+ if (dur_val < S32_MAX) {
+ *modifier = 1;
+ } else {
+ dur_val = dur_val >> HYSTERESIS_VAL_UNIT_SHIFT;
+ *modifier = 0;
+ }
/* Interface limits the value field to S32_MAX */
cnt_val_u32 = (dur_val > S32_MAX) ? S32_MAX : (u32)dur_val;
@@ -2090,16 +2082,18 @@ u32 kbase_csf_firmware_get_gpu_idle_hysteresis_time(struct kbase_device *kbdev)
u32 dur;
kbase_csf_scheduler_spin_lock(kbdev, &flags);
- dur = kbdev->csf.gpu_idle_hysteresis_us;
+ dur = kbdev->csf.gpu_idle_hysteresis_ns;
kbase_csf_scheduler_spin_unlock(kbdev, flags);
return dur;
}
-u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev, u32 dur)
+u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev, u32 dur_ns)
{
unsigned long flags;
- const u32 hysteresis_val = convert_dur_to_idle_count(kbdev, dur);
+ u32 modifier = 0;
+
+ const u32 hysteresis_val = convert_dur_to_idle_count(kbdev, dur_ns, &modifier);
/* The 'fw_load_lock' is taken to synchronize against the deferred
* loading of FW, where the idle timer will be enabled.
@@ -2107,8 +2101,9 @@ u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev,
mutex_lock(&kbdev->fw_load_lock);
if (unlikely(!kbdev->csf.firmware_inited)) {
kbase_csf_scheduler_spin_lock(kbdev, &flags);
- kbdev->csf.gpu_idle_hysteresis_us = dur;
+ kbdev->csf.gpu_idle_hysteresis_ns = dur_ns;
kbdev->csf.gpu_idle_dur_count = hysteresis_val;
+ kbdev->csf.gpu_idle_dur_count_modifier = modifier;
kbase_csf_scheduler_spin_unlock(kbdev, flags);
mutex_unlock(&kbdev->fw_load_lock);
goto end;
@@ -2122,7 +2117,7 @@ u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev,
}
kbase_csf_scheduler_pm_active(kbdev);
- if (kbase_csf_scheduler_wait_mcu_active(kbdev)) {
+ if (kbase_csf_scheduler_killable_wait_mcu_active(kbdev)) {
dev_err(kbdev->dev,
"Unable to activate the MCU, the idle hysteresis value shall remain unchanged");
kbase_csf_scheduler_pm_idle(kbdev);
@@ -2146,8 +2141,9 @@ u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev,
wait_for_global_request(kbdev, GLB_REQ_IDLE_DISABLE_MASK);
kbase_csf_scheduler_spin_lock(kbdev, &flags);
- kbdev->csf.gpu_idle_hysteresis_us = dur;
+ kbdev->csf.gpu_idle_hysteresis_ns = dur_ns;
kbdev->csf.gpu_idle_dur_count = hysteresis_val;
+ kbdev->csf.gpu_idle_dur_count_modifier = modifier;
kbase_csf_firmware_enable_gpu_idle_timer(kbdev);
kbase_csf_scheduler_spin_unlock(kbdev, flags);
wait_for_global_request(kbdev, GLB_REQ_IDLE_ENABLE_MASK);
@@ -2162,11 +2158,12 @@ end:
return hysteresis_val;
}
-static u32 convert_dur_to_core_pwroff_count(struct kbase_device *kbdev, const u32 dur_us)
+static u32 convert_dur_to_core_pwroff_count(struct kbase_device *kbdev, const u32 dur_ns,
+ u32 *modifier)
{
/* Get the cntfreq_el0 value, which drives the SYSTEM_TIMESTAMP */
u64 freq = arch_timer_get_cntfrq();
- u64 dur_val = dur_us;
+ u64 dur_val = dur_ns;
u32 cnt_val_u32, reg_val_u32;
bool src_system_timestamp = freq > 0;
@@ -2187,9 +2184,15 @@ static u32 convert_dur_to_core_pwroff_count(struct kbase_device *kbdev, const u3
"Can't get the timestamp frequency, use cycle counter with MCU shader Core Poweroff timer!");
}
- /* Formula for dur_val = ((dur_us/1e6) * freq_HZ) >> 10) */
- dur_val = (dur_val * freq) >> HYSTERESIS_VAL_UNIT_SHIFT;
- dur_val = div_u64(dur_val, 1000000);
+ /* Formula for dur_val = (dur/1e9) * freq_HZ) */
+ dur_val = dur_val * freq;
+ dur_val = div_u64(dur_val, NSEC_PER_SEC);
+ if (dur_val < S32_MAX) {
+ *modifier = 1;
+ } else {
+ dur_val = dur_val >> HYSTERESIS_VAL_UNIT_SHIFT;
+ *modifier = 0;
+ }
if (dur_val == 0 && !always_on) {
/* Lower Bound - as 0 disables timeout and host controls shader-core power management. */
@@ -2217,20 +2220,23 @@ u32 kbase_csf_firmware_get_mcu_core_pwroff_time(struct kbase_device *kbdev)
unsigned long flags;
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
- pwroff = kbdev->csf.mcu_core_pwroff_dur_us;
+ pwroff = kbdev->csf.mcu_core_pwroff_dur_ns;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
return pwroff;
}
-u32 kbase_csf_firmware_set_mcu_core_pwroff_time(struct kbase_device *kbdev, u32 dur)
+u32 kbase_csf_firmware_set_mcu_core_pwroff_time(struct kbase_device *kbdev, u32 dur_ns)
{
unsigned long flags;
- const u32 pwroff = convert_dur_to_core_pwroff_count(kbdev, dur);
+ u32 modifier = 0;
+
+ const u32 pwroff = convert_dur_to_core_pwroff_count(kbdev, dur_ns, &modifier);
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
- kbdev->csf.mcu_core_pwroff_dur_us = dur;
+ kbdev->csf.mcu_core_pwroff_dur_ns = dur_ns;
kbdev->csf.mcu_core_pwroff_dur_count = pwroff;
+ kbdev->csf.mcu_core_pwroff_dur_count_modifier = modifier;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
dev_dbg(kbdev->dev, "MCU shader Core Poweroff input update: 0x%.8x", pwroff);
@@ -2240,7 +2246,7 @@ u32 kbase_csf_firmware_set_mcu_core_pwroff_time(struct kbase_device *kbdev, u32
u32 kbase_csf_firmware_reset_mcu_core_pwroff_time(struct kbase_device *kbdev)
{
- return kbase_csf_firmware_set_mcu_core_pwroff_time(kbdev, DEFAULT_GLB_PWROFF_TIMEOUT_US);
+ return kbase_csf_firmware_set_mcu_core_pwroff_time(kbdev, DEFAULT_GLB_PWROFF_TIMEOUT_NS);
}
/**
@@ -2345,14 +2351,18 @@ void kbase_csf_firmware_early_term(struct kbase_device *kbdev)
int kbase_csf_firmware_late_init(struct kbase_device *kbdev)
{
- kbdev->csf.gpu_idle_hysteresis_us = FIRMWARE_IDLE_HYSTERESIS_TIME_USEC;
+ u32 modifier = 0;
+
+ kbdev->csf.gpu_idle_hysteresis_ns = FIRMWARE_IDLE_HYSTERESIS_TIME_NS;
+
#ifdef KBASE_PM_RUNTIME
if (kbase_pm_gpu_sleep_allowed(kbdev))
- kbdev->csf.gpu_idle_hysteresis_us /= FIRMWARE_IDLE_HYSTERESIS_GPU_SLEEP_SCALER;
+ kbdev->csf.gpu_idle_hysteresis_ns /= FIRMWARE_IDLE_HYSTERESIS_GPU_SLEEP_SCALER;
#endif
- WARN_ON(!kbdev->csf.gpu_idle_hysteresis_us);
+ WARN_ON(!kbdev->csf.gpu_idle_hysteresis_ns);
kbdev->csf.gpu_idle_dur_count =
- convert_dur_to_idle_count(kbdev, kbdev->csf.gpu_idle_hysteresis_us);
+ convert_dur_to_idle_count(kbdev, kbdev->csf.gpu_idle_hysteresis_ns, &modifier);
+ kbdev->csf.gpu_idle_dur_count_modifier = modifier;
return 0;
}
@@ -3002,7 +3012,9 @@ int kbase_csf_trigger_firmware_config_update(struct kbase_device *kbdev)
/* Ensure GPU is powered-up until we complete config update.*/
kbase_csf_scheduler_pm_active(kbdev);
- kbase_csf_scheduler_wait_mcu_active(kbdev);
+ err = kbase_csf_scheduler_killable_wait_mcu_active(kbdev);
+ if (err)
+ goto exit;
/* The 'reg_lock' is also taken and is held till the update is
* complete, to ensure the config update gets serialized.
@@ -3019,6 +3031,7 @@ int kbase_csf_trigger_firmware_config_update(struct kbase_device *kbdev)
GLB_REQ_FIRMWARE_CONFIG_UPDATE_MASK);
mutex_unlock(&kbdev->csf.reg_lock);
+exit:
kbase_csf_scheduler_pm_idle(kbdev);
return err;
}
diff --git a/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c b/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c
index 6aa4fad..fff95b7 100644
--- a/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c
+++ b/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c
@@ -506,7 +506,7 @@ static int fw_core_dump_create(struct kbase_device *kbdev)
/* Ensure MCU is active before requesting the core dump. */
kbase_csf_scheduler_pm_active(kbdev);
- err = kbase_csf_scheduler_wait_mcu_active(kbdev);
+ err = kbase_csf_scheduler_killable_wait_mcu_active(kbdev);
if (!err)
err = kbase_csf_firmware_req_core_dump(kbdev);
diff --git a/mali_kbase/csf/mali_kbase_csf_firmware_log.c b/mali_kbase/csf/mali_kbase_csf_firmware_log.c
index f43e262..89df839 100644
--- a/mali_kbase/csf/mali_kbase_csf_firmware_log.c
+++ b/mali_kbase/csf/mali_kbase_csf_firmware_log.c
@@ -514,7 +514,7 @@ int kbase_csf_firmware_log_toggle_logging_calls(struct kbase_device *kbdev, u32
/* Wait for the MCU to get disabled */
dev_info(kbdev->dev, "Wait for the MCU to get disabled");
- ret = kbase_pm_wait_for_desired_state(kbdev);
+ ret = kbase_pm_killable_wait_for_desired_state(kbdev);
if (ret) {
dev_err(kbdev->dev,
"wait for PM state failed when toggling FW logging calls");
diff --git a/mali_kbase/csf/mali_kbase_csf_firmware_no_mali.c b/mali_kbase/csf/mali_kbase_csf_firmware_no_mali.c
index 6f565d3..f4ef68e 100644
--- a/mali_kbase/csf/mali_kbase_csf_firmware_no_mali.c
+++ b/mali_kbase/csf/mali_kbase_csf_firmware_no_mali.c
@@ -933,7 +933,7 @@ void kbase_csf_firmware_reload_completed(struct kbase_device *kbdev)
kbase_pm_update_state(kbdev);
}
-static u32 convert_dur_to_idle_count(struct kbase_device *kbdev, const u32 dur_ms)
+static u32 convert_dur_to_idle_count(struct kbase_device *kbdev, const u32 dur_ms, u32 *modifier)
{
#define HYSTERESIS_VAL_UNIT_SHIFT (10)
/* Get the cntfreq_el0 value, which drives the SYSTEM_TIMESTAMP */
@@ -960,6 +960,8 @@ static u32 convert_dur_to_idle_count(struct kbase_device *kbdev, const u32 dur_m
dur_val = (dur_val * freq) >> HYSTERESIS_VAL_UNIT_SHIFT;
dur_val = div_u64(dur_val, 1000);
+ *modifier = 0;
+
/* Interface limits the value field to S32_MAX */
cnt_val_u32 = (dur_val > S32_MAX) ? S32_MAX : (u32)dur_val;
@@ -981,7 +983,7 @@ u32 kbase_csf_firmware_get_gpu_idle_hysteresis_time(struct kbase_device *kbdev)
u32 dur;
kbase_csf_scheduler_spin_lock(kbdev, &flags);
- dur = kbdev->csf.gpu_idle_hysteresis_us;
+ dur = kbdev->csf.gpu_idle_hysteresis_ns;
kbase_csf_scheduler_spin_unlock(kbdev, flags);
return dur;
@@ -990,7 +992,9 @@ u32 kbase_csf_firmware_get_gpu_idle_hysteresis_time(struct kbase_device *kbdev)
u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev, u32 dur)
{
unsigned long flags;
- const u32 hysteresis_val = convert_dur_to_idle_count(kbdev, dur);
+ u32 modifier = 0;
+
+ const u32 hysteresis_val = convert_dur_to_idle_count(kbdev, dur, &modifier);
/* The 'fw_load_lock' is taken to synchronize against the deferred
* loading of FW, where the idle timer will be enabled.
@@ -998,8 +1002,9 @@ u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev,
mutex_lock(&kbdev->fw_load_lock);
if (unlikely(!kbdev->csf.firmware_inited)) {
kbase_csf_scheduler_spin_lock(kbdev, &flags);
- kbdev->csf.gpu_idle_hysteresis_us = dur;
+ kbdev->csf.gpu_idle_hysteresis_ns = dur;
kbdev->csf.gpu_idle_dur_count = hysteresis_val;
+ kbdev->csf.gpu_idle_dur_count_modifier = modifier;
kbase_csf_scheduler_spin_unlock(kbdev, flags);
mutex_unlock(&kbdev->fw_load_lock);
goto end;
@@ -1013,7 +1018,7 @@ u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev,
}
kbase_csf_scheduler_pm_active(kbdev);
- if (kbase_csf_scheduler_wait_mcu_active(kbdev)) {
+ if (kbase_csf_scheduler_killable_wait_mcu_active(kbdev)) {
dev_err(kbdev->dev,
"Unable to activate the MCU, the idle hysteresis value shall remain unchanged");
kbase_csf_scheduler_pm_idle(kbdev);
@@ -1037,8 +1042,9 @@ u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev,
wait_for_global_request(kbdev, GLB_REQ_IDLE_DISABLE_MASK);
kbase_csf_scheduler_spin_lock(kbdev, &flags);
- kbdev->csf.gpu_idle_hysteresis_us = dur;
+ kbdev->csf.gpu_idle_hysteresis_ns = dur;
kbdev->csf.gpu_idle_dur_count = hysteresis_val;
+ kbdev->csf.gpu_idle_dur_count_modifier = modifier;
kbase_csf_firmware_enable_gpu_idle_timer(kbdev);
kbase_csf_scheduler_spin_unlock(kbdev, flags);
wait_for_global_request(kbdev, GLB_REQ_IDLE_ENABLE_MASK);
@@ -1053,7 +1059,8 @@ end:
return hysteresis_val;
}
-static u32 convert_dur_to_core_pwroff_count(struct kbase_device *kbdev, const u32 dur_us)
+static u32 convert_dur_to_core_pwroff_count(struct kbase_device *kbdev, const u32 dur_us,
+ u32 *modifier)
{
/* Get the cntfreq_el0 value, which drives the SYSTEM_TIMESTAMP */
u64 freq = arch_timer_get_cntfrq();
@@ -1079,6 +1086,8 @@ static u32 convert_dur_to_core_pwroff_count(struct kbase_device *kbdev, const u3
dur_val = (dur_val * freq) >> HYSTERESIS_VAL_UNIT_SHIFT;
dur_val = div_u64(dur_val, 1000000);
+ *modifier = 0;
+
/* Interface limits the value field to S32_MAX */
cnt_val_u32 = (dur_val > S32_MAX) ? S32_MAX : (u32)dur_val;
@@ -1100,7 +1109,7 @@ u32 kbase_csf_firmware_get_mcu_core_pwroff_time(struct kbase_device *kbdev)
unsigned long flags;
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
- pwroff = kbdev->csf.mcu_core_pwroff_dur_us;
+ pwroff = kbdev->csf.mcu_core_pwroff_dur_ns;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
return pwroff;
@@ -1109,11 +1118,14 @@ u32 kbase_csf_firmware_get_mcu_core_pwroff_time(struct kbase_device *kbdev)
u32 kbase_csf_firmware_set_mcu_core_pwroff_time(struct kbase_device *kbdev, u32 dur)
{
unsigned long flags;
- const u32 pwroff = convert_dur_to_core_pwroff_count(kbdev, dur);
+ u32 modifier = 0;
+
+ const u32 pwroff = convert_dur_to_core_pwroff_count(kbdev, dur, &modifier);
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
- kbdev->csf.mcu_core_pwroff_dur_us = dur;
+ kbdev->csf.mcu_core_pwroff_dur_ns = dur;
kbdev->csf.mcu_core_pwroff_dur_count = pwroff;
+ kbdev->csf.mcu_core_pwroff_dur_count_modifier = modifier;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
dev_dbg(kbdev->dev, "MCU shader Core Poweroff input update: 0x%.8x", pwroff);
@@ -1123,7 +1135,7 @@ u32 kbase_csf_firmware_set_mcu_core_pwroff_time(struct kbase_device *kbdev, u32
u32 kbase_csf_firmware_reset_mcu_core_pwroff_time(struct kbase_device *kbdev)
{
- return kbase_csf_firmware_set_mcu_core_pwroff_time(kbdev, DEFAULT_GLB_PWROFF_TIMEOUT_US);
+ return kbase_csf_firmware_set_mcu_core_pwroff_time(kbdev, DEFAULT_GLB_PWROFF_TIMEOUT_NS);
}
int kbase_csf_firmware_early_init(struct kbase_device *kbdev)
@@ -1157,14 +1169,17 @@ void kbase_csf_firmware_early_term(struct kbase_device *kbdev)
int kbase_csf_firmware_late_init(struct kbase_device *kbdev)
{
- kbdev->csf.gpu_idle_hysteresis_us = FIRMWARE_IDLE_HYSTERESIS_TIME_USEC;
+ u32 modifier = 0;
+
+ kbdev->csf.gpu_idle_hysteresis_ns = FIRMWARE_IDLE_HYSTERESIS_TIME_NS;
#ifdef KBASE_PM_RUNTIME
if (kbase_pm_gpu_sleep_allowed(kbdev))
- kbdev->csf.gpu_idle_hysteresis_us /= FIRMWARE_IDLE_HYSTERESIS_GPU_SLEEP_SCALER;
+ kbdev->csf.gpu_idle_hysteresis_ns /= FIRMWARE_IDLE_HYSTERESIS_GPU_SLEEP_SCALER;
#endif
- WARN_ON(!kbdev->csf.gpu_idle_hysteresis_us);
+ WARN_ON(!kbdev->csf.gpu_idle_hysteresis_ns);
kbdev->csf.gpu_idle_dur_count =
- convert_dur_to_idle_count(kbdev, kbdev->csf.gpu_idle_hysteresis_us);
+ convert_dur_to_idle_count(kbdev, kbdev->csf.gpu_idle_hysteresis_ns, &modifier);
+ kbdev->csf.gpu_idle_dur_count_modifier = modifier;
return 0;
}
diff --git a/mali_kbase/csf/mali_kbase_csf_registers.h b/mali_kbase/csf/mali_kbase_csf_registers.h
index c7e1fd0..b5ca885 100644
--- a/mali_kbase/csf/mali_kbase_csf_registers.h
+++ b/mali_kbase/csf/mali_kbase_csf_registers.h
@@ -1492,6 +1492,20 @@
#define GLB_PWROFF_TIMER_TIMER_SOURCE_GPU_COUNTER 0x1
/* End of GLB_PWROFF_TIMER_TIMER_SOURCE values */
+/* GLB_PWROFF_TIMER_CONFIG register */
+#ifndef GLB_PWROFF_TIMER_CONFIG
+#define GLB_PWROFF_TIMER_CONFIG 0x0088 /* () Configuration fields for GLB_PWROFF_TIMER */
+#define GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_SHIFT 0
+#define GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_MASK (0x1 << GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_SHIFT)
+#define GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_GET(reg_val) \
+ (((reg_val)&GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_MASK) >> \
+ GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_SHIFT)
+#define GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_SET(reg_val, value) \
+ (((reg_val) & ~GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_MASK) | \
+ (((value) << GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_SHIFT) & \
+ GLB_PWROFF_TIMER_CONFIG_NO_MODIFIER_MASK))
+#endif /* End of GLB_PWROFF_TIMER_CONFIG values */
+
/* GLB_ALLOC_EN register */
#define GLB_ALLOC_EN_MASK_SHIFT 0
#define GLB_ALLOC_EN_MASK_MASK (GPU_ULL(0xFFFFFFFFFFFFFFFF) << GLB_ALLOC_EN_MASK_SHIFT)
@@ -1557,6 +1571,20 @@
#define GLB_IDLE_TIMER_TIMER_SOURCE_GPU_COUNTER 0x1
/* End of GLB_IDLE_TIMER_TIMER_SOURCE values */
+/* GLB_IDLE_TIMER_CONFIG values */
+#ifndef GLB_IDLE_TIMER_CONFIG
+#define GLB_IDLE_TIMER_CONFIG 0x0084 /* () Configuration fields for GLB_IDLE_TIMER */
+#define GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_SHIFT 0
+#define GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_MASK (0x1 << GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_SHIFT)
+#define GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_GET(reg_val) \
+ (((reg_val)&GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_MASK) >> \
+ GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_SHIFT)
+#define GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_SET(reg_val, value) \
+ (((reg_val) & ~GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_MASK) | \
+ (((value) << GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_SHIFT) & \
+ GLB_IDLE_TIMER_CONFIG_NO_MODIFIER_MASK))
+#endif /* End of GLB_IDLE_TIMER_CONFIG values */
+
/* GLB_INSTR_FEATURES register */
#define GLB_INSTR_FEATURES_OFFSET_UPDATE_RATE_SHIFT (0)
#define GLB_INSTR_FEATURES_OFFSET_UPDATE_RATE_MASK ((u32)0xF << GLB_INSTR_FEATURES_OFFSET_UPDATE_RATE_SHIFT)
diff --git a/mali_kbase/csf/mali_kbase_csf_reset_gpu.c b/mali_kbase/csf/mali_kbase_csf_reset_gpu.c
index df2e32d..952209f 100644
--- a/mali_kbase/csf/mali_kbase_csf_reset_gpu.c
+++ b/mali_kbase/csf/mali_kbase_csf_reset_gpu.c
@@ -185,7 +185,7 @@ static void kbase_csf_reset_begin_hw_access_sync(
*/
spin_lock_irqsave(&kbdev->hwaccess_lock, hwaccess_lock_flags);
kbase_csf_scheduler_spin_lock(kbdev, &scheduler_spin_lock_flags);
- atomic_set(&kbdev->csf.reset.state, KBASE_RESET_GPU_HAPPENING);
+ atomic_set(&kbdev->csf.reset.state, KBASE_CSF_RESET_GPU_HAPPENING);
kbase_csf_scheduler_spin_unlock(kbdev, scheduler_spin_lock_flags);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, hwaccess_lock_flags);
}
diff --git a/mali_kbase/csf/mali_kbase_csf_scheduler.c b/mali_kbase/csf/mali_kbase_csf_scheduler.c
index 3940c32..eea0d19 100644
--- a/mali_kbase/csf/mali_kbase_csf_scheduler.c
+++ b/mali_kbase/csf/mali_kbase_csf_scheduler.c
@@ -251,7 +251,8 @@ static bool gpu_metrics_read_event(struct kbase_device *kbdev, struct kbase_cont
*/
static void emit_gpu_metrics_to_frontend(struct kbase_device *kbdev)
{
- const u64 ts_before_drain = ktime_get_raw_ns();
+ u64 system_time = 0;
+ u64 ts_before_drain;
u64 ts = 0;
lockdep_assert_held(&kbdev->csf.scheduler.lock);
@@ -260,6 +261,12 @@ static void emit_gpu_metrics_to_frontend(struct kbase_device *kbdev)
return;
#endif
+ if (WARN_ON_ONCE(kbdev->csf.scheduler.state == SCHED_SUSPENDED))
+ return;
+
+ kbase_backend_get_gpu_time_norequest(kbdev, NULL, &system_time, NULL);
+ ts_before_drain = kbase_backend_time_convert_gpu_to_cpu(kbdev, system_time);
+
while (!kbase_csf_firmware_trace_buffer_is_empty(kbdev->csf.scheduler.gpu_metrics_tb)) {
struct kbase_context *kctx;
bool prev_act;
@@ -719,7 +726,7 @@ void kbase_csf_scheduler_process_gpu_idle_event(struct kbase_device *kbdev)
* updated whilst gpu_idle_worker() is executing.
*/
scheduler->fast_gpu_idle_handling =
- (kbdev->csf.gpu_idle_hysteresis_us == 0) ||
+ (kbdev->csf.gpu_idle_hysteresis_ns == 0) ||
!kbase_csf_scheduler_all_csgs_idle(kbdev);
/* The GPU idle worker relies on update_on_slot_queues_offsets() to have
@@ -824,6 +831,14 @@ static bool queue_group_scheduled_locked(struct kbase_queue_group *group)
return queue_group_scheduled(group);
}
+static void update_idle_protm_group_state_to_runnable(struct kbase_queue_group *group)
+{
+ lockdep_assert_held(&group->kctx->kbdev->csf.scheduler.lock);
+
+ group->run_state = KBASE_CSF_GROUP_RUNNABLE;
+ KBASE_KTRACE_ADD_CSF_GRP(group->kctx->kbdev, CSF_GROUP_RUNNABLE, group, group->run_state);
+}
+
/**
* scheduler_protm_wait_quit() - Wait for GPU to exit protected mode.
*
@@ -4101,16 +4116,13 @@ static void protm_enter_set_next_pending_seq(struct kbase_device *const kbdev)
struct kbase_csf_scheduler *scheduler = &kbdev->csf.scheduler;
u32 num_groups = kbdev->csf.global_iface.group_num;
u32 num_csis = kbdev->csf.global_iface.groups[0].stream_num;
- DECLARE_BITMAP(active_csgs, MAX_SUPPORTED_CSGS) = { 0 };
u32 i;
kbase_csf_scheduler_spin_lock_assert_held(kbdev);
- bitmap_xor(active_csgs, scheduler->csg_slots_idle_mask, scheduler->csg_inuse_bitmap,
- num_groups);
/* Reset the tick's pending protm seq number to invalid initially */
scheduler->tick_protm_pending_seq = KBASEP_TICK_PROTM_PEND_SCAN_SEQ_NR_INVALID;
- for_each_set_bit(i, active_csgs, num_groups) {
+ for_each_set_bit(i, scheduler->csg_inuse_bitmap, num_groups) {
struct kbase_queue_group *group = scheduler->csg_slots[i].resident_group;
/* Set to the next pending protm group's scan_seq_number */
@@ -4389,7 +4401,9 @@ static void scheduler_ctx_scan_groups(struct kbase_device *kbdev, struct kbase_c
scheduler->tick_protm_pending_seq = group->scan_seq_num;
}
- if (queue_group_idle_locked(group)) {
+ if (protm_req && on_slot_group_idle_locked(group))
+ update_idle_protm_group_state_to_runnable(group);
+ else if (queue_group_idle_locked(group)) {
if (can_schedule_idle_group(group))
list_add_tail(&group->link_to_schedule,
&scheduler->idle_groups_to_schedule);
@@ -6249,9 +6263,15 @@ static struct kbase_queue_group *scheduler_get_protm_enter_async_group(
spin_lock_irqsave(&scheduler->interrupt_lock, flags);
- if (kbase_csf_scheduler_protected_mode_in_use(kbdev) ||
- bitmap_empty(pending, ginfo->stream_num))
+ if (bitmap_empty(pending, ginfo->stream_num)) {
+ dev_dbg(kbdev->dev,
+ "Pmode requested for group %d of ctx %d_%d with no pending queues",
+ input_grp->handle, input_grp->kctx->tgid, input_grp->kctx->id);
input_grp = NULL;
+ } else if (kbase_csf_scheduler_protected_mode_in_use(kbdev)) {
+ kbase_csf_scheduler_invoke_tock(kbdev);
+ input_grp = NULL;
+ }
spin_unlock_irqrestore(&scheduler->interrupt_lock, flags);
} else {
@@ -6278,11 +6298,8 @@ void kbase_csf_scheduler_group_protm_enter(struct kbase_queue_group *group)
mutex_lock(&scheduler->lock);
- if (group->run_state == KBASE_CSF_GROUP_IDLE) {
- group->run_state = KBASE_CSF_GROUP_RUNNABLE;
- KBASE_KTRACE_ADD_CSF_GRP(kbdev, CSF_GROUP_RUNNABLE, group,
- group->run_state);
- }
+ if (on_slot_group_idle_locked(group))
+ update_idle_protm_group_state_to_runnable(group);
/* Check if the group is now eligible for execution in protected mode. */
if (scheduler_get_protm_enter_async_group(kbdev, group))
scheduler_group_check_protm_enter(kbdev, group);
@@ -7023,7 +7040,7 @@ void kbase_csf_scheduler_pm_idle(struct kbase_device *kbdev)
}
KBASE_EXPORT_TEST_API(kbase_csf_scheduler_pm_idle);
-int kbase_csf_scheduler_wait_mcu_active(struct kbase_device *kbdev)
+static int scheduler_wait_mcu_active(struct kbase_device *kbdev, bool killable_wait)
{
struct kbase_csf_scheduler *const scheduler = &kbdev->csf.scheduler;
unsigned long flags;
@@ -7036,11 +7053,17 @@ int kbase_csf_scheduler_wait_mcu_active(struct kbase_device *kbdev)
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
kbase_pm_unlock(kbdev);
- err = kbase_pm_wait_for_poweroff_work_complete(kbdev);
+ if (killable_wait)
+ err = kbase_pm_killable_wait_for_poweroff_work_complete(kbdev);
+ else
+ err = kbase_pm_wait_for_poweroff_work_complete(kbdev);
if (err)
return err;
- err = kbase_pm_wait_for_desired_state(kbdev);
+ if (killable_wait)
+ err = kbase_pm_killable_wait_for_desired_state(kbdev);
+ else
+ err = kbase_pm_wait_for_desired_state(kbdev);
if (!err) {
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
WARN_ON(kbdev->pm.backend.mcu_state != KBASE_MCU_ON);
@@ -7049,6 +7072,17 @@ int kbase_csf_scheduler_wait_mcu_active(struct kbase_device *kbdev)
return err;
}
+
+int kbase_csf_scheduler_killable_wait_mcu_active(struct kbase_device *kbdev)
+{
+ return scheduler_wait_mcu_active(kbdev, true);
+}
+
+int kbase_csf_scheduler_wait_mcu_active(struct kbase_device *kbdev)
+{
+ return scheduler_wait_mcu_active(kbdev, false);
+}
+
KBASE_EXPORT_TEST_API(kbase_csf_scheduler_wait_mcu_active);
#ifdef KBASE_PM_RUNTIME
diff --git a/mali_kbase/csf/mali_kbase_csf_scheduler.h b/mali_kbase/csf/mali_kbase_csf_scheduler.h
index f7756c1..0ebea88 100644
--- a/mali_kbase/csf/mali_kbase_csf_scheduler.h
+++ b/mali_kbase/csf/mali_kbase_csf_scheduler.h
@@ -415,6 +415,22 @@ void kbase_csf_scheduler_pm_idle(struct kbase_device *kbdev);
int kbase_csf_scheduler_wait_mcu_active(struct kbase_device *kbdev);
/**
+ * kbase_csf_scheduler_killable_wait_mcu_active - Wait for the MCU to actually become
+ * active in killable state.
+ *
+ * @kbdev: Instance of a GPU platform device that implements a CSF interface.
+ *
+ * This function is same as kbase_csf_scheduler_wait_mcu_active(), expect that
+ * it would allow the SIGKILL signal to interrupt the wait.
+ * This function is supposed to be called from the code that is executed in ioctl or
+ * Userspace context, wherever it is safe to do so.
+ *
+ * Return: 0 if the MCU was successfully activated, or -ETIMEDOUT code on timeout error or
+ * -ERESTARTSYS if the wait was interrupted.
+ */
+int kbase_csf_scheduler_killable_wait_mcu_active(struct kbase_device *kbdev);
+
+/**
* kbase_csf_scheduler_pm_resume_no_lock - Reactivate the scheduler on system resume
*
* @kbdev: Instance of a GPU platform device that implements a CSF interface.
diff --git a/mali_kbase/csf/mali_kbase_csf_timeout.c b/mali_kbase/csf/mali_kbase_csf_timeout.c
index 0cfe7e2..f7fcbb1 100644
--- a/mali_kbase/csf/mali_kbase_csf_timeout.c
+++ b/mali_kbase/csf/mali_kbase_csf_timeout.c
@@ -101,7 +101,7 @@ static ssize_t progress_timeout_store(struct device * const dev,
if (!err) {
kbase_csf_scheduler_pm_active(kbdev);
- err = kbase_csf_scheduler_wait_mcu_active(kbdev);
+ err = kbase_csf_scheduler_killable_wait_mcu_active(kbdev);
if (!err)
err = kbase_csf_firmware_set_timeout(kbdev, timeout);
diff --git a/mali_kbase/device/backend/mali_kbase_device_hw_csf.c b/mali_kbase/device/backend/mali_kbase_device_hw_csf.c
index 3f34729..01a3534 100644
--- a/mali_kbase/device/backend/mali_kbase_device_hw_csf.c
+++ b/mali_kbase/device/backend/mali_kbase_device_hw_csf.c
@@ -191,8 +191,7 @@ bool kbase_is_register_accessible(u32 offset)
{
#ifdef CONFIG_MALI_DEBUG
if (((offset >= MCU_SUBSYSTEM_BASE) && (offset < IPA_CONTROL_BASE)) ||
- ((offset >= GPU_CONTROL_MCU_BASE) && (offset < USER_BASE) &&
- (offset != GPU_CONTROL_MCU_REG(GPU_CTRL_MCU_GPU_COMMAND)))) {
+ ((offset >= GPU_CONTROL_MCU_BASE) && (offset < USER_BASE))) {
WARN(1, "Invalid register offset 0x%x", offset);
return false;
}
diff --git a/mali_kbase/gpu/backend/mali_kbase_gpu_regmap_csf.h b/mali_kbase/gpu/backend/mali_kbase_gpu_regmap_csf.h
index 6e0c8ee..ab989e0 100644
--- a/mali_kbase/gpu/backend/mali_kbase_gpu_regmap_csf.h
+++ b/mali_kbase/gpu/backend/mali_kbase_gpu_regmap_csf.h
@@ -39,11 +39,8 @@
(((reg_val) & ~L2_CONFIG_PBHA_HWU_MASK) | \
(((value) << L2_CONFIG_PBHA_HWU_SHIFT) & L2_CONFIG_PBHA_HWU_MASK))
-/* GPU_CONTROL_MCU registers */
-#define GPU_CONTROL_MCU_BASE 0x3000
-#define GPU_CONTROL_MCU_REG(r) (GPU_CONTROL_MCU_BASE + (r))
-
-#define GPU_CTRL_MCU_GPU_COMMAND 0x30 /* (WO) GPU command register */
+/* GPU_CONTROL_MCU base address */
+#define GPU_CONTROL_MCU_BASE 0x3000
/* MCU_SUBSYSTEM base address */
#define MCU_SUBSYSTEM_BASE 0x20000
@@ -209,12 +206,6 @@
#define GPU_COMMAND_NOP \
GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_NOP, 0)
-/* This leaves the state of active jobs UNDEFINED, but leaves the external
- * bus in a defined and idle state. Power domains remain powered up.
- */
-#define GPU_COMMAND_FAST_RESET \
- GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_RESET, GPU_COMMAND_RESET_PAYLOAD_FAST_RESET)
-
/* Stop all external bus interfaces, and then reset the entire GPU. */
#define GPU_COMMAND_SOFT_RESET \
GPU_COMMAND_CODE_PAYLOAD(GPU_COMMAND_CODE_RESET, GPU_COMMAND_RESET_PAYLOAD_SOFT_RESET)
diff --git a/mali_kbase/gpu/mali_kbase_gpu_regmap.h b/mali_kbase/gpu/mali_kbase_gpu_regmap.h
index 64431ba..a92b498 100644
--- a/mali_kbase/gpu/mali_kbase_gpu_regmap.h
+++ b/mali_kbase/gpu/mali_kbase_gpu_regmap.h
@@ -63,7 +63,6 @@
#define GPU_COMMAND 0x030 /* (WO) */
#define GPU_STATUS 0x034 /* (RO) */
-#define GPU_STATUS_GPU_ACTIVE (1)
#define GPU_STATUS_PRFCNT_ACTIVE (1 << 2) /* Set if the performance counters are active. */
#define GPU_STATUS_CYCLE_COUNT_ACTIVE (1 << 6) /* Set if the cycle counter is active. */
#define GPU_STATUS_PROTECTED_MODE_ACTIVE (1 << 7) /* Set if protected mode is active */
diff --git a/mali_kbase/jm/mali_kbase_jm_defs.h b/mali_kbase/jm/mali_kbase_jm_defs.h
index d2b53ba..a265328 100644
--- a/mali_kbase/jm/mali_kbase_jm_defs.h
+++ b/mali_kbase/jm/mali_kbase_jm_defs.h
@@ -861,10 +861,6 @@ struct jsctx_queue {
* @pf_data: Data relating to Page fault.
* @bf_data: Data relating to Bus fault.
* @current_setup: Stores the MMU configuration for this address space.
- * @is_unresponsive: Flag to indicate MMU is not responding.
- * Set if a MMU command isn't completed within
- * &kbase_device:mmu_or_gpu_cache_op_wait_time_ms.
- * Clear by kbase_ctx_sched_restore_all_as() after GPU reset completes.
*/
struct kbase_as {
int number;
@@ -874,7 +870,6 @@ struct kbase_as {
struct kbase_fault pf_data;
struct kbase_fault bf_data;
struct kbase_mmu_setup current_setup;
- bool is_unresponsive;
};
#endif /* _KBASE_JM_DEFS_H_ */
diff --git a/mali_kbase/mali_base_hwconfig_issues.h b/mali_kbase/mali_base_hwconfig_issues.h
index 65c66ef..91b9b83 100644
--- a/mali_kbase/mali_base_hwconfig_issues.h
+++ b/mali_kbase/mali_base_hwconfig_issues.h
@@ -66,7 +66,6 @@ enum base_hw_issue {
BASE_HW_ISSUE_GPU2021PRO_290,
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_GPU2022PRO_148,
BASE_HW_ISSUE_END
};
@@ -728,7 +727,6 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r0p0
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
BASE_HW_ISSUE_GPU2022PRO_148,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_END
};
@@ -743,7 +741,6 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r0p1
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
BASE_HW_ISSUE_GPU2022PRO_148,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_END
};
@@ -757,7 +754,6 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_model_tTU
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
BASE_HW_ISSUE_GPU2022PRO_148,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_END
};
@@ -771,7 +767,6 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r1p0
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
BASE_HW_ISSUE_GPU2022PRO_148,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_END
};
@@ -785,7 +780,6 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r1p1
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
BASE_HW_ISSUE_GPU2022PRO_148,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_END
};
@@ -799,7 +793,6 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r1p2
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
BASE_HW_ISSUE_GPU2022PRO_148,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_END
};
@@ -813,7 +806,6 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTUx_r1p3
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
BASE_HW_ISSUE_GPU2022PRO_148,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_END
};
@@ -825,7 +817,6 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_model_tTI
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
BASE_HW_ISSUE_GPU2022PRO_148,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_END
};
@@ -837,7 +828,6 @@ __attribute__((unused)) static const enum base_hw_issue base_hw_issues_tTIx_r0p0
BASE_HW_ISSUE_TITANHW_2710,
BASE_HW_ISSUE_TITANHW_2679,
BASE_HW_ISSUE_GPU2022PRO_148,
- BASE_HW_ISSUE_TITANHW_2922,
BASE_HW_ISSUE_END
};
diff --git a/mali_kbase/mali_kbase_core_linux.c b/mali_kbase/mali_kbase_core_linux.c
index 0f5a3a3..1b265f0 100644
--- a/mali_kbase/mali_kbase_core_linux.c
+++ b/mali_kbase/mali_kbase_core_linux.c
@@ -3522,7 +3522,7 @@ static ssize_t gpuinfo_show(struct device *dev,
GPU_FEATURES_RAY_TRACING_GET(gpu_props->props.raw_props.gpu_features);
const u8 nr_cores = gpu_props->num_cores;
- if ((nr_cores > 10) && rt_supported)
+ if ((nr_cores >= 10) && rt_supported)
product_name = "Mali-G720-Immortalis";
else
product_name = (nr_cores >= 6) ? "Mali-G720" : "Mali-G620";
@@ -5559,7 +5559,10 @@ static ssize_t idle_hysteresis_time_store(struct device *dev,
return -EINVAL;
}
- kbase_csf_firmware_set_gpu_idle_hysteresis_time(kbdev, dur);
+ /* In sysFs, The unit of the input value of idle_hysteresis_time is us.
+ * But the unit of the input parameter of this function is ns, so multiply by 1000
+ */
+ kbase_csf_firmware_set_gpu_idle_hysteresis_time(kbdev, dur * NSEC_PER_USEC);
return count;
}
@@ -5586,7 +5589,8 @@ static ssize_t idle_hysteresis_time_show(struct device *dev,
if (!kbdev)
return -ENODEV;
- dur = kbase_csf_firmware_get_gpu_idle_hysteresis_time(kbdev);
+ /* The unit of return value of idle_hysteresis_time_show is us, So divide by 1000.*/
+ dur = kbase_csf_firmware_get_gpu_idle_hysteresis_time(kbdev) / NSEC_PER_USEC;
ret = scnprintf(buf, PAGE_SIZE, "%u\n", dur);
return ret;
@@ -5595,6 +5599,74 @@ static ssize_t idle_hysteresis_time_show(struct device *dev,
static DEVICE_ATTR_RW(idle_hysteresis_time);
/**
+ * idle_hysteresis_time_ns_store - Store callback for CSF
+ * idle_hysteresis_time_ns sysfs file.
+ *
+ * @dev: The device with sysfs file is for
+ * @attr: The attributes of the sysfs file
+ * @buf: The value written to the sysfs file
+ * @count: The number of bytes written to the sysfs file
+ *
+ * This function is called when the idle_hysteresis_time_ns sysfs
+ * file is written to.
+ *
+ * This file contains values of the idle hysteresis duration in ns.
+ *
+ * Return: @count if the function succeeded. An error code on failure.
+ */
+static ssize_t idle_hysteresis_time_ns_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ u32 dur = 0;
+
+ kbdev = to_kbase_device(dev);
+ if (!kbdev)
+ return -ENODEV;
+
+ if (kstrtou32(buf, 0, &dur)) {
+ dev_err(kbdev->dev, "Couldn't process idle_hysteresis_time_ns write operation.\n"
+ "Use format <idle_hysteresis_time_ns>\n");
+ return -EINVAL;
+ }
+
+ kbase_csf_firmware_set_gpu_idle_hysteresis_time(kbdev, dur);
+
+ return count;
+}
+
+/**
+ * idle_hysteresis_time_ns_show - Show callback for CSF
+ * idle_hysteresis_time_ns sysfs entry.
+ *
+ * @dev: The device this sysfs file is for.
+ * @attr: The attributes of the sysfs file.
+ * @buf: The output buffer to receive the GPU information.
+ *
+ * This function is called to get the current idle hysteresis duration in ns.
+ *
+ * Return: The number of bytes output to @buf.
+ */
+static ssize_t idle_hysteresis_time_ns_show(struct device *dev, struct device_attribute *attr,
+ char *const buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret;
+ u32 dur;
+
+ kbdev = to_kbase_device(dev);
+ if (!kbdev)
+ return -ENODEV;
+
+ dur = kbase_csf_firmware_get_gpu_idle_hysteresis_time(kbdev);
+ ret = scnprintf(buf, PAGE_SIZE, "%u\n", dur);
+
+ return ret;
+}
+
+static DEVICE_ATTR_RW(idle_hysteresis_time_ns);
+
+/**
* mcu_shader_pwroff_timeout_show - Get the MCU shader Core power-off time value.
*
* @dev: The device this sysfs file is for.
@@ -5616,7 +5688,8 @@ static ssize_t mcu_shader_pwroff_timeout_show(struct device *dev, struct device_
if (!kbdev)
return -ENODEV;
- pwroff = kbase_csf_firmware_get_mcu_core_pwroff_time(kbdev);
+ /* The unit of return value of the function is us, So divide by 1000.*/
+ pwroff = kbase_csf_firmware_get_mcu_core_pwroff_time(kbdev) / NSEC_PER_USEC;
return scnprintf(buf, PAGE_SIZE, "%u\n", pwroff);
}
@@ -5654,13 +5727,83 @@ static ssize_t mcu_shader_pwroff_timeout_store(struct device *dev, struct device
if (dur == 0 && !always_on)
return -EINVAL;
- kbase_csf_firmware_set_mcu_core_pwroff_time(kbdev, dur);
+ /* In sysFs, The unit of the input value of mcu_shader_pwroff_timeout is us.
+ * But the unit of the input parameter of this function is ns, so multiply by 1000
+ */
+ kbase_csf_firmware_set_mcu_core_pwroff_time(kbdev, dur * NSEC_PER_USEC);
return count;
}
static DEVICE_ATTR_RW(mcu_shader_pwroff_timeout);
+/**
+ * mcu_shader_pwroff_timeout_ns_show - Get the MCU shader Core power-off time value.
+ *
+ * @dev: The device this sysfs file is for.
+ * @attr: The attributes of the sysfs file.
+ * @buf: The output buffer for the sysfs file contents
+ *
+ * Get the internally recorded MCU shader Core power-off (nominal) timeout value.
+ * The unit of the value is in nanoseconds.
+ *
+ * Return: The number of bytes output to @buf if the
+ * function succeeded. A Negative value on failure.
+ */
+static ssize_t mcu_shader_pwroff_timeout_ns_show(struct device *dev, struct device_attribute *attr,
+ char *const buf)
+{
+ struct kbase_device *kbdev = dev_get_drvdata(dev);
+ u32 pwroff;
+
+ if (!kbdev)
+ return -ENODEV;
+
+ pwroff = kbase_csf_firmware_get_mcu_core_pwroff_time(kbdev);
+ return scnprintf(buf, PAGE_SIZE, "%u\n", pwroff);
+}
+
+/**
+ * mcu_shader_pwroff_timeout_ns_store - Set the MCU shader core power-off time value.
+ *
+ * @dev: The device with sysfs file is for
+ * @attr: The attributes of the sysfs file
+ * @buf: The value written to the sysfs file
+ * @count: The number of bytes to write to the sysfs file
+ *
+ * The duration value (unit: nanoseconds) for configuring MCU Shader Core
+ * timer, when the shader cores' power transitions are delegated to the
+ * MCU (normal operational mode)
+ *
+ * Return: @count if the function succeeded. An error code on failure.
+ */
+static ssize_t mcu_shader_pwroff_timeout_ns_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kbase_device *kbdev = dev_get_drvdata(dev);
+ u32 dur;
+
+ const struct kbase_pm_policy *current_policy;
+ bool always_on;
+
+ if (!kbdev)
+ return -ENODEV;
+
+ if (kstrtouint(buf, 0, &dur))
+ return -EINVAL;
+
+ current_policy = kbase_pm_get_policy(kbdev);
+ always_on = current_policy == &kbase_pm_always_on_policy_ops;
+ if (dur == 0 && !always_on)
+ return -EINVAL;
+
+ kbase_csf_firmware_set_mcu_core_pwroff_time(kbdev, dur);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(mcu_shader_pwroff_timeout_ns);
+
#endif /* MALI_USE_CSF */
static struct attribute *kbase_scheduling_attrs[] = {
@@ -5691,7 +5834,9 @@ static struct attribute *kbase_attrs[] = {
&dev_attr_csg_scheduling_period.attr,
&dev_attr_fw_timeout.attr,
&dev_attr_idle_hysteresis_time.attr,
+ &dev_attr_idle_hysteresis_time_ns.attr,
&dev_attr_mcu_shader_pwroff_timeout.attr,
+ &dev_attr_mcu_shader_pwroff_timeout_ns.attr,
#endif /* !MALI_USE_CSF */
&dev_attr_power_policy.attr,
&dev_attr_core_mask.attr,
diff --git a/mali_kbase/mali_kbase_ctx_sched.c b/mali_kbase/mali_kbase_ctx_sched.c
index 01e4eab..ea4f300 100644
--- a/mali_kbase/mali_kbase_ctx_sched.c
+++ b/mali_kbase/mali_kbase_ctx_sched.c
@@ -239,10 +239,11 @@ void kbase_ctx_sched_restore_all_as(struct kbase_device *kbdev)
WARN_ON(!kbdev->pm.backend.gpu_powered);
+ kbdev->mmu_unresponsive = false;
+
for (i = 0; i != kbdev->nr_hw_address_spaces; ++i) {
struct kbase_context *kctx;
- kbdev->as[i].is_unresponsive = false;
#if MALI_USE_CSF
if ((i == MCU_AS_NR) && kbdev->csf.firmware_inited) {
kbase_mmu_update(kbdev, &kbdev->csf.mcu_mmu,
diff --git a/mali_kbase/mali_kbase_defs.h b/mali_kbase/mali_kbase_defs.h
index b6e016f..8179d77 100644
--- a/mali_kbase/mali_kbase_defs.h
+++ b/mali_kbase/mali_kbase_defs.h
@@ -186,6 +186,8 @@ struct kbase_gpu_metrics {
* inactive in the current work period.
* @total_active: Tracks the time for which application has been active
* in the current work period.
+ * @prev_wp_active_end_time: Records the time at which the application last became
+ * inactive in the previous work period.
* @aid: Unique identifier for an application.
* @kctx_count: Counter to keep a track of the number of Kbase contexts
* created for an application. There may be multiple Kbase
@@ -194,8 +196,6 @@ struct kbase_gpu_metrics {
* @active_cnt: Counter that is updated every time the GPU activity starts
* and ends in the current work period for an application.
* @flags: Flags to track the state of GPU metrics context.
- * @prev_wp_active_end_time: Records the time at which the application last became
- * inactive in the previous work period.
*/
struct kbase_gpu_metrics_ctx {
struct list_head link;
@@ -203,13 +203,11 @@ struct kbase_gpu_metrics_ctx {
u64 last_active_start_time;
u64 last_active_end_time;
u64 total_active;
+ u64 prev_wp_active_end_time;
unsigned int aid;
unsigned int kctx_count;
u8 active_cnt;
u8 flags;
-#ifdef CONFIG_MALI_DEBUG
- u64 prev_wp_active_end_time;
-#endif
};
#endif
@@ -905,10 +903,14 @@ struct kbase_mem_migrate {
* to the GPU device. This points to an internal memory
* group manager if no platform-specific memory group
* manager was retrieved through device tree.
+ * @mmu_unresponsive: Flag to indicate MMU is not responding.
+ * Set if a MMU command isn't completed within
+ * &kbase_device:mmu_or_gpu_cache_op_wait_time_ms.
+ * Clear by kbase_ctx_sched_restore_all_as() after GPU reset completes.
* @as: Array of objects representing address spaces of GPU.
- * @as_free: Bitpattern of free/available GPU address spaces.
* @as_to_kctx: Array of pointers to struct kbase_context, having
* GPU adrress spaces assigned to them.
+ * @as_free: Bitpattern of free/available GPU address spaces.
* @mmu_mask_change: Lock to serialize the access to MMU interrupt mask
* register used in the handling of Bus & Page faults.
* @pagesize_2mb: Boolean to determine whether 2MiB page sizes are
@@ -1208,9 +1210,10 @@ struct kbase_device {
struct memory_group_manager_device *mgm_dev;
+ bool mmu_unresponsive;
struct kbase_as as[BASE_MAX_NR_AS];
- u16 as_free;
struct kbase_context *as_to_kctx[BASE_MAX_NR_AS];
+ u16 as_free;
spinlock_t mmu_mask_change;
diff --git a/mali_kbase/mali_kbase_gpu_metrics.c b/mali_kbase/mali_kbase_gpu_metrics.c
index 54a8276..af3a08d 100644
--- a/mali_kbase/mali_kbase_gpu_metrics.c
+++ b/mali_kbase/mali_kbase_gpu_metrics.c
@@ -78,8 +78,6 @@ static inline void validate_tracepoint_data(struct kbase_gpu_metrics_ctx *gpu_me
"prev_wp_active_end_time %llu > start_time %llu for aid %u active_cnt %u",
gpu_metrics_ctx->prev_wp_active_end_time, start_time,
gpu_metrics_ctx->aid, gpu_metrics_ctx->active_cnt);
-
- gpu_metrics_ctx->prev_wp_active_end_time = end_time;
#endif
}
@@ -107,6 +105,7 @@ static void emit_tracepoint_for_active_gpu_metrics_ctx(struct kbase_device *kbde
start_time, end_time, total_active);
validate_tracepoint_data(gpu_metrics_ctx, start_time, end_time, total_active);
+ gpu_metrics_ctx->prev_wp_active_end_time = end_time;
gpu_metrics_ctx->total_active = 0;
}
@@ -159,10 +158,8 @@ void kbase_gpu_metrics_ctx_init(struct kbase_device *kbdev,
gpu_metrics_ctx->total_active = 0;
gpu_metrics_ctx->kctx_count = 1;
gpu_metrics_ctx->active_cnt = 0;
- gpu_metrics_ctx->flags = 0;
-#ifdef CONFIG_MALI_DEBUG
gpu_metrics_ctx->prev_wp_active_end_time = 0;
-#endif
+ gpu_metrics_ctx->flags = 0;
list_add_tail(&gpu_metrics_ctx->link, &kbdev->gpu_metrics.inactive_list);
}
@@ -192,12 +189,39 @@ void kbase_gpu_metrics_ctx_end_activity(struct kbase_context *kctx, u64 timestam
if (WARN_ON_ONCE(!gpu_metrics_ctx->active_cnt))
return;
- gpu_metrics_ctx->active_cnt--;
- if (!gpu_metrics_ctx->active_cnt) {
+ if (--gpu_metrics_ctx->active_cnt)
+ return;
+
+ if (likely(timestamp_ns > gpu_metrics_ctx->last_active_start_time)) {
gpu_metrics_ctx->last_active_end_time = timestamp_ns;
gpu_metrics_ctx->total_active +=
timestamp_ns - gpu_metrics_ctx->last_active_start_time;
+ return;
+ }
+
+ /* Due to conversion from system timestamp to CPU timestamp (which involves rounding)
+ * the value for start and end timestamp could come as same.
+ */
+ if (timestamp_ns == gpu_metrics_ctx->last_active_start_time) {
+ gpu_metrics_ctx->last_active_end_time = timestamp_ns + 1;
+ gpu_metrics_ctx->total_active += 1;
+ return;
}
+
+ /* The following check is to detect the situation where 'ACT=0' event was not visible to
+ * the Kbase even though the system timestamp value sampled by FW was less than the system
+ * timestamp value sampled by Kbase just before the draining of trace buffer.
+ */
+ if (gpu_metrics_ctx->last_active_start_time == gpu_metrics_ctx->first_active_start_time &&
+ gpu_metrics_ctx->prev_wp_active_end_time == gpu_metrics_ctx->first_active_start_time) {
+ WARN_ON_ONCE(gpu_metrics_ctx->total_active);
+ gpu_metrics_ctx->last_active_end_time =
+ gpu_metrics_ctx->prev_wp_active_end_time + 1;
+ gpu_metrics_ctx->total_active = 1;
+ return;
+ }
+
+ WARN_ON_ONCE(1);
}
void kbase_gpu_metrics_emit_tracepoint(struct kbase_device *kbdev, u64 ts)
diff --git a/mali_kbase/mali_kbase_mem.c b/mali_kbase/mali_kbase_mem.c
index 24039aa..e19525f 100644
--- a/mali_kbase/mali_kbase_mem.c
+++ b/mali_kbase/mali_kbase_mem.c
@@ -916,12 +916,12 @@ static void kbase_reg_zone_exec_va_term(struct kbase_context *kctx)
kbase_reg_zone_term(zone);
}
+#if MALI_USE_CSF
static inline u64 kbase_get_exec_fixed_va_zone_base(struct kbase_context *kctx)
{
return kbase_get_exec_va_zone_base(kctx) + KBASE_REG_ZONE_EXEC_VA_SIZE;
}
-#if MALI_USE_CSF
static int kbase_reg_zone_exec_fixed_va_init(struct kbase_context *kctx, u64 gpu_va_limit)
{
struct kbase_reg_zone *zone = kbase_ctx_reg_zone_get(kctx, EXEC_FIXED_VA_ZONE);
diff --git a/mali_kbase/mmu/backend/mali_kbase_mmu_csf.c b/mali_kbase/mmu/backend/mali_kbase_mmu_csf.c
index 86af321..a057d3c 100644
--- a/mali_kbase/mmu/backend/mali_kbase_mmu_csf.c
+++ b/mali_kbase/mmu/backend/mali_kbase_mmu_csf.c
@@ -555,9 +555,8 @@ int kbase_mmu_as_init(struct kbase_device *kbdev, unsigned int i)
kbdev->as[i].bf_data.addr = 0ULL;
kbdev->as[i].pf_data.addr = 0ULL;
kbdev->as[i].gf_data.addr = 0ULL;
- kbdev->as[i].is_unresponsive = false;
- kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%d", WQ_UNBOUND, 1, i);
+ kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%d", WQ_UNBOUND, 0, i);
if (!kbdev->as[i].pf_wq)
return -ENOMEM;
diff --git a/mali_kbase/mmu/backend/mali_kbase_mmu_jm.c b/mali_kbase/mmu/backend/mali_kbase_mmu_jm.c
index 275ac3d..5c774c2 100644
--- a/mali_kbase/mmu/backend/mali_kbase_mmu_jm.c
+++ b/mali_kbase/mmu/backend/mali_kbase_mmu_jm.c
@@ -429,9 +429,8 @@ int kbase_mmu_as_init(struct kbase_device *kbdev, unsigned int i)
kbdev->as[i].number = i;
kbdev->as[i].bf_data.addr = 0ULL;
kbdev->as[i].pf_data.addr = 0ULL;
- kbdev->as[i].is_unresponsive = false;
- kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%u", 0, 1, i);
+ kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%u", 0, 0, i);
if (!kbdev->as[i].pf_wq)
return -ENOMEM;
diff --git a/mali_kbase/mmu/mali_kbase_mmu_hw_direct.c b/mali_kbase/mmu/mali_kbase_mmu_hw_direct.c
index 44d03c8..2abb677 100644
--- a/mali_kbase/mmu/mali_kbase_mmu_hw_direct.c
+++ b/mali_kbase/mmu/mali_kbase_mmu_hw_direct.c
@@ -173,7 +173,7 @@ static int wait_ready(struct kbase_device *kbdev, unsigned int as_nr)
const u32 mmu_as_inactive_wait_time_ms = kbdev->mmu_or_gpu_cache_op_wait_time_ms;
s64 diff;
- if (unlikely(kbdev->as[as_nr].is_unresponsive))
+ if (unlikely(kbdev->mmu_unresponsive))
return -EBUSY;
do {
@@ -192,7 +192,7 @@ static int wait_ready(struct kbase_device *kbdev, unsigned int as_nr)
dev_err(kbdev->dev,
"AS_ACTIVE bit stuck for as %u. Might be caused by unstable GPU clk/pwr or faulty system",
as_nr);
- kbdev->as[as_nr].is_unresponsive = true;
+ kbdev->mmu_unresponsive = true;
if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR))
kbase_reset_gpu_locked(kbdev);
@@ -222,7 +222,7 @@ static int write_cmd(struct kbase_device *kbdev, int as_nr, u32 cmd)
#if MALI_USE_CSF && !IS_ENABLED(CONFIG_MALI_NO_MALI)
static int wait_cores_power_trans_complete(struct kbase_device *kbdev)
{
-#define WAIT_TIMEOUT 1000 /* 1ms timeout */
+#define WAIT_TIMEOUT 50000 /* 50ms timeout */
#define DELAY_TIME_IN_US 1
const int max_iterations = WAIT_TIMEOUT;
int loop;
@@ -242,7 +242,9 @@ static int wait_cores_power_trans_complete(struct kbase_device *kbdev)
}
if (loop == max_iterations) {
- dev_warn(kbdev->dev, "SHADER_PWRTRANS set for too long");
+ dev_warn(kbdev->dev, "SHADER_PWRTRANS %08x%08x set for too long",
+ kbase_reg_read(kbdev, GPU_CONTROL_REG(SHADER_PWRTRANS_HI)),
+ kbase_reg_read(kbdev, GPU_CONTROL_REG(SHADER_PWRTRANS_LO)));
return -ETIMEDOUT;
}
@@ -275,9 +277,8 @@ static int apply_hw_issue_GPU2019_3901_wa(struct kbase_device *kbdev, u32 *mmu_c
* the workaround can be safely skipped.
*/
if (kbdev->pm.backend.l2_state != KBASE_L2_OFF) {
- if (*mmu_cmd != AS_COMMAND_FLUSH_MEM) {
- dev_warn(kbdev->dev,
- "Unexpected mmu command received");
+ if (unlikely(*mmu_cmd != AS_COMMAND_FLUSH_MEM)) {
+ dev_warn(kbdev->dev, "Unexpected MMU command(%u) received", *mmu_cmd);
return -EINVAL;
}
@@ -569,8 +570,14 @@ static int mmu_hw_do_flush(struct kbase_device *kbdev, struct kbase_as *as,
ret = apply_hw_issue_GPU2019_3901_wa(kbdev, &mmu_cmd, as->number);
}
- if (ret)
- return ret;
+ if (ret) {
+ dev_warn(
+ kbdev->dev,
+ "Failed to apply WA for HW issue when doing MMU flush op on VA range %llx-%llx for AS %u",
+ op_param->vpfn << PAGE_SHIFT,
+ ((op_param->vpfn + op_param->nr) << PAGE_SHIFT) - 1, as->number);
+ /* Continue with the MMU flush operation */
+ }
}
#endif