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

Commit 4d611424 authored by Harshdeep Dhatt's avatar Harshdeep Dhatt
Browse files

msm: kgsl: Perform reset sequence during recovery on a6xx



On targets which have GMU, it is recommended to halt GBIF GX
and CX and soft reset the GPU to make recovery more robust.
This sequence also helps to recover successfully in case of
stall-on-fault.

Change-Id: Ie642a8f99aa6f4aca7c31f7e769d1ef14b4b60df
Signed-off-by: default avatarHarshdeep Dhatt <hdhatt@codeaurora.org>
parent cd914bbc
Loading
Loading
Loading
Loading
+56 −1
Original line number Diff line number Diff line
@@ -1156,13 +1156,48 @@ static int a6xx_gmu_load_firmware(struct kgsl_device *device)

#define A6XX_VBIF_XIN_HALT_CTRL1_ACKS   (BIT(0) | BIT(1) | BIT(2) | BIT(3))

static void do_gbif_halt(struct kgsl_device *device, u32 reg, u32 ack_reg,
	u32 mask, const char *client)
{
	u32 ack;
	unsigned long t;

	kgsl_regwrite(device, reg, mask);

	t = jiffies + msecs_to_jiffies(100);
	do {
		kgsl_regread(device, ack_reg, &ack);
		if ((ack & mask) == mask)
			return;

		/*
		 * If we are attempting recovery 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, &ack);
	if ((ack & mask) == mask)
		return;

	dev_err(device->dev, "%s GBIF halt timed out\n", client);
}

static int a6xx_gmu_suspend(struct kgsl_device *device)
{
	int ret = 0;
	struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	/* If SPTP_RAC is on, turn off SPTP_RAC HS */
	a6xx_gmu_sptprac_disable(ADRENO_DEVICE(device));
	a6xx_gmu_sptprac_disable(adreno_dev);

	/* Disconnect GPU from BUS is not needed if CX GDSC goes off later */

@@ -1176,6 +1211,26 @@ static int a6xx_gmu_suspend(struct kgsl_device *device)
	/* Make sure above writes are committed before we proceed to recovery */
	wmb();

	gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1);

	if (adreno_has_gbif(adreno_dev)) {
		struct adreno_gpudev *gpudev =
			ADRENO_GPU_DEVICE(adreno_dev);

		/* Halt GX traffic */
		do_gbif_halt(device, A6XX_RBBM_GBIF_HALT,
			A6XX_RBBM_GBIF_HALT_ACK, gpudev->gbif_gx_halt_mask,
			"GX");
		/* Halt CX traffic */
		do_gbif_halt(device, A6XX_GBIF_HALT, A6XX_GBIF_HALT_ACK,
			gpudev->gbif_arb_halt_mask, "CX");
	}

	kgsl_regwrite(device, A6XX_RBBM_SW_RESET_CMD, 0x1);

	/* Allow the software reset to complete */
	udelay(100);

	/*
	 * This is based on the assumption that GMU is the only one controlling
	 * the GX HS. This code path is the only client voting for GX through
+29 −39
Original line number Diff line number Diff line
@@ -791,8 +791,6 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
	if (pt->name == KGSL_MMU_SECURE_PT)
		ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE];

	ctx->fault = 1;

	if (test_bit(KGSL_FT_PAGEFAULT_GPUHALT_ENABLE,
		&adreno_dev->ft_pf_policy) &&
		(flags & IOMMU_FAULT_TRANSACTION_STALLED)) {
@@ -883,6 +881,9 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
		sctlr_val &= ~(0x1 << KGSL_IOMMU_SCTLR_CFIE_SHIFT);
		KGSL_IOMMU_SET_CTX_REG(ctx, SCTLR, sctlr_val);

		/* This is used by reset/recovery path */
		ctx->stalled_on_fault = true;

		adreno_set_gpu_fault(adreno_dev, ADRENO_IOMMU_PAGE_FAULT);
		/* Go ahead with recovery*/
		adreno_dispatcher_schedule(device);
@@ -1986,7 +1987,7 @@ static void kgsl_iommu_clear_fsr(struct kgsl_mmu *mmu)
	struct kgsl_iommu_context  *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER];
	unsigned int sctlr_val;

	if (ctx->default_pt != NULL) {
	if (ctx->default_pt != NULL && ctx->stalled_on_fault) {
		kgsl_iommu_enable_clk(mmu);
		KGSL_IOMMU_SET_CTX_REG(ctx, FSR, 0xffffffff);
		/*
@@ -2003,6 +2004,7 @@ static void kgsl_iommu_clear_fsr(struct kgsl_mmu *mmu)
		 */
		wmb();
		kgsl_iommu_disable_clk(mmu);
		ctx->stalled_on_fault = false;
	}
}

@@ -2010,42 +2012,30 @@ static void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu)
{
	struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu);
	struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER];
	unsigned int fsr_val;

	if (ctx->default_pt != NULL && ctx->fault) {
		while (1) {
	if (ctx->default_pt != NULL && ctx->stalled_on_fault) {
		/*
		 * This will only clear fault bits in FSR. FSR.SS will still
		 * be set. Writing to RESUME (below) is the only way to clear
		 * FSR.SS bit.
		 */
		KGSL_IOMMU_SET_CTX_REG(ctx, FSR, 0xffffffff);
		/*
			 * Make sure the above register write
			 * is not reordered across the barrier
			 * as we use writel_relaxed to write it.
		 * Make sure the above register write is not reordered across
		 * the barrier as we use writel_relaxed to write it.
		 */
		wmb();

		/*
			 * Write 1 to RESUME.TnR to terminate the
			 * stalled transaction.
		 * Write 1 to RESUME.TnR to terminate the stalled transaction.
		 * This will also allow the SMMU to process new transactions.
		 */
		KGSL_IOMMU_SET_CTX_REG(ctx, RESUME, 1);
		/*
			 * Make sure the above register writes
			 * are not reordered across the barrier
			 * as we use writel_relaxed to write them
		 * Make sure the above register writes are not reordered across
		 * the barrier as we use writel_relaxed to write them.
		 */
		wmb();

			/*
			 * Wait for small time before checking SS bit
			 * to allow transactions to go through after
			 * resume and update SS bit in case more faulty
			 * transactions are pending.
			 */
			udelay(5);
			fsr_val = KGSL_IOMMU_GET_CTX_REG(ctx, FSR);
			if (!(fsr_val & (1 << KGSL_IOMMU_FSR_SS_SHIFT)))
				break;
		}
		ctx->fault = 0;
	}
}

+3 −3
Original line number Diff line number Diff line
@@ -86,8 +86,8 @@ enum kgsl_iommu_context_id {
 * @cb_num: The hardware context bank number, used for calculating register
 *		offsets.
 * @kgsldev: The kgsl device that uses this context.
 * @fault: Flag when set indicates that this iommu device has caused a page
 * fault
 * @stalled_on_fault: Flag when set indicates that this iommu device is stalled
 * on a page fault
 * @default_pt: The default pagetable for this context,
 *		it may be changed by self programming.
 */
@@ -97,7 +97,7 @@ struct kgsl_iommu_context {
	enum kgsl_iommu_context_id id;
	unsigned int cb_num;
	struct kgsl_device *kgsldev;
	int fault;
	bool stalled_on_fault;
	void __iomem *regbase;
	struct kgsl_pagetable *default_pt;
};