|
@@ -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.
|
|
|
*/
|