diff options
author | Markos Chandras <markos.chandras@imgtec.com> | 2014-07-14 11:47:09 (GMT) |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-08-01 22:06:39 (GMT) |
commit | f1014d1b79d0fde02befadb0ca9e4da08ef8d453 (patch) | |
tree | de74b6272d4d5a4ec3676466de8a1e3b37eebeb2 /arch/mips/include | |
parent | 3d528b326d7da8e28ec62c2ff1a92e85d93af098 (diff) | |
download | linux-f1014d1b79d0fde02befadb0ca9e4da08ef8d453.tar.xz |
MIPS: mm: Use the Hardware Page Table Walker if the core supports it
The Hardware Page Table Walker aims to speed up TLB refill exceptions
by handling them in the hardware level instead of having a software
TLB refill handler. However, a TLB refill exception can still be
thrown in certain cases such as, synchronus exceptions, or address
translation or memory errors during the HTW operation. As a result of
which, HTW must not be considered a complete replacement for the TLB
refill software handler, but rather a fast-path for it.
For HTW to work, the PWBase register must contain the task's page
global directory address so the HTW will kick in on TLB refill
exceptions.
Due to HTW being a separate engine embedded deep in the CPU pipeline,
we need to restart the HTW everytime a PTE changes to avoid HTW
fetching a old entry from the page tables. It's also necessary to
restart the HTW on context switches to prevent it from fetching a
page from the previous process. Finally, since HTW is using the
entryhi register to write the translations to the TLB, it's necessary
to stop the HTW whenever the entryhi changes (eg for tlb probe
perations) and enable it back afterwards.
== Performance ==
The following trivial test was used to measure the performance of the
HTW. Using the same root filesystem, the following command was used
to measure the number of tlb refill handler executions with and
without (using 'nohtw' kernel parameter) HTW support. The kernel was
modified to use a scratch register as a counter for the TLB refill
exceptions.
find /usr -type f -exec ls -lh {} \;
HTW Enabled:
TLB refill exceptions: 12306
HTW Disabled:
TLB refill exceptions: 17805
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: Markos Chandras <markos.chandras@imgtec.com>
Patchwork: https://patchwork.linux-mips.org/patch/7336/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/include')
-rw-r--r-- | arch/mips/include/asm/mmu_context.h | 10 | ||||
-rw-r--r-- | arch/mips/include/asm/pgtable.h | 27 |
2 files changed, 37 insertions, 0 deletions
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index 2e373da..2f82568 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h @@ -20,10 +20,20 @@ #include <asm/tlbflush.h> #include <asm-generic/mm_hooks.h> +#define htw_set_pwbase(pgd) \ +do { \ + if (cpu_has_htw) { \ + write_c0_pwbase(pgd); \ + back_to_back_c0_hazard(); \ + htw_reset(); \ + } \ +} while (0) + #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ do { \ extern void tlbmiss_handler_setup_pgd(unsigned long); \ tlbmiss_handler_setup_pgd((unsigned long)(pgd)); \ + htw_set_pwbase((unsigned long)pgd); \ } while (0) #ifdef CONFIG_MIPS_PGD_C0_CONTEXT diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 539ddd1..027c74d 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -97,6 +97,31 @@ extern void paging_init(void); #define pmd_page_vaddr(pmd) pmd_val(pmd) +#define htw_stop() \ +do { \ + if (cpu_has_htw) \ + write_c0_pwctl(read_c0_pwctl() & \ + ~(1 << MIPS_PWCTL_PWEN_SHIFT)); \ +} while(0) + +#define htw_start() \ +do { \ + if (cpu_has_htw) \ + write_c0_pwctl(read_c0_pwctl() | \ + (1 << MIPS_PWCTL_PWEN_SHIFT)); \ +} while(0) + + +#define htw_reset() \ +do { \ + if (cpu_has_htw) { \ + htw_stop(); \ + back_to_back_c0_hazard(); \ + htw_start(); \ + back_to_back_c0_hazard(); \ + } \ +} while(0) + #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) #define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL)) @@ -131,6 +156,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt null.pte_low = null.pte_high = _PAGE_GLOBAL; set_pte_at(mm, addr, ptep, null); + htw_reset(); } #else @@ -168,6 +194,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt else #endif set_pte_at(mm, addr, ptep, __pte(0)); + htw_reset(); } #endif |