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>
This commit is contained in:
Nicholas Piggin 2018-11-05 10:35:12 +08:00 committed by Ley Foon Tan
parent 0b5754b986
commit 3437d3c886
1 changed files with 33 additions and 35 deletions

View File

@ -23,10 +23,6 @@
((((1UL << (cpuinfo.tlb_ptr_sz - cpuinfo.tlb_num_ways_log2))) - 1) \ ((((1UL << (cpuinfo.tlb_ptr_sz - cpuinfo.tlb_num_ways_log2))) - 1) \
<< PAGE_SHIFT) << 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) static void get_misc_and_pid(unsigned long *misc, unsigned long *pid)
{ {
*misc = RDCTL(CTL_TLBMISC); *misc = RDCTL(CTL_TLBMISC);
@ -34,6 +30,15 @@ static void get_misc_and_pid(unsigned long *misc, unsigned long *pid)
*pid = *misc & TLBMISC_PID; *pid = *misc & TLBMISC_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 * All entries common to a mm share an asid. To effectively flush these
* entries, we just bump the asid. * 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; pid = (tlbmisc >> TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK;
if (((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) && if (((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) &&
pid == mmu_pid) { pid == mmu_pid) {
unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE + pr_debug("Flush entry by writing way=%dl pid=%ld\n",
((PAGE_SIZE * cpuinfo.tlb_num_lines) * way) + way, (pid_misc >> TLBMISC_PID_SHIFT));
(addr & TLB_INDEX_MASK);
pr_debug("Flush entry by writing %#lx way=%dl pid=%ld\n",
vaddr, way, (pid_misc >> TLBMISC_PID_SHIFT));
WRCTL(CTL_PTEADDR, (vaddr >> 12) << 2); WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
tlbmisc = pid_misc | TLBMISC_WE | tlbmisc = pid_misc | TLBMISC_WE |
(way << TLBMISC_WAY_SHIFT); (way << TLBMISC_WAY_SHIFT);
WRCTL(CTL_TLBMISC, tlbmisc); 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); tlbmisc = RDCTL(CTL_TLBMISC);
if ((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) { if ((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) {
unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE + pr_debug("Flush entry by writing way=%dl pid=%ld\n",
((PAGE_SIZE * cpuinfo.tlb_num_lines) * way) + way, (pid_misc >> TLBMISC_PID_SHIFT));
(addr & TLB_INDEX_MASK);
pr_debug("Flush entry by writing %#lx way=%dl pid=%ld\n",
vaddr, way, (pid_misc >> TLBMISC_PID_SHIFT));
WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
tlbmisc = pid_misc | TLBMISC_WE | tlbmisc = pid_misc | TLBMISC_WE |
(way << TLBMISC_WAY_SHIFT); (way << TLBMISC_WAY_SHIFT);
WRCTL(CTL_PTEADDR, (vaddr >> 12) << 2);
WRCTL(CTL_TLBMISC, tlbmisc); 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); tlbmisc = RDCTL(CTL_TLBMISC);
tlbacc = RDCTL(CTL_TLBACC); 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", pr_debug("-- way:%02x vpn:0x%08lx phys:0x%08lx pid:0x%02lx flags:%c%c%c%c%c\n",
way, way,
(pteaddr << (PAGE_SHIFT-2)), (pteaddr << (PAGE_SHIFT-2)),
@ -205,6 +203,7 @@ void dump_tlb(void)
void flush_tlb_pid(unsigned long pid) void flush_tlb_pid(unsigned long pid)
{ {
unsigned long addr = 0;
unsigned int line; unsigned int line;
unsigned int way; unsigned int way;
unsigned long org_misc, pid_misc; 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); get_misc_and_pid(&org_misc, &pid_misc);
for (line = 0; line < cpuinfo.tlb_num_lines; line++) { 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++) { for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
unsigned long pteaddr;
unsigned long tlbmisc; unsigned long tlbmisc;
unsigned long tlbacc;
tlbmisc = pid_misc | TLBMISC_RD | tlbmisc = pid_misc | TLBMISC_RD |
(way << TLBMISC_WAY_SHIFT); (way << TLBMISC_WAY_SHIFT);
WRCTL(CTL_TLBMISC, tlbmisc); WRCTL(CTL_TLBMISC, tlbmisc);
pteaddr = RDCTL(CTL_PTEADDR);
tlbmisc = RDCTL(CTL_TLBMISC); tlbmisc = RDCTL(CTL_TLBMISC);
tlbacc = RDCTL(CTL_TLBACC);
if (((tlbmisc>>TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK) if (((tlbmisc>>TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK)
== pid) { == pid) {
tlbmisc = pid_misc | TLBMISC_WE | tlbmisc = pid_misc | TLBMISC_WE |
(way << TLBMISC_WAY_SHIFT); (way << TLBMISC_WAY_SHIFT);
WRCTL(CTL_TLBMISC, tlbmisc); WRCTL(CTL_TLBMISC, tlbmisc);
WRCTL(CTL_TLBACC, WRCTL(CTL_TLBACC, 0);
(MAX_PHYS_ADDR >> PAGE_SHIFT));
} }
} }
addr += PAGE_SIZE;
WRCTL(CTL_TLBMISC, org_misc); WRCTL(CTL_TLBMISC, org_misc);
} }
} }
void flush_tlb_all(void) void flush_tlb_all(void)
{ {
int i; unsigned long addr = 0;
unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE; unsigned int line;
unsigned int way; unsigned int way;
unsigned long org_misc, pid_misc, tlbmisc; 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 /* Map each TLB entry to physcal address 0 with no-access and a
bad ptbase */ bad ptbase */
for (way = 0; way < cpuinfo.tlb_num_ways; way++) { for (line = 0; line < cpuinfo.tlb_num_lines; line++) {
tlbmisc = pid_misc | (way << TLBMISC_WAY_SHIFT); WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
for (i = 0; i < cpuinfo.tlb_num_lines; i++) {
WRCTL(CTL_PTEADDR, ((vaddr) >> PAGE_SHIFT) << 2); for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
tlbmisc = pid_misc | (way << TLBMISC_WAY_SHIFT);
WRCTL(CTL_TLBMISC, tlbmisc); WRCTL(CTL_TLBMISC, tlbmisc);
WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT)); WRCTL(CTL_TLBACC, 0);
vaddr += 1UL << 12;
} }
addr += PAGE_SIZE;
} }
/* restore pid/way */ /* restore pid/way */