From 3437d3c886ed07863acde923a627395abb177aa9 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Mon, 5 Nov 2018 10:35:12 +0800 Subject: 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 Signed-off-by: Ley Foon Tan --- arch/nios2/mm/tlb.c | 68 ++++++++++++++++++++++++++--------------------------- 1 file 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); @@ -34,6 +30,15 @@ static void get_misc_and_pid(unsigned long *misc, unsigned long *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 * 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 */ -- cgit v1.2.3-59-g8ed1b