aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/include
diff options
context:
space:
mode:
authorMarkos Chandras <markos.chandras@imgtec.com>2014-07-14 07:47:09 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-08-01 18:06:39 -0400
commitf1014d1b79d0fde02befadb0ca9e4da08ef8d453 (patch)
treede74b6272d4d5a4ec3676466de8a1e3b37eebeb2 /arch/mips/include
parent3d528b326d7da8e28ec62c2ff1a92e85d93af098 (diff)
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.h10
-rw-r--r--arch/mips/include/asm/pgtable.h27
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 2e373da5f8e9..2f82568a3ee4 100644
--- a/arch/mips/include/asm/mmu_context.h
+++ b/arch/mips/include/asm/mmu_context.h
@@ -20,10 +20,20 @@
20#include <asm/tlbflush.h> 20#include <asm/tlbflush.h>
21#include <asm-generic/mm_hooks.h> 21#include <asm-generic/mm_hooks.h>
22 22
23#define htw_set_pwbase(pgd) \
24do { \
25 if (cpu_has_htw) { \
26 write_c0_pwbase(pgd); \
27 back_to_back_c0_hazard(); \
28 htw_reset(); \
29 } \
30} while (0)
31
23#define TLBMISS_HANDLER_SETUP_PGD(pgd) \ 32#define TLBMISS_HANDLER_SETUP_PGD(pgd) \
24do { \ 33do { \
25 extern void tlbmiss_handler_setup_pgd(unsigned long); \ 34 extern void tlbmiss_handler_setup_pgd(unsigned long); \
26 tlbmiss_handler_setup_pgd((unsigned long)(pgd)); \ 35 tlbmiss_handler_setup_pgd((unsigned long)(pgd)); \
36 htw_set_pwbase((unsigned long)pgd); \
27} while (0) 37} while (0)
28 38
29#ifdef CONFIG_MIPS_PGD_C0_CONTEXT 39#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index 539ddd148bbb..027c74db13f9 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -97,6 +97,31 @@ extern void paging_init(void);
97 97
98#define pmd_page_vaddr(pmd) pmd_val(pmd) 98#define pmd_page_vaddr(pmd) pmd_val(pmd)
99 99
100#define htw_stop() \
101do { \
102 if (cpu_has_htw) \
103 write_c0_pwctl(read_c0_pwctl() & \
104 ~(1 << MIPS_PWCTL_PWEN_SHIFT)); \
105} while(0)
106
107#define htw_start() \
108do { \
109 if (cpu_has_htw) \
110 write_c0_pwctl(read_c0_pwctl() | \
111 (1 << MIPS_PWCTL_PWEN_SHIFT)); \
112} while(0)
113
114
115#define htw_reset() \
116do { \
117 if (cpu_has_htw) { \
118 htw_stop(); \
119 back_to_back_c0_hazard(); \
120 htw_start(); \
121 back_to_back_c0_hazard(); \
122 } \
123} while(0)
124
100#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) 125#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
101 126
102#define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL)) 127#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
131 null.pte_low = null.pte_high = _PAGE_GLOBAL; 156 null.pte_low = null.pte_high = _PAGE_GLOBAL;
132 157
133 set_pte_at(mm, addr, ptep, null); 158 set_pte_at(mm, addr, ptep, null);
159 htw_reset();
134} 160}
135#else 161#else
136 162
@@ -168,6 +194,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
168 else 194 else
169#endif 195#endif
170 set_pte_at(mm, addr, ptep, __pte(0)); 196 set_pte_at(mm, addr, ptep, __pte(0));
197 htw_reset();
171} 198}
172#endif 199#endif
173 200