diff options
author | Jörg Wagner <jorwag@google.com> | 2023-08-31 17:27:24 +0000 |
---|---|---|
committer | Jörg Wagner <jorwag@google.com> | 2023-08-31 17:27:24 +0000 |
commit | e61eb93296e9f940b32d4ad4b0c3a5557cbeaf17 (patch) | |
tree | 4c649cc9f5a08e8362f9d564f121f46b07d89ecd | |
parent | dacf004cc8a4b35f5a0fb5fb67246f9cc8fdaafb (diff) | |
download | gpu-e61eb93296e9f940b32d4ad4b0c3a5557cbeaf17.tar.gz |
Update KMD to 'mini release: update r44p1-00dev2 to r44p1-00dev3'
Provenance: ipdelivery@5c8fdf6c071d63537e87949cfb4845079a669a0b
Change-Id: Icc06581f804bf59be5fe923349318e703f02d5a3
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 |