From ed12df75f69ebb2a0541b5ea4f3724806ecde1de Mon Sep 17 00:00:00 2001 From: Puranam V G Tejaswi Date: Wed, 11 Nov 2020 22:28:43 +0530 Subject: [PATCH] msm: kgsl: Simplify GBIF halt sequence for stall-on-fault case Currently during stall-on-fault recovery, we keep resuming SMMU and check if GBIF halt succeeded. This is done to recover from a case where a GPU block continuously initiated faulty transactions, which would keep stalling SMMU. If we set CFCFG to 0 as part of handling the first fault, all these transactions will be terminated and will not stall SMMU. This simplifies the GBIF halt sequence and avoids resuming every time. Change-Id: Iada83d6a08e5e0a4f6241b17d1b178ab680f1364 Signed-off-by: Puranam V G Tejaswi --- drivers/gpu/msm/adreno_a6xx.c | 96 +++++++++---------------------- drivers/gpu/msm/adreno_a6xx.h | 11 ---- drivers/gpu/msm/adreno_a6xx_gmu.c | 16 +++--- drivers/gpu/msm/kgsl_iommu.c | 20 +++++++ 4 files changed, 54 insertions(+), 89 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index a6f08740a676..4b796166b1a9 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1264,6 +1264,29 @@ void a6xx_gx_cpr_toggle(struct kgsl_device *device) wmb(); } +/* This is only defined for non-GMU and non-RGMU targets */ +static int a6xx_clear_pending_transactions(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + if (adreno_is_a619_holi(adreno_dev)) { + kgsl_regwrite(device, A6XX_RBBM_GPR0_CNTL, 0x1e0); + ret = adreno_wait_for_halt_ack(device, + A6XX_RBBM_VBIF_GX_RESET_STATUS, 0xf0); + } else { + kgsl_regwrite(device, A6XX_RBBM_GBIF_HALT, + A6XX_GBIF_GX_HALT_MASK); + ret = adreno_wait_for_halt_ack(device, A6XX_RBBM_GBIF_HALT_ACK, + A6XX_GBIF_GX_HALT_MASK); + } + + if (ret) + return ret; + + return a6xx_halt_gbif(adreno_dev); +} + /** * a6xx_reset() - Helper function to reset the GPU * @device: Pointer to the KGSL device structure for the GPU @@ -1277,19 +1300,9 @@ static int a6xx_reset(struct kgsl_device *device) int ret; unsigned long flags = device->pwrctrl.ctrl_flags; - /* - * Stall on fault needs GBIF halt sequences for robust recovery. - * Because in a worst-case scenario, if any of the GPU blocks is - * generating a stream of un-ending faulting transactions, SMMU will - * process those transactions when we try to resume it and enter - * stall-on-fault mode again. GBIF halt sequences make sure that all - * GPU transactions are halted at GBIF which ensures that SMMU - * can resume safely. - */ - a6xx_do_gbif_halt(adreno_dev, A6XX_RBBM_GBIF_HALT, - A6XX_RBBM_GBIF_HALT_ACK, A6XX_GBIF_GX_HALT_MASK, "GX"); - a6xx_do_gbif_halt(adreno_dev, A6XX_GBIF_HALT, A6XX_GBIF_HALT_ACK, - A6XX_GBIF_ARB_HALT_MASK, "CX"); + ret = a6xx_clear_pending_transactions(adreno_dev); + if (ret) + return ret; /* Clear ctrl_flags to ensure clocks and regulators are turned off */ device->pwrctrl.ctrl_flags = 0; @@ -2441,63 +2454,6 @@ u64 a6xx_read_alwayson(struct adreno_device *adreno_dev) return (((u64) hi) << 32) | lo; } -void a6xx_do_gbif_halt(struct adreno_device *adreno_dev, - u32 halt_reg, u32 ack_reg, u32 mask, const char *client) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - unsigned long t; - u32 val; - - kgsl_regwrite(device, halt_reg, mask); - - t = jiffies + msecs_to_jiffies(100); - do { - kgsl_regread(device, ack_reg, &val); - if ((val & mask) == mask) - return; - - /* - * If we are attempting GBIF halt in case of stall-on-fault - * then the halt sequence will not complete as long as SMMU - * is stalled. - */ - kgsl_mmu_pagefault_resume(&device->mmu); - usleep_range(10, 100); - } while (!time_after(jiffies, t)); - - /* Check one last time */ - kgsl_mmu_pagefault_resume(&device->mmu); - - kgsl_regread(device, ack_reg, &val); - if ((val & mask) == mask) - return; - - dev_err(device->dev, "%s GBIF Halt ack timed out\n", client); -} - -/* This is only defined for non-GMU and non-RGMU targets */ -static int a6xx_clear_pending_transactions(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - int ret; - - if (adreno_is_a619_holi(adreno_dev)) { - kgsl_regwrite(device, A6XX_RBBM_GPR0_CNTL, 0x1e0); - ret = adreno_wait_for_halt_ack(device, - A6XX_RBBM_VBIF_GX_RESET_STATUS, 0xf0); - } else { - kgsl_regwrite(device, A6XX_RBBM_GBIF_HALT, - A6XX_GBIF_GX_HALT_MASK); - ret = adreno_wait_for_halt_ack(device, A6XX_RBBM_GBIF_HALT_ACK, - A6XX_GBIF_GX_HALT_MASK); - } - - if (ret) - return ret; - - return a6xx_halt_gbif(adreno_dev); -} - const struct adreno_gpudev adreno_a6xx_gpudev = { .reg_offsets = a6xx_register_offsets, .probe = a6xx_probe, diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index 4c28695cbbf8..a15c1d8f401a 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -317,17 +317,6 @@ int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev); void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev); bool a6xx_gmu_sptprac_is_on(struct adreno_device *adreno_dev); -/** - * a6xx_do_gbif_halt - halt gbif traffic and wait for ack - * @adreno_dev: An Adreno GPU handle - * @halt_reg: reg to trigger gbif halt - * @ack_reg: status register to check for ack - * @mask: mask for ack - * @client: client name - "GX" or "CX" - */ -void a6xx_do_gbif_halt(struct adreno_device *adreno_dev, - u32 halt_reg, u32 ack_reg, u32 mask, const char *client); - /** * a6xx_read_alwayson - Read the current always on clock value * @adreno_dev: An Adreno GPU handle diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 33bcef5d08b0..1ae6d4488b3d 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1617,15 +1617,15 @@ static void a6xx_gmu_pwrctrl_suspend(struct adreno_device *adreno_dev) if (adreno_has_gbif(adreno_dev)) { /* Halt GX traffic */ - if (a6xx_gmu_gx_is_on(device)) - a6xx_do_gbif_halt(adreno_dev, A6XX_RBBM_GBIF_HALT, - A6XX_RBBM_GBIF_HALT_ACK, - A6XX_GBIF_GX_HALT_MASK, - "GX"); - + if (a6xx_gmu_gx_is_on(device)) { + kgsl_regwrite(device, A6XX_RBBM_GBIF_HALT, + A6XX_GBIF_GX_HALT_MASK); + adreno_wait_for_halt_ack(device, + A6XX_RBBM_GBIF_HALT_ACK, + A6XX_GBIF_GX_HALT_MASK); + } /* Halt CX traffic */ - a6xx_do_gbif_halt(adreno_dev, A6XX_GBIF_HALT, A6XX_GBIF_HALT_ACK, - A6XX_GBIF_ARB_HALT_MASK, "CX"); + a6xx_halt_gbif(adreno_dev); } if (a6xx_gmu_gx_is_on(device)) diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 05d05025427b..a1a4e5d151d0 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1747,6 +1747,26 @@ static void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu) struct kgsl_iommu_context *ctx = &iommu->user_context; if (ctx->default_pt != NULL && ctx->stalled_on_fault) { + u32 sctlr_val = KGSL_IOMMU_GET_CTX_REG(ctx, + KGSL_IOMMU_CTX_SCTLR); + + /* + * As part of recovery, GBIF halt sequence should be performed. + * In a worst case scenario, if any GPU block is generating a + * stream of un-ending faulting transactions, SMMU would enter + * stall-on-fault mode again after resuming and not let GBIF + * halt succeed. In order to avoid that situation and terminate + * those faulty transactions, set CFCFG and HUPCF to 0. + */ + sctlr_val &= ~(0x1 << KGSL_IOMMU_SCTLR_CFCFG_SHIFT); + sctlr_val &= ~(0x1 << KGSL_IOMMU_SCTLR_HUPCF_SHIFT); + KGSL_IOMMU_SET_CTX_REG(ctx, KGSL_IOMMU_CTX_SCTLR, sctlr_val); + /* + * Make sure the above register write is not reordered across + * the barrier as we use writel_relaxed to write it. + */ + wmb(); + /* * This will only clear fault bits in FSR. FSR.SS will still * be set. Writing to RESUME (below) is the only way to clear