arm64: Implement the 8994_TLBI_WA by checking the HW SOC version
8994 V2 does not have the TLB invalidate bug (CONFIG_ARCH_MSM8994_V1_TLBI_WA). Use the HW SOC version register to detect if we are running on V2 and determine if the workaround needs to be applied. Change-Id: I2635bccb7902fb65c717d56ea9df6ad95f2ca5f7 Signed-off-by: Rohit Vaswani <rvaswani@codeaurora.org>
This commit is contained in:
parent
0b5fe7577d
commit
c161068566
|
@ -0,0 +1,14 @@
|
|||
*CPUSS-8994
|
||||
|
||||
CPUSS refers to the CPU sub-system and this node provides the base address to the CPU sub-system
|
||||
registers like TCSR_HW_SOC_VERSION which contain the CPU SOC VERSION for 8994 and variant chips.
|
||||
|
||||
compatible: Must be "qcom,cpuss-8994"
|
||||
reg: Base Address for the CPUSS
|
||||
|
||||
Example:
|
||||
tss@fd4a8000 {
|
||||
compatible = "qcom,cpuss-8994";
|
||||
reg = <0xfd4a8000 0x4>;
|
||||
};
|
||||
|
|
@ -78,77 +78,87 @@ static inline void flush_tlb_all(void)
|
|||
isb();
|
||||
}
|
||||
|
||||
static inline void flush_tlb_mm(struct mm_struct *mm)
|
||||
static inline bool msm8994_needs_tlbi_wa(void)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_MSM8994_V1_TLBI_WA
|
||||
dsb(ishst);
|
||||
asm("tlbi vmalle1is");
|
||||
dsb(ish);
|
||||
isb();
|
||||
extern int msm8994_req_tlbi_wa;
|
||||
return msm8994_req_tlbi_wa;
|
||||
#else
|
||||
unsigned long asid = (unsigned long)ASID(mm) << 48;
|
||||
|
||||
dsb(ishst);
|
||||
asm("tlbi aside1is, %0" : : "r" (asid));
|
||||
dsb(ish);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void flush_tlb_mm(struct mm_struct *mm)
|
||||
{
|
||||
if (msm8994_needs_tlbi_wa()) {
|
||||
dsb(ishst);
|
||||
asm("tlbi vmalle1is");
|
||||
dsb(ish);
|
||||
isb();
|
||||
} else {
|
||||
unsigned long asid = (unsigned long)ASID(mm) << 48;
|
||||
|
||||
dsb(ishst);
|
||||
asm("tlbi aside1is, %0" : : "r" (asid));
|
||||
dsb(ish);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void flush_tlb_page(struct vm_area_struct *vma,
|
||||
unsigned long uaddr)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_MSM8994_V1_TLBI_WA
|
||||
dsb(ishst);
|
||||
asm("tlbi vmalle1is");
|
||||
dsb(ish);
|
||||
isb();
|
||||
#else
|
||||
unsigned long addr = uaddr >> 12 |
|
||||
((unsigned long)ASID(vma->vm_mm) << 48);
|
||||
if (msm8994_needs_tlbi_wa()) {
|
||||
dsb(ishst);
|
||||
asm("tlbi vmalle1is");
|
||||
dsb(ish);
|
||||
isb();
|
||||
} else {
|
||||
unsigned long addr = uaddr >> 12 |
|
||||
((unsigned long)ASID(vma->vm_mm) << 48);
|
||||
|
||||
dsb(ishst);
|
||||
asm("tlbi vae1is, %0" : : "r" (addr));
|
||||
dsb(ish);
|
||||
#endif
|
||||
dsb(ishst);
|
||||
asm("tlbi vae1is, %0" : : "r" (addr));
|
||||
dsb(ish);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __flush_tlb_range(struct vm_area_struct *vma,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_MSM8994_V1_TLBI_WA
|
||||
asm("tlbi vmalle1is");
|
||||
dsb(sy);
|
||||
isb();
|
||||
#else
|
||||
unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48;
|
||||
unsigned long addr;
|
||||
start = asid | (start >> 12);
|
||||
end = asid | (end >> 12);
|
||||
if (msm8994_needs_tlbi_wa()) {
|
||||
asm("tlbi vmalle1is");
|
||||
dsb(sy);
|
||||
isb();
|
||||
} else {
|
||||
unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48;
|
||||
unsigned long addr;
|
||||
start = asid | (start >> 12);
|
||||
end = asid | (end >> 12);
|
||||
|
||||
dsb(ishst);
|
||||
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
|
||||
asm("tlbi vae1is, %0" : : "r"(addr));
|
||||
dsb(ish);
|
||||
#endif
|
||||
dsb(ishst);
|
||||
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
|
||||
asm("tlbi vae1is, %0" : : "r"(addr));
|
||||
dsb(ish);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_MSM8994_V1_TLBI_WA
|
||||
asm("tlbi vmalle1is");
|
||||
dsb(sy);
|
||||
isb();
|
||||
#else
|
||||
unsigned long addr;
|
||||
start >>= 12;
|
||||
end >>= 12;
|
||||
if (msm8994_needs_tlbi_wa()) {
|
||||
asm("tlbi vmalle1is");
|
||||
dsb(sy);
|
||||
isb();
|
||||
} else {
|
||||
unsigned long addr;
|
||||
start >>= 12;
|
||||
end >>= 12;
|
||||
|
||||
dsb(ishst);
|
||||
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
|
||||
asm("tlbi vaae1is, %0" : : "r"(addr));
|
||||
dsb(ish);
|
||||
isb();
|
||||
#endif
|
||||
dsb(ishst);
|
||||
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
|
||||
asm("tlbi vaae1is, %0" : : "r"(addr));
|
||||
dsb(ish);
|
||||
isb();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
@ -534,3 +535,28 @@ void arch_setup_pdev_archdata(struct platform_device *pdev)
|
|||
pdev->archdata.dma_mask = DMA_BIT_MASK(32);
|
||||
pdev->dev.dma_mask = &pdev->archdata.dma_mask;
|
||||
}
|
||||
|
||||
/* Used for 8994 Only */
|
||||
int msm8994_req_tlbi_wa = 1;
|
||||
#define SOC_MAJOR_REV(val) (((val) & 0xF00) >> 8)
|
||||
|
||||
static int __init msm8994_check_tlbi_workaround(void)
|
||||
{
|
||||
void __iomem *addr;
|
||||
int major_rev;
|
||||
struct device_node *dn = of_find_compatible_node(NULL,
|
||||
NULL, "qcom,cpuss-8994");
|
||||
if (dn) {
|
||||
addr = of_iomap(dn, 0);
|
||||
if (!addr)
|
||||
return -ENOMEM;
|
||||
major_rev = SOC_MAJOR_REV((__raw_readl(addr)));
|
||||
msm8994_req_tlbi_wa = (major_rev >= 2) ? 0 : 1;
|
||||
} else {
|
||||
/* If the node does not exist disable the workaround */
|
||||
msm8994_req_tlbi_wa = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall_sync(msm8994_check_tlbi_workaround);
|
||||
|
|
Loading…
Reference in New Issue