With v15 GPUs, FW can yield GPU access at any point. This includes when panthor has scheduled a reset. If a WINDOW_CLOSED event is received after reset work is scheduled but before the actual RESET_SOFT command is sent, panthor_aw can end up assuming that the WINDOW_CLOSED is a result of the reset and fail to schedule the post-yield cleanup.
Introduce pre_reset and post_reset helpers for panthor_aw which marks a granted AW as reset-active so reset-originated WINDOW_CLOSED handling does not suppress post-yield cleanup when FW yield wins the race. Signed-off-by: Karunika Choo <[email protected]> --- drivers/gpu/drm/panthor/panthor_aw.c | 54 +++++++++++++++++++++--- drivers/gpu/drm/panthor/panthor_aw.h | 7 +++ drivers/gpu/drm/panthor/panthor_device.c | 13 +++++- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_aw.c b/drivers/gpu/drm/panthor/panthor_aw.c index 9ebb23eadfec5..7ef13db4acf50 100644 --- a/drivers/gpu/drm/panthor/panthor_aw.c +++ b/drivers/gpu/drm/panthor/panthor_aw.c @@ -248,7 +248,7 @@ static void panthor_aw_handle_window_closed(struct panthor_aw *aw) struct panthor_device *ptdev = aw->ptdev; /* Ignore this WINDOW_CLOSED as part of reset operation. */ - if (panthor_device_reset_is_pending(ptdev)) + if (atomic_read(&aw->state) == PANTHOR_AW_STATE_RESET_ACTIVE) return; if (atomic_read(&aw->state) == PANTHOR_AW_STATE_GPU_STOPPED || @@ -260,14 +260,14 @@ static void panthor_aw_handle_window_closed(struct panthor_aw *aw) /* * Window may have been closed immediately after opening. - * Setting state back to READY will prevent WINDOW_OPENDED from + * Setting state back to READY will prevent WINDOW_OPENED from * mistakenly transitioning the state to GRANTED. */ if (panthor_aw_state_try_set(aw, PANTHOR_AW_STATE_GPU_REQUEST, PANTHOR_AW_STATE_READY)) return; - /* Triggerred from messaged-based yield. Unblock its wait */ + /* Triggered from messaged-based yield. Unblock its wait */ if (panthor_aw_state_try_set(aw, PANTHOR_AW_STATE_STOPPED_IDLE, PANTHOR_AW_STATE_READY)) return; @@ -275,6 +275,17 @@ static void panthor_aw_handle_window_closed(struct panthor_aw *aw) panthor_aw_schedule_post_yield_work(aw); } +static void panthor_aw_handle_window_opened(struct panthor_aw *aw) +{ + /* Ignore this WINDOW_OPENED as part of reset operation. */ + if (atomic_read(&aw->state) == PANTHOR_AW_STATE_RESET_ACTIVE) + return; + + /* Window opened due to GPU_REQUEST */ + panthor_aw_state_try_set(aw, PANTHOR_AW_STATE_GPU_REQUEST, + PANTHOR_AW_STATE_GPU_GRANTED); +} + static irqreturn_t panthor_aw_irq_raw_hander(int irq, void *data) { struct panthor_irq *pirq = data; @@ -297,10 +308,8 @@ static irqreturn_t panthor_aw_irq_raw_hander(int irq, void *data) if (status & WINDOW_IRQ_WINDOW_CLOSED) panthor_aw_handle_window_closed(aw); - if ((status & WINDOW_IRQ_WINDOW_OPENED) && panthor_aw_is_open(aw)) - panthor_aw_state_try_set(aw, PANTHOR_AW_STATE_GPU_REQUEST, - PANTHOR_AW_STATE_GPU_GRANTED); + panthor_aw_handle_window_opened(aw); gpu_write(pirq->iomem, INT_CLEAR, status); @@ -579,5 +588,36 @@ bool panthor_aw_has_gpu_access(struct panthor_device *ptdev) if (!ptdev->aw) return true; - return (atomic_read(&ptdev->aw->state) == PANTHOR_AW_STATE_GPU_GRANTED); + switch (atomic_read(&ptdev->aw->state)) { + case PANTHOR_AW_STATE_GPU_GRANTED: + case PANTHOR_AW_STATE_RESET_ACTIVE: + return true; + } + + return false; +} + +void panthor_aw_pre_reset(struct panthor_device *ptdev) +{ + struct panthor_aw *aw = ptdev->aw; + + if (!aw) + return; + + panthor_aw_state_try_set(ptdev->aw, PANTHOR_AW_STATE_GPU_GRANTED, + PANTHOR_AW_STATE_RESET_ACTIVE); +} + +void panthor_aw_post_reset(struct panthor_device *ptdev) +{ + struct panthor_aw *aw = ptdev->aw; + + if (!aw) + return; + + panthor_aw_state_try_set(aw, PANTHOR_AW_STATE_RESET_ACTIVE, + PANTHOR_AW_STATE_GPU_GRANTED); + + if (!panthor_aw_is_open(aw)) + panthor_aw_schedule_post_yield_work(aw); } diff --git a/drivers/gpu/drm/panthor/panthor_aw.h b/drivers/gpu/drm/panthor/panthor_aw.h index 1da613fa330a0..0269bbbbdc165 100644 --- a/drivers/gpu/drm/panthor/panthor_aw.h +++ b/drivers/gpu/drm/panthor/panthor_aw.h @@ -24,6 +24,9 @@ enum aw_states { /** @PANTHOR_AW_STATE_GPU_GRANTED: AW is granted GPU access. */ PANTHOR_AW_STATE_GPU_GRANTED, + /** @PANTHOR_AW_STATE_RESET_ACTIVE: AW is being reset. */ + PANTHOR_AW_STATE_RESET_ACTIVE, + /** @PANTHOR_AW_STATE_STOPPED_IDLE: AW has stopped GPU access. */ PANTHOR_AW_STATE_STOPPED_IDLE, @@ -43,4 +46,8 @@ int panthor_aw_ensure_gpu_access(struct panthor_device *ptdev); bool panthor_aw_has_gpu_access(struct panthor_device *ptdev); +void panthor_aw_pre_reset(struct panthor_device *ptdev); + +void panthor_aw_post_reset(struct panthor_device *ptdev); + #endif diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index ea35c5e1d87b4..86eb4e9a61789 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -138,18 +138,27 @@ static void panthor_device_reset_work(struct work_struct *work) if (!drm_dev_enter(&ptdev->base, &cookie)) return; + if (!panthor_aw_has_gpu_access(ptdev)) + goto out_clear_pending; + panthor_sched_pre_reset(ptdev); + panthor_aw_pre_reset(ptdev); panthor_fw_pre_reset(ptdev, true); panthor_mmu_pre_reset(ptdev); + panthor_hw_soft_reset(ptdev); + panthor_hw_l2_power_on(ptdev); panthor_mmu_post_reset(ptdev); ret = panthor_fw_post_reset(ptdev); - atomic_set(&ptdev->reset.pending, 0); + panthor_aw_post_reset(ptdev); panthor_sched_post_reset(ptdev, ret != 0); + +out_clear_pending: + atomic_set(&ptdev->reset.pending, 0); drm_dev_exit(cookie); - if (ret) { + if (ret && panthor_aw_has_gpu_access(ptdev)) { panthor_device_unplug(ptdev); drm_err(&ptdev->base, "Failed to boot MCU after reset, making device unusable."); } -- 2.43.0
