diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index e5dde885f890..5dae8152f4c3 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1104,6 +1104,9 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, /* Populate the GMU version info before GMU boots */ load_gmu_version_info(device); + /* Clear any previously set cm3 fault */ + atomic_set(&gmu->cm3_fault, 0); + ret = a6xx_gmu_start(device); if (ret) return ret; diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 98b0b0688e72..f7b28d9a70a3 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -1014,7 +1014,17 @@ static irqreturn_t gmu_irq_handler(int irq, void *data) ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK, (mask | GMU_INT_WDOG_BITE)); - adreno_gmu_send_nmi(adreno_dev); + /* make sure we're reading the latest cm3_fault */ + smp_rmb(); + + /* + * We should not send NMI if there was a CM3 fault reported + * because we don't want to overwrite the critical CM3 state + * captured by gmu before it sent the CM3 fault interrupt. + */ + if (!atomic_read(&gmu->cm3_fault)) + adreno_gmu_send_nmi(adreno_dev); + /* * There is sufficient delay for the GMU to have finished * handling the NMI before snapshot is taken, as the fault @@ -1532,9 +1542,21 @@ static void gmu_snapshot(struct kgsl_device *device) if (test_and_set_bit(GMU_FAULT, &device->gmu_core.flags)) return; - adreno_gmu_send_nmi(adreno_dev); - /* Wait for the NMI to be handled */ - udelay(100); + /* make sure we're reading the latest cm3_fault */ + smp_rmb(); + + /* + * We should not send NMI if there was a CM3 fault reported because we + * don't want to overwrite the critical CM3 state captured by gmu before + * it sent the CM3 fault interrupt. + */ + if (!atomic_read(&gmu->cm3_fault)) { + adreno_gmu_send_nmi(adreno_dev); + + /* Wait for the NMI to be handled */ + udelay(100); + } + kgsl_device_snapshot(device, NULL, true); adreno_write_gmureg(adreno_dev, diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 312f7d5256d5..7c6ca7e03b5c 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -210,6 +210,8 @@ struct gmu_device { unsigned long kmem_bitmap; const struct gmu_vma_entry *vma; unsigned int log_wptr_retention; + /** @cm3_fault: whether gmu received a cm3 fault interrupt */ + atomic_t cm3_fault; }; struct gmu_memdesc *gmu_get_memdesc(struct gmu_device *gmu, diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 04f1212b9c27..a7c5f3a307a5 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -852,9 +852,14 @@ irqreturn_t hfi_irq_handler(int irq, void *data) if (status & HFI_IRQ_DBGQ_MASK) tasklet_hi_schedule(&hfi->tasklet); - if (status & HFI_IRQ_CM3_FAULT_MASK) + if (status & HFI_IRQ_CM3_FAULT_MASK) { dev_err_ratelimited(&gmu->pdev->dev, "GMU CM3 fault interrupt received\n"); + atomic_set(&gmu->cm3_fault, 1); + + /* make sure other CPUs see the update */ + smp_wmb(); + } if (status & ~HFI_IRQ_MASK) dev_err_ratelimited(&gmu->pdev->dev, "Unhandled HFI interrupts 0x%lx\n",