summaryrefslogtreecommitdiffstats
path: root/arch/mips/mips-boards
diff options
context:
space:
mode:
authorRalf Baechle2006-04-05 10:45:45 +0200
committerRalf Baechle2006-04-19 04:14:28 +0200
commit41c594ab65fc89573af296d192aa5235d09717ab (patch)
tree562462512a320f386bdf49eabfbb26bb3ee761fa /arch/mips/mips-boards
parent[MIPS] kpsd and other AP/SP improvements. (diff)
downloadkernel-qcow2-linux-41c594ab65fc89573af296d192aa5235d09717ab.tar.gz
kernel-qcow2-linux-41c594ab65fc89573af296d192aa5235d09717ab.tar.xz
kernel-qcow2-linux-41c594ab65fc89573af296d192aa5235d09717ab.zip
[MIPS] MT: Improved multithreading support.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/mips-boards')
-rw-r--r--arch/mips/mips-boards/generic/init.c1
-rw-r--r--arch/mips/mips-boards/generic/time.c68
-rw-r--r--arch/mips/mips-boards/malta/Makefile1
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c11
-rw-r--r--arch/mips/mips-boards/malta/malta_smp.c128
-rw-r--r--arch/mips/mips-boards/sim/cmdline.c59
-rw-r--r--arch/mips/mips-boards/sim/sim_cmdline.c6
-rw-r--r--arch/mips/mips-boards/sim/sim_smp.c14
8 files changed, 203 insertions, 85 deletions
diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c
index eab5a705e989..17dfe6a8cab9 100644
--- a/arch/mips/mips-boards/generic/init.c
+++ b/arch/mips/mips-boards/generic/init.c
@@ -220,7 +220,6 @@ void __init kgdb_config (void)
generic_putDebugChar (*s++);
}
- kgdb_enabled = 1;
/* Breakpoint is invoked after interrupts are initialised */
}
}
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 93f3bf2c2b22..a9f6124b3a22 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -30,6 +30,7 @@
#include <linux/mc146818rtc.h>
#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
#include <asm/ptrace.h>
#include <asm/hardirq.h>
#include <asm/irq.h>
@@ -50,16 +51,23 @@ unsigned long cpu_khz;
static char display_string[] = " LINUX ON ATLAS ";
#endif
#if defined(CONFIG_MIPS_MALTA)
+#if defined(CONFIG_MIPS_MT_SMTC)
+static char display_string[] = " SMTC LINUX ON MALTA ";
+#else
static char display_string[] = " LINUX ON MALTA ";
+#endif /* CONFIG_MIPS_MT_SMTC */
#endif
#if defined(CONFIG_MIPS_SEAD)
static char display_string[] = " LINUX ON SEAD ";
#endif
-static unsigned int display_count = 0;
+static unsigned int display_count;
#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8)
-static unsigned int timer_tick_count=0;
+#define CPUCTR_IMASKBIT (0x100 << MIPSCPU_INT_CPUCTR)
+
+static unsigned int timer_tick_count;
static int mips_cpu_timer_irq;
+extern void smtc_timer_broadcast(int);
static inline void scroll_display_message(void)
{
@@ -75,15 +83,55 @@ static void mips_timer_dispatch (struct pt_regs *regs)
do_IRQ (mips_cpu_timer_irq, regs);
}
+/*
+ * Redeclare until I get around mopping the timer code insanity on MIPS.
+ */
extern int null_perf_irq(struct pt_regs *regs);
extern int (*perf_irq)(struct pt_regs *regs);
irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- int r2 = cpu_has_mips_r2;
int cpu = smp_processor_id();
+ int r2 = cpu_has_mips_r2;
+
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * In an SMTC system, one Count/Compare set exists per VPE.
+ * Which TC within a VPE gets the interrupt is essentially
+ * random - we only know that it shouldn't be one with
+ * IXMT set. Whichever TC gets the interrupt needs to
+ * send special interprocessor interrupts to the other
+ * TCs to make sure that they schedule, etc.
+ *
+ * That code is specific to the SMTC kernel, not to
+ * the a particular platform, so it's invoked from
+ * the general MIPS timer_interrupt routine.
+ */
+
+ /*
+ * DVPE is necessary so long as cross-VPE interrupts
+ * are done via read-modify-write of Cause register.
+ */
+ int vpflags = dvpe();
+ write_c0_compare (read_c0_count() - 1);
+ clear_c0_cause(CPUCTR_IMASKBIT);
+ evpe(vpflags);
+
+ if (cpu_data[cpu].vpe_id == 0) {
+ timer_interrupt(irq, dev_id, regs);
+ scroll_display_message();
+ } else
+ write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
+ smtc_timer_broadcast(cpu_data[cpu].vpe_id);
+ if (cpu != 0)
+ /*
+ * Other CPUs should do profiling and process accounting
+ */
+ local_timer_interrupt(irq, dev_id, regs);
+
+#else /* CONFIG_MIPS_MT_SMTC */
if (cpu == 0) {
/*
* CPU 0 handles the global timer interrupt job and process
@@ -107,12 +155,14 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* More support needs to be added to kernel/time for
* counter/timer interrupts on multiple CPU's
*/
- write_c0_compare (read_c0_count() + (mips_hpt_frequency/HZ));
+ write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
+
/*
- * other CPUs should do profiling and process accounting
+ * Other CPUs should do profiling and process accounting
*/
- local_timer_interrupt (irq, dev_id, regs);
+ local_timer_interrupt(irq, dev_id, regs);
}
+#endif /* CONFIG_MIPS_MT_SMTC */
out:
return IRQ_HANDLED;
@@ -126,7 +176,7 @@ static unsigned int __init estimate_cpu_frequency(void)
unsigned int prid = read_c0_prid() & 0xffff00;
unsigned int count;
-#ifdef CONFIG_MIPS_SEAD
+#if defined(CONFIG_MIPS_SEAD) || defined(CONFIG_MIPS_SIM)
/*
* The SEAD board doesn't have a real time clock, so we can't
* really calculate the timer frequency
@@ -211,7 +261,11 @@ void __init mips_timer_setup(struct irqaction *irq)
/* we are using the cpu counter for timer interrupts */
irq->handler = mips_timer_interrupt; /* we use our own handler */
+#ifdef CONFIG_MIPS_MT_SMTC
+ setup_irq_smtc(mips_cpu_timer_irq, irq, CPUCTR_IMASKBIT);
+#else
setup_irq(mips_cpu_timer_irq, irq);
+#endif /* CONFIG_MIPS_MT_SMTC */
#ifdef CONFIG_SMP
/* irq_desc(riptor) is a global resource, when the interrupt overlaps
diff --git a/arch/mips/mips-boards/malta/Makefile b/arch/mips/mips-boards/malta/Makefile
index fd4c143c0e2f..77ee5c6d33c1 100644
--- a/arch/mips/mips-boards/malta/Makefile
+++ b/arch/mips/mips-boards/malta/Makefile
@@ -20,3 +20,4 @@
#
obj-y := malta_int.o malta_setup.o
+obj-$(CONFIG_SMP) += malta_smp.o
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index 1da8c18b9c8e..64db07d4dbe5 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -118,8 +118,9 @@ static void malta_hw0_irqdispatch(struct pt_regs *regs)
int irq;
irq = get_int();
- if (irq < 0)
+ if (irq < 0) {
return; /* interrupt has already been cleared */
+ }
do_IRQ(MALTA_INT_BASE+irq, regs);
}
@@ -324,9 +325,15 @@ void __init arch_init_irq(void)
else if (cpu_has_vint) {
set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch);
-
+#ifdef CONFIG_MIPS_MT_SMTC
+ setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq,
+ (0x100 << MIPSCPU_INT_I8259A));
+ setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI,
+ &corehi_irqaction, (0x100 << MIPSCPU_INT_COREHI));
+#else /* Not SMTC */
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
+#endif /* CONFIG_MIPS_MT_SMTC */
}
else {
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
diff --git a/arch/mips/mips-boards/malta/malta_smp.c b/arch/mips/mips-boards/malta/malta_smp.c
new file mode 100644
index 000000000000..6c6c8eeedbce
--- /dev/null
+++ b/arch/mips/mips-boards/malta/malta_smp.c
@@ -0,0 +1,128 @@
+/*
+ * Malta Platform-specific hooks for SMP operation
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+
+#include <asm/atomic.h>
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+#ifdef CONFIG_MIPS_MT_SMTC
+#include <asm/smtc_ipi.h>
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+/* VPE/SMP Prototype implements platform interfaces directly */
+#if !defined(CONFIG_MIPS_MT_SMP)
+
+/*
+ * Cause the specified action to be performed on a targeted "CPU"
+ */
+
+void core_send_ipi(int cpu, unsigned int action)
+{
+/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
+#ifdef CONFIG_MIPS_MT_SMTC
+ smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Detect available CPUs/VPEs/TCs and populate phys_cpu_present_map
+ */
+
+void __init prom_build_cpu_map(void)
+{
+ int nextslot;
+
+ /*
+ * As of November, 2004, MIPSsim only simulates one core
+ * at a time. However, that core may be a MIPS MT core
+ * with multiple virtual processors and thread contexts.
+ */
+
+ if (read_c0_config3() & (1<<2)) {
+ nextslot = mipsmt_build_cpu_map(1);
+ }
+}
+
+/*
+ * Platform "CPU" startup hook
+ */
+
+void prom_boot_secondary(int cpu, struct task_struct *idle)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ smtc_boot_secondary(cpu, idle);
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Post-config but pre-boot cleanup entry point
+ */
+
+void prom_init_secondary(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ void smtc_init_secondary(void);
+ int myvpe;
+
+ /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
+ myvpe = read_c0_tcbind() & TCBIND_CURVPE;
+ if (myvpe != 0) {
+ /* Ideally, this should be done only once per VPE, but... */
+ clear_c0_status(STATUSF_IP2);
+ set_c0_status(STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP3
+ | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6
+ | STATUSF_IP7);
+ }
+
+ smtc_init_secondary();
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Platform SMP pre-initialization
+ *
+ * As noted above, we can assume a single CPU for now
+ * but it may be multithreaded.
+ */
+
+void plat_smp_setup(void)
+{
+ if (read_c0_config3() & (1<<2))
+ mipsmt_build_cpu_map(0);
+}
+
+void __init plat_prepare_cpus(unsigned int max_cpus)
+{
+ if (read_c0_config3() & (1<<2))
+ mipsmt_prepare_cpus();
+}
+
+/*
+ * SMP initialization finalization entry point
+ */
+
+void prom_smp_finish(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ smtc_smp_finish();
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Hook for after all CPUs are online
+ */
+
+void prom_cpus_done(void)
+{
+}
+
+#endif /* CONFIG_MIPS32R2_MT_SMP */
diff --git a/arch/mips/mips-boards/sim/cmdline.c b/arch/mips/mips-boards/sim/cmdline.c
deleted file mode 100644
index fef9fbd8e710..000000000000
--- a/arch/mips/mips-boards/sim/cmdline.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Kernel command line creation using the prom monitor (YAMON) argc/argv.
- */
-#include <linux/init.h>
-#include <linux/string.h>
-
-#include <asm/bootinfo.h>
-
-extern int prom_argc;
-extern int *_prom_argv;
-
-/*
- * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
- * This macro take care of sign extension.
- */
-#define prom_argv(index) ((char *)(((int *)(int)_prom_argv)[(index)]))
-
-char arcs_cmdline[CL_SIZE];
-
-char * __init prom_getcmdline(void)
-{
- return &(arcs_cmdline[0]);
-}
-
-
-void __init prom_init_cmdline(void)
-{
- char *cp;
- int actr;
-
- actr = 1; /* Always ignore argv[0] */
-
- cp = &(arcs_cmdline[0]);
- while(actr < prom_argc) {
- strcpy(cp, prom_argv(actr));
- cp += strlen(prom_argv(actr));
- *cp++ = ' ';
- actr++;
- }
- if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
- --cp;
- *cp = '\0';
-}
diff --git a/arch/mips/mips-boards/sim/sim_cmdline.c b/arch/mips/mips-boards/sim/sim_cmdline.c
index 9df37c6fca36..c63021a5dc6c 100644
--- a/arch/mips/mips-boards/sim/sim_cmdline.c
+++ b/arch/mips/mips-boards/sim/sim_cmdline.c
@@ -26,8 +26,10 @@ char * __init prom_getcmdline(void)
return arcs_cmdline;
}
-
void __init prom_init_cmdline(void)
{
- /* nothing to do */
+ char *cp;
+ cp = arcs_cmdline;
+ /* Get boot line from environment? */
+ *cp = '\0';
}
diff --git a/arch/mips/mips-boards/sim/sim_smp.c b/arch/mips/mips-boards/sim/sim_smp.c
index a9f0c2bfe4ad..b7084e7c4bf9 100644
--- a/arch/mips/mips-boards/sim/sim_smp.c
+++ b/arch/mips/mips-boards/sim/sim_smp.c
@@ -44,8 +44,6 @@
void core_send_ipi(int cpu, unsigned int action)
{
#ifdef CONFIG_MIPS_MT_SMTC
- void smtc_send_ipi(int, int, unsigned int);
-
smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
#endif /* CONFIG_MIPS_MT_SMTC */
/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
@@ -59,15 +57,8 @@ void core_send_ipi(int cpu, unsigned int action)
void __init prom_build_cpu_map(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
- extern int mipsmt_build_cpu_map(int startslot);
int nextslot;
- cpus_clear(phys_cpu_present_map);
-
- /* Register the boot CPU */
-
- smp_prepare_boot_cpu();
-
/*
* As of November, 2004, MIPSsim only simulates one core
* at a time. However, that core may be a MIPS MT core
@@ -87,8 +78,6 @@ void __init prom_build_cpu_map(void)
void prom_boot_secondary(int cpu, struct task_struct *idle)
{
#ifdef CONFIG_MIPS_MT_SMTC
- extern void smtc_boot_secondary(int cpu, struct task_struct *t);
-
smtc_boot_secondary(cpu, idle);
#endif /* CONFIG_MIPS_MT_SMTC */
}
@@ -113,7 +102,6 @@ void prom_init_secondary(void)
void prom_prepare_cpus(unsigned int max_cpus)
{
#ifdef CONFIG_MIPS_MT_SMTC
- void mipsmt_prepare_cpus(int c);
/*
* As noted above, we can assume a single CPU for now
* but it may be multithreaded.
@@ -132,8 +120,6 @@ void prom_prepare_cpus(unsigned int max_cpus)
void prom_smp_finish(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
- void smtc_smp_finish(void);
-
smtc_smp_finish();
#endif /* CONFIG_MIPS_MT_SMTC */
}