Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed12df75 authored by Puranam V G Tejaswi's avatar Puranam V G Tejaswi
Browse files

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: default avatarPuranam V G Tejaswi <pvgtejas@codeaurora.org>
parent 58329ca1
Loading
Loading
Loading
Loading
+26 −70
Original line number Diff line number Diff line
@@ -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,
+0 −11
Original line number Diff line number Diff line
@@ -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
+8 −8
Original line number Diff line number Diff line
@@ -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,
		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,
				"GX");

					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))
+20 −0
Original line number Diff line number Diff line
@@ -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