1
0
Fork 0

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

on i.MX8QM 1.0/1.1,TLB maintenance through DVM messages over ARADDR channel,
some bits (see the following) will be corrupted:

ASID[15:12] VA[48:45] VA[44:41] VA[39:36]

This issue will result in the TLB aintenance across the clusters not working
as expected due to some VA and ASID bits get corrupted

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.

Note: To simplify the code, we did not check VA[40] bit specifically

Signed-off-by: Jason Liu <jason.hui.liu@nxp.com>
Reviewed-by: Anson Huang <anson.huang@nxp.com>
5.4-rM2-2.2.x-imx-squashed
Jason Liu 2019-10-31 14:48:12 +08:00 committed by Dong Aisheng
parent fbfe972a07
commit 593bea4e36
2 changed files with 34 additions and 10 deletions

View File

@ -15,6 +15,8 @@
#include <asm/cputype.h>
#include <asm/mmu.h>
extern bool TKT340553_SW_WORKAROUND;
/*
* Raw TLBI operations.
*
@ -149,8 +151,12 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
unsigned long asid = __TLBI_VADDR(0, ASID(mm));
dsb(ishst);
__tlbi(aside1is, asid);
__tlbi_user(aside1is, asid);
if (TKT340553_SW_WORKAROUND && ASID(mm) >> 12) {
__tlbi(vmalle1is);
} else {
__tlbi(aside1is, asid);
__tlbi_user(aside1is, asid);
}
dsb(ish);
}
@ -160,8 +166,12 @@ static inline void flush_tlb_page_nosync(struct vm_area_struct *vma,
unsigned long addr = __TLBI_VADDR(uaddr, ASID(vma->vm_mm));
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);
}
}
static inline void flush_tlb_page(struct vm_area_struct *vma,
@ -183,6 +193,7 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
{
unsigned long asid = ASID(vma->vm_mm);
unsigned long addr;
unsigned long mask = (1 << 20) - 1;
start = round_down(start, stride);
end = round_up(end, stride);
@ -197,10 +208,13 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
start = __TLBI_VADDR(start, asid);
end = __TLBI_VADDR(end, asid);
mask <<= 24;
dsb(ishst);
for (addr = start; addr < end; addr += stride) {
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 {
@ -234,8 +248,12 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
end = __TLBI_VADDR(end, 0);
dsb(ishst);
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
__tlbi(vaale1is, addr);
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) {
if (TKT340553_SW_WORKAROUND && addr >> 24)
__tlbi(vmalle1is);
else
__tlbi(vaale1is, addr);
}
dsb(ish);
isb();
}
@ -249,7 +267,10 @@ static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)
unsigned long addr = __TLBI_VADDR(kaddr, 0);
dsb(ishst);
__tlbi(vaae1is, addr);
if (TKT340553_SW_WORKAROUND && addr >> 24)
__tlbi(vmalle1is);
else
__tlbi(vaae1is, addr);
dsb(ish);
isb();
}

View File

@ -12,6 +12,8 @@
#define IMX_SCU_SOC_DRIVER_NAME "imx-scu-soc"
bool TKT340553_SW_WORKAROUND;
static struct imx_sc_ipc *soc_ipc_handle;
struct imx_sc_msg_misc_get_soc_id {
@ -114,9 +116,10 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
/* format soc_id value passed from SCU firmware */
val = id & 0x1f;
if (of_machine_is_compatible("fsl,imx8qm"))
if (of_machine_is_compatible("fsl,imx8qm")) {
soc_dev_attr->soc_id = "i.MX8QM";
else if (of_machine_is_compatible("fsl,imx8qxp"))
TKT340553_SW_WORKAROUND = true;
} else if (of_machine_is_compatible("fsl,imx8qxp"))
soc_dev_attr->soc_id = "i.MX8QXP";
/* format revision value passed from SCU firmware */