[MIPS] MT: Scheduler support for SMT

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 11bc17c..d5a89f3 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1442,6 +1442,7 @@
 	select MIPS_MT
 	select NR_CPUS_DEFAULT_2
 	select SMP
+	select SYS_SUPPORTS_SCHED_SMT if SMP
 	select SYS_SUPPORTS_SMP
 	help
 	  This is a kernel model which is also known a VSMP or lately
@@ -1468,6 +1469,19 @@
 config MIPS_MT
 	bool
 
+config SCHED_SMT
+	bool "SMT (multithreading) scheduler support"
+	depends on SYS_SUPPORTS_SCHED_SMT
+	default n
+	help
+	  SMT scheduler support improves the CPU scheduler's decision making
+	  when dealing with MIPS MT enabled cores at a cost of slightly
+	  increased overhead in some places. If unsure say N here.
+
+config SYS_SUPPORTS_SCHED_SMT
+	bool
+
+
 config SYS_SUPPORTS_MULTITHREADING
 	bool
 
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 6e6e947..34dd228 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -62,6 +62,7 @@
 		);
 	seq_printf(m, "shadow register sets\t: %d\n",
 		       cpu_data[n].srsets);
+	seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core);
 
 	sprintf(fmt, "VCE%%c exceptions\t\t: %s\n",
 	        cpu_has_vce ? "%u" : "not available");
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 94e210c..2ab0b7e 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -22,6 +22,7 @@
 #include <linux/cpumask.h>
 #include <linux/interrupt.h>
 #include <linux/compiler.h>
+#include <linux/smp.h>
 
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
@@ -30,7 +31,6 @@
 #include <asm/system.h>
 #include <asm/hardirq.h>
 #include <asm/mmu_context.h>
-#include <asm/smp.h>
 #include <asm/time.h>
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
@@ -223,6 +223,7 @@
 void __init plat_smp_setup(void)
 {
 	unsigned int mvpconf0, ntc, tc, ncpu = 0;
+	unsigned int nvpe;
 
 #ifdef CONFIG_MIPS_MT_FPAFF
 	/* If we have an FPU, enroll ourselves in the FPU-full mask */
@@ -242,6 +243,9 @@
 	mvpconf0 = read_c0_mvpconf0();
 	ntc = (mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT;
 
+	nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
+	smp_num_siblings = nvpe;
+
 	/* we'll always have more TC's than VPE's, so loop setting everything
 	   to a sensible state */
 	for (tc = 0; tc <= ntc; tc++) {
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 63989e9..335be9b 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -56,6 +56,34 @@
 extern void __init calibrate_delay(void);
 extern void cpu_idle(void);
 
+/* Number of TCs (or siblings in Intel speak) per CPU core */
+int smp_num_siblings = 1;
+EXPORT_SYMBOL(smp_num_siblings);
+
+/* representing the TCs (or siblings in Intel speak) of each logical CPU */
+cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(cpu_sibling_map);
+
+/* representing cpus for which sibling maps can be computed */
+static cpumask_t cpu_sibling_setup_map;
+
+static inline void set_cpu_sibling_map(int cpu)
+{
+	int i;
+
+	cpu_set(cpu, cpu_sibling_setup_map);
+
+	if (smp_num_siblings > 1) {
+		for_each_cpu_mask(i, cpu_sibling_setup_map) {
+			if (cpu_data[cpu].core == cpu_data[i].core) {
+				cpu_set(i, cpu_sibling_map[cpu]);
+				cpu_set(cpu, cpu_sibling_map[i]);
+			}
+		}
+	} else
+		cpu_set(cpu, cpu_sibling_map[cpu]);
+}
+
 /*
  * First C code run on the secondary CPUs after being started up by
  * the master.
@@ -85,6 +113,7 @@
 	cpu_data[cpu].udelay_val = loops_per_jiffy;
 
 	prom_smp_finish();
+	set_cpu_sibling_map(cpu);
 
 	cpu_set(cpu, cpu_callin_map);
 
@@ -258,6 +287,7 @@
 	init_new_context(current, &init_mm);
 	current_thread_info()->cpu = 0;
 	plat_prepare_cpus(max_cpus);
+	set_cpu_sibling_map(0);
 #ifndef CONFIG_HOTPLUG_CPU
 	cpu_present_map = cpu_possible_map;
 #endif