diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index 9e82dd79c7db59d1da730af1b6ed5354599ad2f4..8c72efcb638ed002bb6303b31a1402b3633a6495 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -24,6 +24,7 @@ #include <linux/sched.h> #include <asm/cputype.h> #include <asm/mmu.h> +#include <soc/imx8/soc.h> /* * Raw TLBI operations. @@ -120,8 +121,12 @@ static inline void flush_tlb_mm(struct mm_struct *mm) unsigned long asid = ASID(mm) << 48; dsb(ishst); - __tlbi(aside1is, asid); - __tlbi_user(aside1is, asid); + if (TKT340553_SW_WORKAROUND && ASID(mm) >> 11) { + __tlbi(vmalle1is); + } else { + __tlbi(aside1is, asid); + __tlbi_user(aside1is, asid); + } dsb(ish); } @@ -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); dsb(ishst); - __tlbi(vale1is, addr); - __tlbi_user(vale1is, addr); + if (TKT340553_SW_WORKAROUND && (uaddr >> 36 || (ASID(vma->vm_mm) >> 12))) { + __tlbi(vmalle1is); + } else { + __tlbi(vale1is, addr); + __tlbi_user(vale1is, addr); + } dsb(ish); } @@ -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 addr; + unsigned long mask = (1 << 20) - 1; if ((end - start) > MAX_TLB_RANGE) { flush_tlb_mm(vma->vm_mm); @@ -156,10 +166,14 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, start = asid | (start >> 12); end = asid | (end >> 12); + mask <<= 24; + dsb(ishst); 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_user(vale1is, addr); } else { @@ -189,8 +203,12 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end end >>= 12; dsb(ishst); - for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) - __tlbi(vaae1is, addr); + for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) { + if (TKT340553_SW_WORKAROUND && addr >> 24) + __tlbi(vmalle1is); + else + __tlbi(vaae1is, addr); + } dsb(ish); isb(); } @@ -204,8 +222,13 @@ static inline void __flush_tlb_pgtable(struct mm_struct *mm, { unsigned long addr = uaddr >> 12 | (ASID(mm) << 48); - __tlbi(vae1is, addr); - __tlbi_user(vae1is, addr); + if (TKT340553_SW_WORKAROUND && (uaddr >> 36 || (ASID(mm) >> 12))) { + __tlbi(vmalle1is); + } else { + __tlbi(vae1is, addr); + __tlbi_user(vae1is, addr); + } + dsb(ish); } diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c index 73733378360e991d7a2138e0bb857817a5699946..0e38e4af6d591a182ef40e227fdf7587c8becab8 100644 --- a/drivers/soc/imx/soc-imx8.c +++ b/drivers/soc/imx/soc-imx8.c @@ -134,9 +134,16 @@ static u32 imx_init_revision_from_scu(void) return rev; } +bool TKT340553_SW_WORKAROUND; + 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)