summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2018-11-05 10:35:12 +0800
committerLey Foon Tan <ley.foon.tan@intel.com>2019-03-07 05:29:35 +0800
commit3437d3c886ed07863acde923a627395abb177aa9 (patch)
treeaf1a7cb90e1689ec8fc31aa49cc7f501e5047997 /arch
parent0b5754b9869ba00dd4489c9d58a342cba7d6f69f (diff)
nios2: Use an invalid TLB entry address helper function
There is no need for complicated calculation for an invalid address that maps to the same TLB index as the entry to be invalidated. Using the TLB address plus the two top bits set puts the address into the kernel TLB bypass range and still maps to the same cache line. This is also a bug fix for flush_tlb_pid, which is currently unused, but does not set PTEADDR to invalid. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/nios2/mm/tlb.c68
1 files changed, 33 insertions, 35 deletions
diff --git a/arch/nios2/mm/tlb.c b/arch/nios2/mm/tlb.c
index 99e047082993..eb568a919576 100644
--- a/arch/nios2/mm/tlb.c
+++ b/arch/nios2/mm/tlb.c
@@ -23,10 +23,6 @@
((((1UL << (cpuinfo.tlb_ptr_sz - cpuinfo.tlb_num_ways_log2))) - 1) \
<< PAGE_SHIFT)
-/* Used as illegal PHYS_ADDR for TLB mappings
- */
-#define MAX_PHYS_ADDR 0
-
static void get_misc_and_pid(unsigned long *misc, unsigned long *pid)
{
*misc = RDCTL(CTL_TLBMISC);
@@ -35,6 +31,15 @@ static void get_misc_and_pid(unsigned long *misc, unsigned long *pid)
}
/*
+ * This provides a PTEADDR value for addr that will cause a TLB miss
+ * (fast TLB miss). TLB invalidation replaces entries with this value.
+ */
+static unsigned long pteaddr_invalid(unsigned long addr)
+{
+ return ((addr | 0xC0000000UL) >> PAGE_SHIFT) << 2;
+}
+
+/*
* All entries common to a mm share an asid. To effectively flush these
* entries, we just bump the asid.
*/
@@ -74,17 +79,14 @@ void flush_tlb_one_pid(unsigned long addr, unsigned long mmu_pid)
pid = (tlbmisc >> TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK;
if (((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) &&
pid == mmu_pid) {
- unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE +
- ((PAGE_SIZE * cpuinfo.tlb_num_lines) * way) +
- (addr & TLB_INDEX_MASK);
- pr_debug("Flush entry by writing %#lx way=%dl pid=%ld\n",
- vaddr, way, (pid_misc >> TLBMISC_PID_SHIFT));
+ pr_debug("Flush entry by writing way=%dl pid=%ld\n",
+ way, (pid_misc >> TLBMISC_PID_SHIFT));
- WRCTL(CTL_PTEADDR, (vaddr >> 12) << 2);
+ WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
tlbmisc = pid_misc | TLBMISC_WE |
(way << TLBMISC_WAY_SHIFT);
WRCTL(CTL_TLBMISC, tlbmisc);
- WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT));
+ WRCTL(CTL_TLBACC, 0);
}
}
@@ -128,18 +130,14 @@ static void flush_tlb_one(unsigned long addr)
tlbmisc = RDCTL(CTL_TLBMISC);
if ((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) {
- unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE +
- ((PAGE_SIZE * cpuinfo.tlb_num_lines) * way) +
- (addr & TLB_INDEX_MASK);
-
- pr_debug("Flush entry by writing %#lx way=%dl pid=%ld\n",
- vaddr, way, (pid_misc >> TLBMISC_PID_SHIFT));
+ pr_debug("Flush entry by writing way=%dl pid=%ld\n",
+ way, (pid_misc >> TLBMISC_PID_SHIFT));
+ WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
tlbmisc = pid_misc | TLBMISC_WE |
(way << TLBMISC_WAY_SHIFT);
- WRCTL(CTL_PTEADDR, (vaddr >> 12) << 2);
WRCTL(CTL_TLBMISC, tlbmisc);
- WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT));
+ WRCTL(CTL_TLBACC, 0);
}
}
@@ -177,7 +175,7 @@ void dump_tlb_line(unsigned long line)
tlbmisc = RDCTL(CTL_TLBMISC);
tlbacc = RDCTL(CTL_TLBACC);
- if ((tlbacc << PAGE_SHIFT) != (MAX_PHYS_ADDR & PAGE_MASK)) {
+ if ((tlbacc << PAGE_SHIFT) != 0) {
pr_debug("-- way:%02x vpn:0x%08lx phys:0x%08lx pid:0x%02lx flags:%c%c%c%c%c\n",
way,
(pteaddr << (PAGE_SHIFT-2)),
@@ -205,6 +203,7 @@ void dump_tlb(void)
void flush_tlb_pid(unsigned long pid)
{
+ unsigned long addr = 0;
unsigned int line;
unsigned int way;
unsigned long org_misc, pid_misc;
@@ -213,38 +212,35 @@ void flush_tlb_pid(unsigned long pid)
get_misc_and_pid(&org_misc, &pid_misc);
for (line = 0; line < cpuinfo.tlb_num_lines; line++) {
- WRCTL(CTL_PTEADDR, line << 2);
+ WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
- unsigned long pteaddr;
unsigned long tlbmisc;
- unsigned long tlbacc;
tlbmisc = pid_misc | TLBMISC_RD |
(way << TLBMISC_WAY_SHIFT);
WRCTL(CTL_TLBMISC, tlbmisc);
- pteaddr = RDCTL(CTL_PTEADDR);
tlbmisc = RDCTL(CTL_TLBMISC);
- tlbacc = RDCTL(CTL_TLBACC);
if (((tlbmisc>>TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK)
== pid) {
tlbmisc = pid_misc | TLBMISC_WE |
(way << TLBMISC_WAY_SHIFT);
WRCTL(CTL_TLBMISC, tlbmisc);
- WRCTL(CTL_TLBACC,
- (MAX_PHYS_ADDR >> PAGE_SHIFT));
+ WRCTL(CTL_TLBACC, 0);
}
}
+ addr += PAGE_SIZE;
+
WRCTL(CTL_TLBMISC, org_misc);
}
}
void flush_tlb_all(void)
{
- int i;
- unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE;
+ unsigned long addr = 0;
+ unsigned int line;
unsigned int way;
unsigned long org_misc, pid_misc, tlbmisc;
@@ -254,14 +250,16 @@ void flush_tlb_all(void)
/* Map each TLB entry to physcal address 0 with no-access and a
bad ptbase */
- for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
- tlbmisc = pid_misc | (way << TLBMISC_WAY_SHIFT);
- for (i = 0; i < cpuinfo.tlb_num_lines; i++) {
- WRCTL(CTL_PTEADDR, ((vaddr) >> PAGE_SHIFT) << 2);
+ for (line = 0; line < cpuinfo.tlb_num_lines; line++) {
+ WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
+
+ for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
+ tlbmisc = pid_misc | (way << TLBMISC_WAY_SHIFT);
WRCTL(CTL_TLBMISC, tlbmisc);
- WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT));
- vaddr += 1UL << 12;
+ WRCTL(CTL_TLBACC, 0);
}
+
+ addr += PAGE_SIZE;
}
/* restore pid/way */