mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] metag: smp / cache changes
@ 2013-03-15 13:55 James Hogan
  2013-03-15 13:55 ` [PATCH 1/3] metag: smp: copy cache partition and enable GCOn James Hogan
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: James Hogan @ 2013-03-15 13:55 UTC (permalink / raw)
  To: linux-kernel; +Cc: James Hogan

Here are a few Meta SMP and cache changes I have for v3.10. The first
one removes the need to have an SMP specific bootloader to configure the
cache partitions and coherency for the hardware threads that will run
SMP, and the other two are very minor fixes.

James Hogan (3):
  metag: smp: copy cache partition and enable GCOn
  metag: cachepart: take into account small cache bits
  metag: cachepart: fix get_global_dcache_size() typo

 arch/metag/include/asm/metag_mem.h |   3 +
 arch/metag/kernel/cachepart.c      |  16 ++++--
 arch/metag/kernel/head.S           |   8 +++
 arch/metag/kernel/smp.c            | 115 +++++++++++++++++++++++++++++++++++++
 4 files changed, 137 insertions(+), 5 deletions(-)

-- 
1.8.1.2



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

* [PATCH 1/3] metag: smp: copy cache partition and enable GCOn
  2013-03-15 13:55 [PATCH 0/3] metag: smp / cache changes James Hogan
@ 2013-03-15 13:55 ` James Hogan
  2013-03-15 13:55 ` [PATCH 2/3] metag: cachepart: take into account small cache bits James Hogan
  2013-03-15 13:55 ` [PATCH 3/3] metag: cachepart: fix get_global_dcache_size() typo James Hogan
  2 siblings, 0 replies; 4+ messages in thread
From: James Hogan @ 2013-03-15 13:55 UTC (permalink / raw)
  To: linux-kernel; +Cc: James Hogan

When starting an SMP hardware thread, copy the cache partition
configuration so that the threads share the same cache partitions. Also
enable the GCOn bit if running in the local half of the virtual address
space to enable coherency of shared local cache partitions. An atomic
unlock system event is executed by the new cpu before any memory is read
to ensure that any writes made by the boot cpu prior to full coherency
taking effect are visible to the new cpu.

This is to allow SMP to work even when the bootloader hasn't configured
the caches for coherency. A log message is printed to describe the cache
partition changes so that the user is aware of potential unintentional
cache wastage if they've configured the cache partitions in the wrong
way.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
---
 arch/metag/include/asm/metag_mem.h |   3 +
 arch/metag/kernel/head.S           |   8 +++
 arch/metag/kernel/smp.c            | 115 +++++++++++++++++++++++++++++++++++++
 3 files changed, 126 insertions(+)

diff --git a/arch/metag/include/asm/metag_mem.h b/arch/metag/include/asm/metag_mem.h
index 3f7b54d..aa5a076 100644
--- a/arch/metag/include/asm/metag_mem.h
+++ b/arch/metag/include/asm/metag_mem.h
@@ -700,6 +700,9 @@
 #define     SYSC_xCPARTG_AND_S    8
 #define     SYSC_xCPARTL_OR_BITS  0x000F0000 /* Ors into top 4 bits */
 #define     SYSC_xCPARTL_OR_S     16
+#ifdef METAC_2_1
+#define     SYSC_DCPART_GCON_BIT  0x00100000 /* Coherent shared local */
+#endif /* METAC_2_1 */
 #define     SYSC_xCPARTG_OR_BITS  0x0F000000 /* Ors into top 4 bits */
 #define     SYSC_xCPARTG_OR_S     24
 #define     SYSC_CWRMODE_BIT      0x80000000 /* Write cache mode bit */
diff --git a/arch/metag/kernel/head.S b/arch/metag/kernel/head.S
index 969dffa..713f71d 100644
--- a/arch/metag/kernel/head.S
+++ b/arch/metag/kernel/head.S
@@ -1,6 +1,7 @@
 	! Copyright 2005,2006,2007,2009 Imagination Technologies
 
 #include <linux/init.h>
