]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
nios2: update_mmu_cache preload the TLB with the new PTE
authorNicholas Piggin <npiggin@gmail.com>
Wed, 7 Nov 2018 02:35:34 +0000 (10:35 +0800)
committerLey Foon Tan <ley.foon.tan@intel.com>
Wed, 6 Mar 2019 21:29:35 +0000 (05:29 +0800)
Rather than flush the TLB entry when installing a new PTE to allow
the fast TLB reload to re-fill the TLB, just refill the TLB entry
when removing the old one.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
arch/nios2/include/asm/tlbflush.h
arch/nios2/mm/cacheflush.c
arch/nios2/mm/tlb.c

index 982a7ecf221f184d6d2014fc7992b08cccfc4685..b4bf487b9832a3305bd39c49bf248e4ea738b050 100644 (file)
@@ -30,6 +30,9 @@ struct mm_struct;
  *  - flush_tlb_page(vma, address) flushes a page
  *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
  *  - flush_tlb_kernel_page(address) flushes a kernel page
+ *
+ *  - reload_tlb_page(vma, address, pte) flushes the TLB for address like
+ *    flush_tlb_page, then replaces it with a TLB for pte.
  */
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *mm);
@@ -48,4 +51,7 @@ static inline void flush_tlb_kernel_page(unsigned long address)
        flush_tlb_kernel_range(address, address + PAGE_SIZE);
 }
 
+extern void reload_tlb_page(struct vm_area_struct *vma, unsigned long addr,
+                           pte_t pte);
+
 #endif /* _ASM_NIOS2_TLBFLUSH_H */
index d58e7e80dc0df482d43ab8552f120d781e6c1c2e..65de1bd6a7604aef65ab38034a77f6ffb9cfa472 100644 (file)
@@ -198,13 +198,14 @@ void flush_dcache_page(struct page *page)
 EXPORT_SYMBOL(flush_dcache_page);
 
 void update_mmu_cache(struct vm_area_struct *vma,
-                     unsigned long address, pte_t *pte)
+                     unsigned long address, pte_t *ptep)
 {
-       unsigned long pfn = pte_pfn(*pte);
+       pte_t pte = *ptep;
+       unsigned long pfn = pte_pfn(pte);
        struct page *page;
        struct address_space *mapping;
 
-       flush_tlb_page(vma, address);
+       reload_tlb_page(vma, address, pte);
 
        if (!pfn_valid(pfn))
                return;
index 2e49993d29efcdb51a722b3e96b089e37050797a..af871188556917d7bb777f2ebf4dec3d66379c96 100644 (file)
@@ -43,13 +43,11 @@ static unsigned long pteaddr_invalid(unsigned long addr)
  * This one is only used for pages with the global bit set so we don't care
  * much about the ASID.
  */
-void flush_tlb_one_pid(unsigned long addr, unsigned long mmu_pid)
+static void replace_tlb_one_pid(unsigned long addr, unsigned long mmu_pid, unsigned long tlbacc)
 {
        unsigned int way;
        unsigned long org_misc, pid_misc;
 
-       pr_debug("Flush tlb-entry for vaddr=%#lx\n", addr);
-
        /* remember pid/way until we return. */
        get_misc_and_pid(&org_misc, &pid_misc);
 
@@ -72,10 +70,11 @@ void flush_tlb_one_pid(unsigned long addr, unsigned long mmu_pid)
                if (pid != mmu_pid)
                        continue;
 
-               tlbmisc = TLBMISC_WE | (way << TLBMISC_WAY_SHIFT);
+               tlbmisc = mmu_pid | TLBMISC_WE | (way << TLBMISC_WAY_SHIFT);
                WRCTL(CTL_TLBMISC, tlbmisc);
-               WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
-               WRCTL(CTL_TLBACC, 0);
+               if (tlbacc == 0)
+                       WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
+               WRCTL(CTL_TLBACC, tlbacc);
                /*
                 * There should be only a single entry that maps a
                 * particular {address,pid} so break after a match.
@@ -86,6 +85,20 @@ void flush_tlb_one_pid(unsigned long addr, unsigned long mmu_pid)
        WRCTL(CTL_TLBMISC, org_misc);
 }
 
+static void flush_tlb_one_pid(unsigned long addr, unsigned long mmu_pid)
+{
+       pr_debug("Flush tlb-entry for vaddr=%#lx\n", addr);
+
+       replace_tlb_one_pid(addr, mmu_pid, 0);
+}
+
+static void reload_tlb_one_pid(unsigned long addr, unsigned long mmu_pid, pte_t pte)
+{
+       pr_debug("Reload tlb-entry for vaddr=%#lx\n", addr);
+
+       replace_tlb_one_pid(addr, mmu_pid, pte_val(pte));
+}
+
 void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                        unsigned long end)
 {
@@ -97,6 +110,13 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        }
 }
 
+void reload_tlb_page(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+{
+       unsigned long mmu_pid = get_pid_from_context(&vma->vm_mm->context);
+
+       reload_tlb_one_pid(addr, mmu_pid, pte);
+}
+
 /*
  * This one is only used for pages with the global bit set so we don't care
  * much about the ASID.