diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2018-11-05 03:35:12 +0100 |
---|---|---|
committer | Ley Foon Tan <ley.foon.tan@intel.com> | 2019-03-06 22:29:35 +0100 |
commit | 3437d3c886ed07863acde923a627395abb177aa9 (patch) | |
tree | af1a7cb90e1689ec8fc31aa49cc7f501e5047997 | |
parent | nios2: pte_clear does not need to flush TLB (diff) | |
download | linux-3437d3c886ed07863acde923a627395abb177aa9.tar.xz linux-3437d3c886ed07863acde923a627395abb177aa9.zip |
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>
-rw-r--r-- | arch/nios2/mm/tlb.c | 68 |
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 */ |