[PATCH 2/3] MIPS: CMP: Malta: Add support for CPU hotplugging.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: "Steven J. Hill" <Steven.Hill@xxxxxxxxxx>

Adds support for CPU hotplugging on the Malta platform.

Signed-off-by: Steven J. Hill <Steven.Hill@xxxxxxxxxx>
---
 arch/mips/include/asm/amon.h     |    1 +
 arch/mips/mti-malta/malta-amon.c |  107 +++++++++++++++++++++++++++++++-------
 arch/mips/mti-malta/malta-int.c  |    2 +-
 3 files changed, 91 insertions(+), 19 deletions(-)

diff --git a/arch/mips/include/asm/amon.h b/arch/mips/include/asm/amon.h
index 3cc03c6..a71e82d 100644
--- a/arch/mips/include/asm/amon.h
+++ b/arch/mips/include/asm/amon.h
@@ -10,3 +10,4 @@
 int amon_cpu_avail(int cpu);
 int amon_cpu_start(int cpu, unsigned long pc, unsigned long sp,
 		   unsigned long gp, unsigned long a0);
+void amon_cpu_dead(void);
diff --git a/arch/mips/mti-malta/malta-amon.c b/arch/mips/mti-malta/malta-amon.c
index 0319ad8..80ad67a 100644
--- a/arch/mips/mti-malta/malta-amon.c
+++ b/arch/mips/mti-malta/malta-amon.c
@@ -3,10 +3,10 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * Arbitrary Monitor Interface
+ *
  * Copyright (C) 2007 MIPS Technologies, Inc.  All rights reserved.
  * Copyright (C) 2013 Imagination Technologies Ltd.
- *
- * Arbitrary Monitor Interface
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -22,40 +22,49 @@ int amon_cpu_avail(int cpu)
 	struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
 
 	if (cpu < 0 || cpu >= NCPULAUNCH) {
-		pr_debug("avail: cpu%d is out of range\n", cpu);
+		pr_debug("%s: CPU%d is out of range\n", __func__, cpu);
 		return 0;
 	}
 
 	launch += cpu;
