Skip to content

Commit fcb3243

Browse files
mairacanalpelwell
authored andcommitted
drm/v3d: Idle AXI transactions before disabling the clock on suspend
Currently, v3d_power_suspend() removes the GPU clock without first quiescing the GPU's memory interface (AXI). If the clock is cut while the core still has outstanding AXI transactions in flight, the hardware is frozen mid-transaction. That corrupted state survives the power cycle, and the first job submitted after the next resume will cause a GPU hang accompanied by an L2T "pte invalid" MMU fault. The hardware already provides a safe-powerdown sequence for this: request the GMP to stop and wait for outstanding reads/writes to drain (v3d_idle_axi()), plus the GCA safe shutdown on pre-4.1 cores (v3d_idle_gca()). The driver implements both, but the runtime PM support added later never invoked them when powering the GPU down. Perform the safe-powerdown sequence in v3d_power_suspend() before disabling the clock, while the core is still powered. Cc: stable@vger.kernel.org Link: #7443 Link: #7488 Fixes: 17af1d14deaf ("drm/v3d: Introduce Runtime Power Management") Signed-off-by: Maíra Canal <mcanal@igalia.com>
1 parent 9467e93 commit fcb3243

3 files changed

Lines changed: 11 additions & 2 deletions

File tree

drivers/gpu/drm/v3d/v3d_drv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,8 @@ int v3d_gem_init(struct drm_device *dev);
578578
void v3d_gem_destroy(struct drm_device *dev);
579579
void v3d_reset_sms(struct v3d_dev *v3d);
580580
void v3d_reset(struct v3d_dev *v3d);
581+
void v3d_idle_axi(struct v3d_dev *v3d, int core);
582+
void v3d_idle_gca(struct v3d_dev *v3d);
581583
void v3d_invalidate_caches(struct v3d_dev *v3d);
582584
void v3d_clean_caches(struct v3d_dev *v3d);
583585

drivers/gpu/drm/v3d/v3d_gem.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ v3d_init_core(struct v3d_dev *v3d, int core)
3636
V3D_CORE_WRITE(core, V3D_CTL_L2TFLEND, ~0);
3737
}
3838

39-
static void
39+
void
4040
v3d_idle_axi(struct v3d_dev *v3d, int core)
4141
{
4242
if (v3d->ver >= V3D_GEN_71) {
@@ -61,7 +61,7 @@ v3d_idle_axi(struct v3d_dev *v3d, int core)
6161
}
6262
}
6363

64-
static void
64+
void
6565
v3d_idle_gca(struct v3d_dev *v3d)
6666
{
6767
if (v3d->ver >= V3D_GEN_41)

drivers/gpu/drm/v3d/v3d_power.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,15 @@ int v3d_power_suspend(struct device *dev)
5555
/* Always clean V3D caches on shutdown. */
5656
v3d_clean_caches(v3d);
5757

58+
/* Wait until V3D has no active or pending AXI transactions. */
59+
v3d_idle_axi(v3d, 0);
60+
v3d_idle_gca(v3d);
61+
5862
ret = v3d_suspend_sms(v3d);
5963
if (ret) {
64+
/* Staying active: undo the GMP STOP_REQ from v3d_idle_axi(). */
65+
V3D_WRITE(V3D_GMP_CFG(v3d->ver),
66+
V3D_READ(V3D_GMP_CFG(v3d->ver)) & ~V3D_GMP_CFG_STOP_REQ);
6067
v3d_irq_enable(v3d);
6168
return ret;
6269
}

0 commit comments

Comments
 (0)