+#include <asm/metag_mem.h>
 #include <generated/asm-offsets.h>
 #undef __exit
 
@@ -48,6 +49,13 @@ __exit:
 	.global _secondary_startup
 	.type _secondary_startup,function
 _secondary_startup:
+#if CONFIG_PAGE_OFFSET < LINGLOBAL_BASE
+	! In case GCOn has just been turned on we need to fence any writes that
+	! the boot thread might have performed prior to coherency taking effect.
+	MOVT	D0Re0,#HI(LINSYSEVENT_WR_ATOMIC_UNLOCK)
+	MOV	D1Re0,#0
+	SETD	[D0Re0], D1Re0
+#endif
 	MOVT	A0StP,#HI(_secondary_data_stack)
 	ADD	A0StP,A0StP,#LO(_secondary_data_stack)
 	GETD	A0StP,[A0StP]
diff --git a/arch/metag/kernel/smp.c b/arch/metag/kernel/smp.c
index 4b6d1f14..4e7751a 100644
--- a/arch/metag/kernel/smp.c
+++ b/arch/metag/kernel/smp.c
@@ -28,6 +28,8 @@
 #include <asm/cachepart.h>
 #include <asm/core_reg.h>
 #include <asm/cpu.h>
+#include <asm/global_lock.h>
+#include <asm/metag_mem.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -37,6 +39,9 @@
 #include <asm/hwthread.h>
 #include <asm/traps.h>
 
+#define SYSC_DCPART(n)	(SYSC_DCPART0 + SYSC_xCPARTn_STRIDE * (n))
+#define SYSC_ICPART(n)	(SYSC_ICPART0 + SYSC_xCPARTn_STRIDE * (n))
+
 DECLARE_PER_CPU(PTBI, pTBI);
 
 void *secondary_data_stack;
@@ -99,6 +104,114 @@ int __cpuinit boot_secondary(unsigned int thread, struct task_struct *idle)
 	return 0;
 }
 
