From 461d1597ffad7a826f8aaa63ab0727c37b632e34 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 26 Jan 2015 09:40:34 +0000 Subject: MIPS: asm: pgtable: Add c0 hazards on HTW start/stop sequences When we use htw_{start,stop}() outside of htw_reset(), we need to ensure that c0 changes have been propagated properly before we attempt to continue with subsequence memory operations. Signed-off-by: Markos Chandras Cc: # 3.17+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9114/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'arch/mips/include/asm/pgtable.h') diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 62a6ba383d4f..45d7fd5e1466 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -99,16 +99,20 @@ extern void paging_init(void); #define htw_stop() \ do { \ - if (cpu_has_htw) \ + if (cpu_has_htw) { \ write_c0_pwctl(read_c0_pwctl() & \ ~(1 << MIPS_PWCTL_PWEN_SHIFT)); \ + back_to_back_c0_hazard(); \ + } \ } while(0) #define htw_start() \ do { \ - if (cpu_has_htw) \ + if (cpu_has_htw) { \ write_c0_pwctl(read_c0_pwctl() | \ (1 << MIPS_PWCTL_PWEN_SHIFT)); \ + back_to_back_c0_hazard(); \ + } \ } while(0) @@ -116,9 +120,7 @@ do { \ do { \ if (cpu_has_htw) { \ htw_stop(); \ - back_to_back_c0_hazard(); \ htw_start(); \ - back_to_back_c0_hazard(); \ } \ } while(0) -- cgit From fde3538a8a711aedf1173ecb2d45aed868f51c97 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 26 Jan 2015 09:40:36 +0000 Subject: MIPS: asm: pgtable: Prevent HTW race when updating PTEs Whenever we modify a page table entry, we need to ensure that the HTW will not fetch a stable entry. And for that to happen we need to ensure that HTW is stopped before we modify the said entry otherwise the HTW may already be in the process of reading that entry and fetching the old information. As a result of which, we replace the htw_reset() calls with htw_{stop,start} in more appropriate places. This also removes the remaining users of htw_reset() and as a result we drop that macro Signed-off-by: Markos Chandras Cc: # 3.17+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9116/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'arch/mips/include/asm/pgtable.h') diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 45d7fd5e1466..3aa982b50a10 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -116,14 +116,6 @@ do { \ } while(0) -#define htw_reset() \ -do { \ - if (cpu_has_htw) { \ - htw_stop(); \ - htw_start(); \ - } \ -} while(0) - extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval); @@ -155,12 +147,13 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt { pte_t null = __pte(0); + htw_stop(); /* Preserve global status for the pair */ if (ptep_buddy(ptep)->pte_low & _PAGE_GLOBAL) null.pte_low = null.pte_high = _PAGE_GLOBAL; set_pte_at(mm, addr, ptep, null); - htw_reset(); + htw_start(); } #else @@ -190,6 +183,7 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { + htw_stop(); #if !defined(CONFIG_CPU_R3000) && !defined(CONFIG_CPU_TX39XX) /* Preserve global status for the pair */ if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL) @@ -197,7 +191,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(); + htw_start(); } #endif -- cgit From ed4cbc81addbc076b016c5b979fd1a02f0897f0a Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 26 Jan 2015 13:04:33 +0000 Subject: MIPS: HTW: Prevent accidental HTW start due to nested htw_{start, stop} activate_mm() and switch_mm() call get_new_mmu_context() which in turn can enable the HTW before the entryhi is changed with the new ASID. Since the latter will enable the HTW in local_flush_tlb_all(), then there is a small timing window where the HTW is running with the new ASID but with an old pgd since the TLBMISS_HANDLER_SETUP_PGD hasn't assigned a new one yet. In order to prevent that, we introduce a simple htw counter to avoid starting HTW accidentally due to nested htw_{start,stop}() sequences. Moreover, since various IPI calls can enforce TLB flushing operations on a different core, such an operation may interrupt another htw_{stop,start} in progress leading inconsistent updates of the htw_seq variable. In order to avoid that, we disable the interrupts whenever we update that variable. Signed-off-by: Markos Chandras Cc: # 3.17+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9118/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable.h | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'arch/mips/include/asm/pgtable.h') diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 3aa982b50a10..845016d1cdbd 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -99,19 +99,31 @@ extern void paging_init(void); #define htw_stop() \ do { \ + unsigned long flags; \ + \ if (cpu_has_htw) { \ - write_c0_pwctl(read_c0_pwctl() & \ - ~(1 << MIPS_PWCTL_PWEN_SHIFT)); \ - back_to_back_c0_hazard(); \ + local_irq_save(flags); \ + if(!raw_current_cpu_data.htw_seq++) { \ + write_c0_pwctl(read_c0_pwctl() & \ + ~(1 << MIPS_PWCTL_PWEN_SHIFT)); \ + back_to_back_c0_hazard(); \ + } \ + local_irq_restore(flags); \ } \ } while(0) #define htw_start() \ do { \ + unsigned long flags; \ + \ if (cpu_has_htw) { \ - write_c0_pwctl(read_c0_pwctl() | \ - (1 << MIPS_PWCTL_PWEN_SHIFT)); \ - back_to_back_c0_hazard(); \ + local_irq_save(flags); \ + if (!--raw_current_cpu_data.htw_seq) { \ + write_c0_pwctl(read_c0_pwctl() | \ + (1 << MIPS_PWCTL_PWEN_SHIFT)); \ + back_to_back_c0_hazard(); \ + } \ + local_irq_restore(flags); \ } \ } while(0) -- cgit From 05f9883a2899d50ff96f05b7a76b7597009b0680 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Thu, 19 Feb 2015 10:18:50 -0600 Subject: MIPS: Usage and cosmetic cleanups of page table bits. * Clean up white spaces and tabs. * Get rid of remaining hardcoded values for calculating shifts and masks. * Get rid of redundant macro values. * Do not use page table bits directly in #ifdef's. Signed-off-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9287/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/mips/include/asm/pgtable.h') diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 845016d1cdbd..3435e84356a5 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -344,7 +344,7 @@ static inline pte_t pte_mkyoung(pte_t pte) return pte; } -#ifdef _PAGE_HUGE +#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT static inline int pte_huge(pte_t pte) { return pte_val(pte) & _PAGE_HUGE; } static inline pte_t pte_mkhuge(pte_t pte) @@ -352,7 +352,7 @@ static inline pte_t pte_mkhuge(pte_t pte) pte_val(pte) |= _PAGE_HUGE; return pte; } -#endif /* _PAGE_HUGE */ +#endif /* CONFIG_MIPS_HUGE_TLB_SUPPORT */ #endif static inline int pte_special(pte_t pte) { return 0; } static inline pte_t pte_mkspecial(pte_t pte) { return pte; } -- cgit