Skip to content
Snippets Groups Projects
Commit c9eb1788 authored by Jason Liu's avatar Jason Liu
Browse files

MLK-16005-2 arm64: tlb: add the SW workaround for i.MX8QM TKT340553


on i.MX8QM TO1.0, there is an issue: the bus width between A53-CCI-A72
is limited to 36bits.TLB maintenance through DVM messages over AR channel,
some bits will be forced(truncated) to zero as the followings:

ASID[15:12] is forced to 0
VA[48:45] is forced to 0
VA[44:41] is forced to 0
VA[39:36] is forced to 0

This issue will result in the TLB aintenance across the clusters not working
as expected due to some VA and ASID bits get truncated and forced to be zero.

The SW workaround is: use the vmalle1is if VA larger than 36bits or
ASID[15:12] is not zero, otherwise, we use original TLB maintenance path.

Signed-off-by: default avatarJason Liu <jason.hui.liu@nxp.com>
Reviewed-by: default avatarAnson Huang <anson.huang@nxp.com>
parent 4c998a8e
No related branches found
No related tags found
No related merge requests found
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/mmu.h> #include <asm/mmu.h>
#include <soc/imx8/soc.h>
/* /*
* Raw TLBI operations. * Raw TLBI operations.
...@@ -120,8 +121,12 @@ static inline void flush_tlb_mm(struct mm_struct *mm) ...@@ -120,8 +121,12 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
unsigned long asid = ASID(mm) << 48; unsigned long asid = ASID(mm) << 48;
dsb(ishst); dsb(ishst);
__tlbi(aside1is, asid); if (TKT340553_SW_WORKAROUND && ASID(mm) >> 11) {
__tlbi_user(aside1is, asid); __tlbi(vmalle1is);
} else {
__tlbi(aside1is, asid);
__tlbi_user(aside1is, asid);
}
dsb(ish); dsb(ish);
} }
...@@ -131,8 +136,12 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, ...@@ -131,8 +136,12 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long addr = uaddr >> 12 | (ASID(vma->vm_mm) << 48); unsigned long addr = uaddr >> 12 | (ASID(vma->vm_mm) << 48);
dsb(ishst); dsb(ishst);
__tlbi(vale1is, addr); if (TKT340553_SW_WORKAROUND && (uaddr >> 36 || (ASID(vma->vm_mm) >> 12))) {
__tlbi_user(vale1is, addr); __tlbi(vmalle1is);
} else {
__tlbi(vale1is, addr);
__tlbi_user(vale1is, addr);
}
dsb(ish); dsb(ish);
} }
...@@ -148,6 +157,7 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, ...@@ -148,6 +157,7 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
{ {
unsigned long asid = ASID(vma->vm_mm) << 48; unsigned long asid = ASID(vma->vm_mm) << 48;
unsigned long addr; unsigned long addr;
unsigned long mask = (1 << 20) - 1;
if ((end - start) > MAX_TLB_RANGE) { if ((end - start) > MAX_TLB_RANGE) {
flush_tlb_mm(vma->vm_mm); flush_tlb_mm(vma->vm_mm);
...@@ -156,10 +166,14 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, ...@@ -156,10 +166,14 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
start = asid | (start >> 12); start = asid | (start >> 12);
end = asid | (end >> 12); end = asid | (end >> 12);
mask <<= 24;
dsb(ishst); dsb(ishst);
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) { for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) {
if (last_level) { if (TKT340553_SW_WORKAROUND && (addr & mask || (ASID(vma->vm_mm) >> 12))) {
__tlbi(vmalle1is);
} else if (last_level) {
__tlbi(vale1is, addr); __tlbi(vale1is, addr);
__tlbi_user(vale1is, addr); __tlbi_user(vale1is, addr);
} else { } else {
...@@ -189,8 +203,12 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end ...@@ -189,8 +203,12 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
end >>= 12; end >>= 12;
dsb(ishst); dsb(ishst);
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) {
__tlbi(vaae1is, addr); if (TKT340553_SW_WORKAROUND && addr >> 24)
__tlbi(vmalle1is);
else
__tlbi(vaae1is, addr);
}
dsb(ish); dsb(ish);
isb(); isb();
} }
...@@ -204,8 +222,13 @@ static inline void __flush_tlb_pgtable(struct mm_struct *mm, ...@@ -204,8 +222,13 @@ static inline void __flush_tlb_pgtable(struct mm_struct *mm,
{ {
unsigned long addr = uaddr >> 12 | (ASID(mm) << 48); unsigned long addr = uaddr >> 12 | (ASID(mm) << 48);
__tlbi(vae1is, addr); if (TKT340553_SW_WORKAROUND && (uaddr >> 36 || (ASID(mm) >> 12))) {
__tlbi_user(vae1is, addr); __tlbi(vmalle1is);
} else {
__tlbi(vae1is, addr);
__tlbi_user(vae1is, addr);
}
dsb(ish); dsb(ish);
} }
......
...@@ -134,9 +134,16 @@ static u32 imx_init_revision_from_scu(void) ...@@ -134,9 +134,16 @@ static u32 imx_init_revision_from_scu(void)
return rev; return rev;
} }
bool TKT340553_SW_WORKAROUND;
static u32 imx8qm_soc_revision(void) static u32 imx8qm_soc_revision(void)
{ {
return imx_init_revision_from_scu(); u32 rev = imx_init_revision_from_scu();
if (rev == IMX_CHIP_REVISION_1_0)
TKT340553_SW_WORKAROUND = true;
return rev;
} }
static u32 imx8qxp_soc_revision(void) static u32 imx8qxp_soc_revision(void)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment