linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] ARM: tlb: add branch predictor maintenance operations
@ 2013-02-25 15:21 Will Deacon
  2013-02-25 15:21 ` [PATCH 2/2] ARM: mm: perform explicit branch predictor maintenance when required Will Deacon
  2013-02-25 16:31 ` [PATCH 1/2] ARM: tlb: add branch predictor maintenance operations Catalin Marinas
  0 siblings, 2 replies; 4+ messages in thread
From: Will Deacon @ 2013-02-25 15:21 UTC (permalink / raw)
  To: linux-arm-kernel

The ARM architecture requires explicit branch predictor maintenance
when updating an instruction stream for a given virtual address. In
reality, this isn't so much of a burden because the branch predictor
is flushed during the cache maintenance required to make the new
instructions visible to the I-side of the processor.

However, there are still some cases where explicit flushing is required,
so add a local_bp_flush_all operation to deal with this.

Cc: <stable@vger.kernel.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---

I can't make my mind up about whether or not this go to -stable... on
the one hand it *is* part of a bug fix but, then again, it's not
something that's knowingly caused any problems so far.

 arch/arm/include/asm/tlbflush.h | 34 ++++++++++++++++++++++++++++------
 arch/arm/kernel/smp_tlb.c       | 12 ++++++++++++
 2 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index 6e924d3..4db8c88 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -34,10 +34,13 @@
 #define TLB_V6_D_ASID	(1 << 17)
 #define TLB_V6_I_ASID	(1 << 18)
 
+#define TLB_V6_BP	(1 << 19)
+
 /* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */
-#define TLB_V7_UIS_PAGE	(1 << 19)
-#define TLB_V7_UIS_FULL (1 << 20)
-#define TLB_V7_UIS_ASID (1 << 21)
+#define TLB_V7_UIS_PAGE	(1 << 20)
+#define TLB_V7_UIS_FULL (1 << 21)
+#define TLB_V7_UIS_ASID (1 << 22)
+#define TLB_V7_UIS_BP	(1 << 23)
 
 #define TLB_BARRIER	(1 << 28)
 #define TLB_L2CLEAN_FR	(1 << 29)		/* Feroceon */
@@ -150,7 +153,8 @@
 #define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
 			 TLB_V6_I_FULL | TLB_V6_D_FULL | \
 			 TLB_V6_I_PAGE | TLB_V6_D_PAGE | \
-			 TLB_V6_I_ASID | TLB_V6_D_ASID)
+			 TLB_V6_I_ASID | TLB_V6_D_ASID | \
+			 TLB_V6_BP)
 
 #ifdef CONFIG_CPU_TLB_V6
 # define v6wbi_possible_flags	v6wbi_tlb_flags
@@ -166,9 +170,11 @@
 #endif
 
 #define v7wbi_tlb_flags_smp	(TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
-			 TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID)
+				 TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | \
+				 TLB_V7_UIS_ASID | TLB_V7_UIS_BP)
 #define v7wbi_tlb_flags_up	(TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
-			 TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID)
+				 TLB_V6_U_FULL | TLB_V6_U_PAGE | \
+				 TLB_V6_U_ASID | TLB_V6_BP)
 
 #ifdef CONFIG_CPU_TLB_V7
 
@@ -430,6 +436,20 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
 	}
 }
 
+static inline void local_flush_bp_all(void)
+{
+	const int zero = 0;
+	const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+	if (tlb_flag(TLB_V7_UIS_BP))
+		asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero));
+	else if (tlb_flag(TLB_V6_BP))
+		asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero));
+
+	if (tlb_flag(TLB_BARRIER))
+		isb();
+}
+
 /*
  *	flush_pmd_entry
  *
@@ -480,6 +500,7 @@ static inline void clean_pmd_entry(void *pmd)
 #define flush_tlb_kernel_page	local_flush_tlb_kernel_page
 #define flush_tlb_range		local_flush_tlb_range
 #define flush_tlb_kernel_range	local_flush_tlb_kernel_range
+#define flush_bp_all		local_flush_bp_all
 #else
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *mm);
@@ -487,6 +508,7 @@ extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
 extern void flush_tlb_kernel_page(unsigned long kaddr);
 extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void flush_bp_all(void);
 #endif
 
 /*
diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c
index 02c5d2c..bd03005 100644
--- a/arch/arm/kernel/smp_tlb.c
+++ b/arch/arm/kernel/smp_tlb.c
@@ -64,6 +64,11 @@ static inline void ipi_flush_tlb_kernel_range(void *arg)
 	local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end);
 }
 
+static inline void ipi_flush_bp_all(void *ignored)
+{
+	local_flush_bp_all();
+}
+
 void flush_tlb_all(void)
 {
 	if (tlb_ops_need_broadcast())
@@ -127,3 +132,10 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 		local_flush_tlb_kernel_range(start, end);
 }
 
+void flush_bp_all(void)
+{
+	if (tlb_ops_need_broadcast())
+		on_each_cpu(ipi_flush_bp_all, NULL, 1);
+	else
+		local_flush_bp_all();
+}
-- 
1.8.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] ARM: mm: perform explicit branch predictor maintenance when required
  2013-02-25 15:21 [PATCH 1/2] ARM: tlb: add branch predictor maintenance operations Will Deacon
@ 2013-02-25 15:21 ` Will Deacon
  2013-02-25 16:31   ` Catalin Marinas
  2013-02-25 16:31 ` [PATCH 1/2] ARM: tlb: add branch predictor maintenance operations Catalin Marinas
  1 sibling, 1 reply; 4+ messages in thread
From: Will Deacon @ 2013-02-25 15:21 UTC (permalink / raw)
  To: linux-arm-kernel

The ARM ARM requires branch predictor maintenance if, for a given ASID,
the instructions at a specific virtual address appear to change.

>From the kernel's point of view, that means:

	- Changing the kernel's view of memory (e.g. switching to the
	  identity map)
	- ASID rollover (since ASIDs will be re-allocated to new tasks)

This patch adds explicit branch predictor maintenance when either of the
two conditions above are met.

Cc: <stable@vger.kernel.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm/kernel/smp.c     | 1 +
 arch/arm/kernel/suspend.c | 1 +
 arch/arm/mm/context.c     | 4 +++-
 arch/arm/mm/idmap.c       | 1 +
 4 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 5f73f70..6f00f3c 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -285,6 +285,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
 	 * switch away from it before attempting any exclusive accesses.
 	 */
 	cpu_switch_mm(mm->pgd, mm);
+	local_flush_bp_all();
 	enter_lazy_tlb(mm, current);
 	local_flush_tlb_all();
 
diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c
index 358bca3..c59c97e 100644
--- a/arch/arm/kernel/suspend.c
+++ b/arch/arm/kernel/suspend.c
@@ -68,6 +68,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
 	ret = __cpu_suspend(arg, fn);
 	if (ret == 0) {
 		cpu_switch_mm(mm->pgd, mm);
+		local_flush_bp_all();
 		local_flush_tlb_all();
 	}
 
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 44d4ee5..a5a4b2bc 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -212,8 +212,10 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
 		atomic64_set(&mm->context.id, asid);
 	}
 
-	if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending))
+	if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) {
+		local_flush_bp_all();
 		local_flush_tlb_all();
+	}
 
 	atomic64_set(&per_cpu(active_asids, cpu), asid);
 	cpumask_set_cpu(cpu, mm_cpumask(mm));
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 2dffc01..5ee505c 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -141,6 +141,7 @@ void setup_mm_for_reboot(void)
 {
 	/* Switch to the identity mapping. */
 	cpu_switch_mm(idmap_pgd, &init_mm);
+	local_flush_bp_all();
 
 #ifdef CONFIG_CPU_HAS_ASID
 	/*
-- 
1.8.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 1/2] ARM: tlb: add branch predictor maintenance operations
  2013-02-25 15:21 [PATCH 1/2] ARM: tlb: add branch predictor maintenance operations Will Deacon
  2013-02-25 15:21 ` [PATCH 2/2] ARM: mm: perform explicit branch predictor maintenance when required Will Deacon
@ 2013-02-25 16:31 ` Catalin Marinas
  1 sibling, 0 replies; 4+ messages in thread
From: Catalin Marinas @ 2013-02-25 16:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 25, 2013 at 03:21:27PM +0000, Will Deacon wrote:
> The ARM architecture requires explicit branch predictor maintenance
> when updating an instruction stream for a given virtual address. In
> reality, this isn't so much of a burden because the branch predictor
> is flushed during the cache maintenance required to make the new
> instructions visible to the I-side of the processor.
> 
> However, there are still some cases where explicit flushing is required,
> so add a local_bp_flush_all operation to deal with this.
> 
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Will Deacon <will.deacon@arm.com>

Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/2] ARM: mm: perform explicit branch predictor maintenance when required
  2013-02-25 15:21 ` [PATCH 2/2] ARM: mm: perform explicit branch predictor maintenance when required Will Deacon
@ 2013-02-25 16:31   ` Catalin Marinas
  0 siblings, 0 replies; 4+ messages in thread
From: Catalin Marinas @ 2013-02-25 16:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 25, 2013 at 03:21:28PM +0000, Will Deacon wrote:
> The ARM ARM requires branch predictor maintenance if, for a given ASID,
> the instructions at a specific virtual address appear to change.
> 
> From the kernel's point of view, that means:
> 
> 	- Changing the kernel's view of memory (e.g. switching to the
> 	  identity map)
> 	- ASID rollover (since ASIDs will be re-allocated to new tasks)
> 
> This patch adds explicit branch predictor maintenance when either of the
> two conditions above are met.
> 
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Will Deacon <will.deacon@arm.com>

Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-02-25 16:31 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-02-25 15:21 [PATCH 1/2] ARM: tlb: add branch predictor maintenance operations Will Deacon
2013-02-25 15:21 ` [PATCH 2/2] ARM: mm: perform explicit branch predictor maintenance when required Will Deacon
2013-02-25 16:31   ` Catalin Marinas
2013-02-25 16:31 ` [PATCH 1/2] ARM: tlb: add branch predictor maintenance operations Catalin Marinas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).