diff mbox series

[v6,01/11] drm/v3d: Address race-condition in MMU flush

Message ID 20240923141348.2422499-2-mcanal@igalia.com (mailing list archive)
State New, archived
Headers show
Series drm/v3d: Enable Big and Super Pages | expand

Commit Message

Maíra Canal Sept. 23, 2024, 1:55 p.m. UTC
We must first flush the MMU cache and then, flush the TLB, not the other
way around. Currently, we can see a race condition between the MMU cache
and the TLB when running multiple rendering processes at the same time.
This is evidenced by MMU errors triggered by the IRQ.

Fix the MMU flush order by flushing the MMU cache and then the TLB.
Also, in order to address the race condition, wait for the MMU cache flush
to finish before starting the TLB flush.

Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
 drivers/gpu/drm/v3d/v3d_mmu.c | 29 ++++++++++-------------------
 1 file changed, 10 insertions(+), 19 deletions(-)

Comments

Iago Toral Sept. 24, 2024, 5:27 a.m. UTC | #1
Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>

El lun, 23-09-2024 a las 10:55 -0300, Maíra Canal escribió:
> We must first flush the MMU cache and then, flush the TLB, not the
> other
> way around. Currently, we can see a race condition between the MMU
> cache
> and the TLB when running multiple rendering processes at the same
> time.
> This is evidenced by MMU errors triggered by the IRQ.
> 
> Fix the MMU flush order by flushing the MMU cache and then the TLB.
> Also, in order to address the race condition, wait for the MMU cache
> flush
> to finish before starting the TLB flush.
> 
> Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for
> Broadcom V3D V3.x+")
> Signed-off-by: Maíra Canal <mcanal@igalia.com>
> ---
>  drivers/gpu/drm/v3d/v3d_mmu.c | 29 ++++++++++-------------------
>  1 file changed, 10 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/gpu/drm/v3d/v3d_mmu.c
> b/drivers/gpu/drm/v3d/v3d_mmu.c
> index 14f3af40d6f6..e36ec3343b06 100644
> --- a/drivers/gpu/drm/v3d/v3d_mmu.c
> +++ b/drivers/gpu/drm/v3d/v3d_mmu.c
> @@ -32,32 +32,23 @@ static int v3d_mmu_flush_all(struct v3d_dev *v3d)
>  {
>  	int ret;
>  
> -	/* Make sure that another flush isn't already running when
> we
> -	 * start this one.
> -	 */
> -	ret = wait_for(!(V3D_READ(V3D_MMU_CTL) &
> -			 V3D_MMU_CTL_TLB_CLEARING), 100);
> -	if (ret)
> -		dev_err(v3d->drm.dev, "TLB clear wait idle pre-wait
> failed\n");
> -
> -	V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL) |
> -		  V3D_MMU_CTL_TLB_CLEAR);
> -
> -	V3D_WRITE(V3D_MMUC_CONTROL,
> -		  V3D_MMUC_CONTROL_FLUSH |
> +	V3D_WRITE(V3D_MMUC_CONTROL, V3D_MMUC_CONTROL_FLUSH |
>  		  V3D_MMUC_CONTROL_ENABLE);
>  
> -	ret = wait_for(!(V3D_READ(V3D_MMU_CTL) &
> -			 V3D_MMU_CTL_TLB_CLEARING), 100);
> +	ret = wait_for(!(V3D_READ(V3D_MMUC_CONTROL) &
> +			 V3D_MMUC_CONTROL_FLUSHING), 100);
>  	if (ret) {
> -		dev_err(v3d->drm.dev, "TLB clear wait idle
> failed\n");
> +		dev_err(v3d->drm.dev, "MMUC flush wait idle
> failed\n");
>  		return ret;
>  	}
>  
> -	ret = wait_for(!(V3D_READ(V3D_MMUC_CONTROL) &
> -			 V3D_MMUC_CONTROL_FLUSHING), 100);
> +	V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL) |
> +		  V3D_MMU_CTL_TLB_CLEAR);
> +
> +	ret = wait_for(!(V3D_READ(V3D_MMU_CTL) &
> +			 V3D_MMU_CTL_TLB_CLEARING), 100);
>  	if (ret)
> -		dev_err(v3d->drm.dev, "MMUC flush wait idle
> failed\n");
> +		dev_err(v3d->drm.dev, "MMU TLB clear wait idle
> failed\n");
>  
>  	return ret;
>  }
diff mbox series

Patch

diff --git a/drivers/gpu/drm/v3d/v3d_mmu.c b/drivers/gpu/drm/v3d/v3d_mmu.c
index 14f3af40d6f6..e36ec3343b06 100644
--- a/drivers/gpu/drm/v3d/v3d_mmu.c
+++ b/drivers/gpu/drm/v3d/v3d_mmu.c
@@ -32,32 +32,23 @@  static int v3d_mmu_flush_all(struct v3d_dev *v3d)
 {
 	int ret;
 
-	/* Make sure that another flush isn't already running when we
-	 * start this one.
-	 */
-	ret = wait_for(!(V3D_READ(V3D_MMU_CTL) &
-			 V3D_MMU_CTL_TLB_CLEARING), 100);
-	if (ret)
-		dev_err(v3d->drm.dev, "TLB clear wait idle pre-wait failed\n");
-
-	V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL) |
-		  V3D_MMU_CTL_TLB_CLEAR);
-
-	V3D_WRITE(V3D_MMUC_CONTROL,
-		  V3D_MMUC_CONTROL_FLUSH |
+	V3D_WRITE(V3D_MMUC_CONTROL, V3D_MMUC_CONTROL_FLUSH |
 		  V3D_MMUC_CONTROL_ENABLE);
 
-	ret = wait_for(!(V3D_READ(V3D_MMU_CTL) &
-			 V3D_MMU_CTL_TLB_CLEARING), 100);
+	ret = wait_for(!(V3D_READ(V3D_MMUC_CONTROL) &
+			 V3D_MMUC_CONTROL_FLUSHING), 100);
 	if (ret) {
-		dev_err(v3d->drm.dev, "TLB clear wait idle failed\n");
+		dev_err(v3d->drm.dev, "MMUC flush wait idle failed\n");
 		return ret;
 	}
 
-	ret = wait_for(!(V3D_READ(V3D_MMUC_CONTROL) &
-			 V3D_MMUC_CONTROL_FLUSHING), 100);
+	V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL) |
+		  V3D_MMU_CTL_TLB_CLEAR);
+
+	ret = wait_for(!(V3D_READ(V3D_MMU_CTL) &
+			 V3D_MMU_CTL_TLB_CLEARING), 100);
 	if (ret)
-		dev_err(v3d->drm.dev, "MMUC flush wait idle failed\n");
+		dev_err(v3d->drm.dev, "MMU TLB clear wait idle failed\n");
 
 	return ret;
 }