-	if (!(launch->flags & LAUNCH_FREADY)) {
-		pr_debug("avail: cpu%d is not ready\n", cpu);
-		return 0;
-	}
-	if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) {
-		pr_debug("avail: too late.. cpu%d is already gone\n", cpu);
-		return 0;
-	}
-
-	return 1;
+	if (launch->flags == LAUNCH_FREADY) {
+		pr_debug("%s: CPU%d is available\n", __func__, cpu);
+		return LAUNCH_FREADY;
+	} else if (launch->flags & LAUNCH_FGONE) {
+		pr_debug("%s: CPU%d is already gone\n", __func__, cpu);
+		return LAUNCH_FGONE;
+	} else if (launch->flags & LAUNCH_FGO) {
+		pr_debug("%s: CPU%d is going\n", __func__, cpu);
+		return LAUNCH_FGO;
+	} else {
+		pr_debug("%s: CPU%d is unavailable\n", __func__, cpu);
+ 		return 0;
+ 	}
 }
 
 int amon_cpu_start(int cpu,
-		    unsigned long pc, unsigned long sp,
-		    unsigned long gp, unsigned long a0)
+		   unsigned long pc, unsigned long sp,
+		   unsigned long gp, unsigned long a0)
 {
+	int this_cpu;
 	volatile struct cpulaunch *launch =
 		(struct cpulaunch  *)CKSEG0ADDR(CPULAUNCH);
 
 	if (!amon_cpu_avail(cpu))
 		return -1;
-	if (cpu == smp_processor_id()) {
+
+	preempt_disable();
+	this_cpu = smp_processor_id();
+	preempt_enable();
+
+	if (cpu == this_cpu) {
 		pr_debug("launch: I am cpu%d!\n", cpu);
 		return -1;
 	}
-	launch += cpu;
 
 	pr_debug("launch: starting cpu%d\n", cpu);
 
+	launch += cpu;
 	launch->pc = pc;
 	launch->gp = gp;
 	launch->sp = sp;
@@ -67,12 +76,74 @@ int amon_cpu_start(int cpu,
 
 	while ((launch->flags & LAUNCH_FGONE) == 0)
 		;
-	smp_rmb();	/* Target will be updating flags soon */
+	smp_rmb();		/* Target will be updating flags soon */
 	pr_debug("launch: cpu%d gone!\n", cpu);
 
 	return 0;
 }
 
+/*
+ * Restart the CPU ready for amon_cpu_start again
+ * A bit of a hack... it duplicates the CPU startup code that
+ * lives somewhere in the boot monitor.
+ */
+void amon_cpu_dead(void)
+{
+	struct cpulaunch *launch;
+	unsigned int r0;
+	int cpufreq;
+
+	launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
+	launch += smp_processor_id();
+
+	launch->pc = 0;
+	launch->gp = 0;
+	launch->sp = 0;
+	launch->a0 = 0;
+	launch->flags = LAUNCH_FREADY;
+
+	cpufreq = 500000000;	/* FIXME: Correct value? */
+
+	__asm__ __volatile__ (
+	"	.set	push\n\t"
+	"	.set	noreorder\n\t"
+	"1:\n\t"
+	"	lw	%[r0],%[LAUNCH_FLAGS](%[launch])\n\t"
+	"	andi	%[r0],%[FGO]\n\t"
+	"	bnez    %[r0],1f\n\t"
+	"	 nop\n\t"
+	"	mfc0	%[r0],$9\n\t"	/* Read Count */
+	"	addu    %[r0],%[waitperiod]\n\t"
+	"	mtc0	%[r0],$11\n\t"	/* Write Compare */
+	"	wait\n\t"
+	"	b	1b\n\t"
+	"	 nop\n\t"
+	"1:	lw	$ra,%[LAUNCH_PC](%[launch])\n\t"
+	"	lw	$gp,%[LAUNCH_GP](%[launch])\n\t"
+	"	lw	$sp,%[LAUNCH_SP](%[launch])\n\t"
+	"	lw	$a0,%[LAUNCH_A0](%[launch])\n\t"
+	"	move	$a1,$zero\n\t"
+	"	move	$a2,$zero\n\t"
+	"	move	$a3,$zero\n\t"
+	"	lw	%[r0],%[LAUNCH_FLAGS](%[launch])\n\t"
+	"	ori	%[r0],%[FGONE]\n\t"
+	"	jr	$ra\n\t"
+	"	 sw	%[r0],%[LAUNCH_FLAGS](%[launch])\n\t"
+	"	.set	pop\n\t"
+	: [r0] "=&r" (r0)
+	: [launch] "r" (launch),
+	  [FGONE] "i" (LAUNCH_FGONE),
+	  [FGO] "i" (LAUNCH_FGO),
+	  [LAUNCH_PC] "i" (offsetof(struct cpulaunch, pc)),
+	  [LAUNCH_GP] "i" (offsetof(struct cpulaunch, gp)),
+	  [LAUNCH_SP] "i" (offsetof(struct cpulaunch, sp)),
+	  [LAUNCH_A0] "i" (offsetof(struct cpulaunch, a0)),
+	  [LAUNCH_FLAGS] "i" (offsetof(struct cpulaunch, flags)),
+	  [waitperiod] "i" ((cpufreq / 2) / 100)	/* delay of ~10ms  */
+	: "ra", "a0", "a1", "a2", "a3", "sp" /* ,"gp" */
+	);
+}
+
 #ifdef CONFIG_MIPS_VPE_LOADER
 int vpe_run(struct vpe *v)
 {
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index ca3e3a4..136c4fc 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -39,7 +39,7 @@
 
 int gcmp_present = -1;
 static unsigned long _msc01_biu_base;
-static unsigned long _gcmp_base;
+unsigned long _gcmp_base;
 static unsigned int ipi_map[NR_CPUS];
 
 static DEFINE_RAW_SPINLOCK(mips_irq_lock);
-- 
1.7.10.4



[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux