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:
Rohit Vaswani 2014-09-24 22:18:31 -07:00
parent 0b5fe7577d
commit c161068566
3 changed files with 100 additions and 50 deletions

View File

@ -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>;
};

View File

@ -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();
}
}
/*

View File

@ -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);