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

Commit 236cef42 authored by Chintan Pandya's avatar Chintan Pandya
Browse files

iommu: msm: Workaround for SMMU PTE prefetch HW bug



Some SMMU implementation has speculative pre-fetch to
optimize performance by reducing HTW to DDR. MMU-500
also implements such pre-fetching with a limitation
that it cannot identify when to stop pre-fetching.
This results into pre-fetching junk data after the
last PTE from last level of page table. This junk PTE
can result into any SMMU issues like incorrect
translation, permission fault, page fault etc.

Now, to avoid that, we anyway do memset 0 to the entire
page allocated to page table. But we flush only those
entries to DDR which are part of valid mapping. Any
data after the valid page table entries may not be
set to zero as we don't issue explicit flush for them.
And this results into the problem described above.

Do an explicit flush for few guard page table entries
and make sure that they reflect 0 in DDR. This stops
SMMU to do over pre-fetch.

CRs-Fixed: 644219
Change-Id: I4695e50e14d6122356090118e15311797ad5e290
Signed-off-by: default avatarChintan Pandya <cpandya@codeaurora.org>
parent 62bdcef8
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@


#define NUM_FL_PTE      4096
#define NUM_FL_PTE      4096
#define NUM_SL_PTE      256
#define NUM_SL_PTE      256
#define GUARD_PTE       2
#define NUM_TEX_CLASS   8
#define NUM_TEX_CLASS   8


/* First-level page table bits */
/* First-level page table bits */
@@ -173,7 +174,7 @@ static u32 *make_second_level(struct msm_iommu_pt *pt,
		goto fail;
		goto fail;
	}
	}
	memset(sl, 0, SZ_4K);
	memset(sl, 0, SZ_4K);
	clean_pte(sl, sl + NUM_SL_PTE, pt->redirect);
	clean_pte(sl, sl + NUM_SL_PTE + GUARD_PTE, pt->redirect);


	*fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
	*fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
			FL_TYPE_TABLE);
			FL_TYPE_TABLE);
+3 −2
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@
#define NUM_FL_PTE      4   /* First level */
#define NUM_FL_PTE      4   /* First level */
#define NUM_SL_PTE      512 /* Second level */
#define NUM_SL_PTE      512 /* Second level */
#define NUM_TL_PTE      512 /* Third level */
#define NUM_TL_PTE      512 /* Third level */
#define GUARD_PTE       2


#define PTE_SIZE	8
#define PTE_SIZE	8


@@ -191,7 +192,7 @@ static inline u64 *make_second_level_tbl(s32 redirect, u64 *fl_pte)
		goto fail;
		goto fail;
	}
	}
	memset(sl, 0, SZ_4K);
	memset(sl, 0, SZ_4K);
	clean_pte(sl, sl + NUM_SL_PTE, redirect);
	clean_pte(sl, sl + NUM_SL_PTE + GUARD_PTE, redirect);


	/* Leave APTable bits 0 to let next level decide access permissinons */
	/* Leave APTable bits 0 to let next level decide access permissinons */
	*fl_pte = (((phys_addr_t)__pa(sl)) & FLSL_BASE_MASK) | FLSL_TYPE_TABLE;
	*fl_pte = (((phys_addr_t)__pa(sl)) & FLSL_BASE_MASK) | FLSL_TYPE_TABLE;
@@ -209,7 +210,7 @@ static inline u64 *make_third_level_tbl(s32 redirect, u64 *sl_pte)
		goto fail;
		goto fail;
	}
	}
	memset(tl, 0, SZ_4K);
	memset(tl, 0, SZ_4K);
	clean_pte(tl, tl + NUM_TL_PTE, redirect);
	clean_pte(tl, tl + NUM_TL_PTE + GUARD_PTE, redirect);


	/* Leave APTable bits 0 to let next level decide access permissions */
	/* Leave APTable bits 0 to let next level decide access permissions */
	*sl_pte = (((phys_addr_t)__pa(tl)) & FLSL_BASE_MASK) | FLSL_TYPE_TABLE;
	*sl_pte = (((phys_addr_t)__pa(tl)) & FLSL_BASE_MASK) | FLSL_TYPE_TABLE;