+/**
+ * describe_cachepart_change: describe a change to cache partitions.
+ * @thread:	Hardware thread number.
+ * @label:	Label of cache type, e.g. "dcache" or "icache".
+ * @sz:		Total size of the cache.
+ * @old:	Old cache partition configuration (*CPART* register).
+ * @new:	New cache partition configuration (*CPART* register).
+ *
+ * If the cache partition has changed, prints a message to the log describing
+ * those changes.
+ */
+static __cpuinit void describe_cachepart_change(unsigned int thread,
+						const char *label,
+						unsigned int sz,
+						unsigned int old,
+						unsigned int new)
+{
+	unsigned int lor1, land1, gor1, gand1;
+	unsigned int lor2, land2, gor2, gand2;
+	unsigned int diff = old ^ new;
+
+	if (!diff)
+		return;
+
+	pr_info("Thread %d: %s partition changed:", thread, label);
+	if (diff & (SYSC_xCPARTL_OR_BITS | SYSC_xCPARTL_AND_BITS)) {
+		lor1   = (old & SYSC_xCPARTL_OR_BITS)  >> SYSC_xCPARTL_OR_S;
+		lor2   = (new & SYSC_xCPARTL_OR_BITS)  >> SYSC_xCPARTL_OR_S;
+		land1  = (old & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
+		land2  = (new & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
+		pr_cont(" L:%#x+%#x->%#x+%#x",
+			(lor1 * sz) >> 4,
+			((land1 + 1) * sz) >> 4,
+			(lor2 * sz) >> 4,
+			((land2 + 1) * sz) >> 4);
+	}
+	if (diff & (SYSC_xCPARTG_OR_BITS | SYSC_xCPARTG_AND_BITS)) {
+		gor1   = (old & SYSC_xCPARTG_OR_BITS)  >> SYSC_xCPARTG_OR_S;
+		gor2   = (new & SYSC_xCPARTG_OR_BITS)  >> SYSC_xCPARTG_OR_S;
+		gand1  = (old & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
+		gand2  = (new & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
+		pr_cont(" G:%#x+%#x->%#x+%#x",
+			(gor1 * sz) >> 4,
+			((gand1 + 1) * sz) >> 4,
+			(gor2 * sz) >> 4,
+			((gand2 + 1) * sz) >> 4);
+	}
+	if (diff & SYSC_CWRMODE_BIT)
+		pr_cont(" %sWR",
+			(new & SYSC_CWRMODE_BIT) ? "+" : "-");
+	if (diff & SYSC_DCPART_GCON_BIT)
+		pr_cont(" %sGCOn",
+			(new & SYSC_DCPART_GCON_BIT) ? "+" : "-");
+	pr_cont("\n");
+}
+
+/**
+ * setup_smp_cache: ensure cache coherency for new SMP thread.
+ * @thread:	New hardware thread number.
+ *
+ * Ensures that coherency is enabled and that the threads share the same cache
+ * partitions.
+ */
+static __cpuinit void setup_smp_cache(unsigned int thread)
+{
+	unsigned int this_thread, lflags;
+	unsigned int dcsz, dcpart_this, dcpart_old, dcpart_new;
+	unsigned int icsz, icpart_old, icpart_new;
+
+	/*
+	 * Copy over the current thread's cache partition configuration to the
+	 * new thread so that they share cache partitions.
+	 */
+	__global_lock2(lflags);
+	this_thread = hard_processor_id();
+	/* Share dcache partition */
+	dcpart_this = metag_in32(SYSC_DCPART(this_thread));
+	dcpart_old = metag_in32(SYSC_DCPART(thread));
+	dcpart_new = dcpart_this;
+#if PAGE_OFFSET < LINGLOBAL_BASE
+	/*
+	 * For the local data cache to be coherent the threads must also have
+	 * GCOn enabled.
+	 */
+	dcpart_new |= SYSC_DCPART_GCON_BIT;
+	metag_out32(dcpart_new, SYSC_DCPART(this_thread));
+#endif
+	metag_out32(dcpart_new, SYSC_DCPART(thread));
+	/* Share icache partition too */
+	icpart_new = metag_in32(SYSC_ICPART(this_thread));
+	icpart_old = metag_in32(SYSC_ICPART(thread));
+	metag_out32(icpart_new, SYSC_ICPART(thread));
+	__global_unlock2(lflags);
+
+	/*
+	 * Log if the cache partitions were altered so the user is aware of any
+	 * potential unintentional cache wastage.
+	 */
+	dcsz = get_dcache_size();
+	icsz = get_dcache_size();
+	describe_cachepart_change(this_thread, "dcache", dcsz,
+				  dcpart_this, dcpart_new);
+	describe_cachepart_change(thread, "dcache", dcsz,
+				  dcpart_old, dcpart_new);
+	describe_cachepart_change(thread, "icache", icsz,
+				  icpart_old, icpart_new);
+}
+
 int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
 {
 	unsigned int thread = cpu_2_hwthread_id[cpu];
@@ -108,6 +221,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
 
 	flush_tlb_all();
 
+	setup_smp_cache(thread);
+
 	/*
 	 * Tell the secondary CPU where to find its idle thread's stack.
 	 */
-- 
1.8.1.2



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

* [PATCH 2/3] metag: cachepart: take into account small cache bits
  2013-03-15 13:55 [PATCH 0/3] metag: smp / cache changes James Hogan
  2013-03-15 13:55 ` [PATCH 1/3] metag: smp: copy cache partition and enable GCOn James Hogan
@ 2013-03-15 13:55 ` James Hogan
  2013-03-15 13:55 ` [PATCH 3/3] metag: cachepart: fix get_global_dcache_size() typo James Hogan
  2 siblings, 0 replies; 4+ messages in thread
From: James Hogan @ 2013-03-15 13:55 UTC (permalink / raw)
  To: linux-kernel; +Cc: James Hogan

The CORE_CONFIG2 register has bits to indicate that the data or code
cache is small, i.e. that the size described in the field should be
divided by 64. Take this into account in get_icache_size() and
get_dcache_size().

Signed-off-by: James Hogan <james.hogan@imgtec.com>
---
 arch/metag/kernel/cachepart.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/arch/metag/kernel/cachepart.c b/arch/metag/kernel/cachepart.c
index 3a589dfb..c737edb 100644
--- a/arch/metag/kernel/cachepart.c
+++ b/arch/metag/kernel/cachepart.c
@@ -24,15 +24,21 @@
 unsigned int get_dcache_size(void)
 {
 	unsigned int config2 = metag_in32(METAC_CORE_CONFIG2);
-	return 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS)
-				>> METAC_CORECFG2_DCSZ_S);
+	unsigned int sz = 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS)
+				     >> METAC_CORECFG2_DCSZ_S);
+	if (config2 & METAC_CORECFG2_DCSMALL_BIT)
+		sz >>= 6;
+	return sz;
 }
 
 unsigned int get_icache_size(void)
 {
 	unsigned int config2 = metag_in32(METAC_CORE_CONFIG2);
-	return 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS)
-				>> METAC_CORE_C2ICSZ_S);
+	unsigned int sz = 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS)
+				     >> METAC_CORE_C2ICSZ_S);
+	if (config2 & METAC_CORECFG2_ICSMALL_BIT)
+		sz >>= 6;
+	return sz;
 }
 
 unsigned int get_global_dcache_size(void)
-- 
1.8.1.2



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

* [PATCH 3/3] metag: cachepart: fix get_global_dcache_size() typo
  2013-03-15 13:55 [PATCH 0/3] metag: smp / cache changes James Hogan
  2013-03-15 13:55 ` [PATCH 1/3] metag: smp: copy cache partition and enable GCOn James Hogan
  2013-03-15 13:55 ` [PATCH 2/3] metag: cachepart: take into account small cache bits James Hogan
@ 2013-03-15 13:55 ` James Hogan
  2 siblings, 0 replies; 4+ messages in thread
From: James Hogan @ 2013-03-15 13:55 UTC (permalink / raw)
  To: linux-kernel; +Cc: James Hogan

Compilation is broken when the kernel is destined to live in the global
part of the virtual address space:

arch/metag/kernel/cachepart.c In function 'get_thread_cache_size':
arch/metag/kernel/cachepart.c +71 : error: implicit declaration of function 'get_global_dache_size'

Fix the typo.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
---
 arch/metag/kernel/cachepart.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/metag/kernel/cachepart.c b/arch/metag/kernel/cachepart.c
index c737edb..954548b 100644
--- a/arch/metag/kernel/cachepart.c
+++ b/arch/metag/kernel/cachepart.c
@@ -67,7 +67,7 @@ static unsigned int get_thread_cache_size(unsigned int cache, int thread_id)
 		return 0;
 #if PAGE_OFFSET >= LINGLOBAL_BASE
 	/* Checking for global cache */
-	cache_size = (cache == DCACHE ? get_global_dache_size() :
+	cache_size = (cache == DCACHE ? get_global_dcache_size() :
 		get_global_icache_size());
 	offset = 8;
 #else
-- 
1.8.1.2



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

end of thread, other threads:[~2013-03-15 13:55 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-15 13:55 [PATCH 0/3] metag: smp / cache changes James Hogan
2013-03-15 13:55 ` [PATCH 1/3] metag: smp: copy cache partition and enable GCOn James Hogan
2013-03-15 13:55 ` [PATCH 2/3] metag: cachepart: take into account small cache bits James Hogan
2013-03-15 13:55 ` [PATCH 3/3] metag: cachepart: fix get_global_dcache_size() typo James Hogan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®