summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips64/kernel/process.c1
-rw-r--r--arch/mips64/kernel/smp.c10
-rw-r--r--arch/mips64/sgi-ip27/ip27-irq.c194
-rw-r--r--include/asm-mips64/system.h25
4 files changed, 219 insertions, 11 deletions
diff --git a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c
index f6998a6bb..c2c077e35 100644
--- a/arch/mips64/kernel/process.c
+++ b/arch/mips64/kernel/process.c
@@ -33,6 +33,7 @@
asmlinkage int cpu_idle(void)
{
/* endless idle loop with no priority at all */
+ init_idle();
current->priority = 0;
current->counter = -100;
while (1) {
diff --git a/arch/mips64/kernel/smp.c b/arch/mips64/kernel/smp.c
index c0cd75e9a..7888fa01d 100644
--- a/arch/mips64/kernel/smp.c
+++ b/arch/mips64/kernel/smp.c
@@ -3,18 +3,28 @@
#include <linux/threads.h>
#include <linux/time.h>
#include <linux/timex.h>
+#include <linux/sched.h>
#include <asm/atomic.h>
#include <asm/processor.h>
#include <asm/system.h>
+#include <asm/hardirq.h>
/* The 'big kernel lock' */
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
int smp_threads_ready = 0;
+static void smp_tune_scheduling (void)
+{
+}
+
void __init smp_boot_cpus(void)
{
+ global_irq_holder = 0;
+ current->processor = 0;
+ init_idle();
+ smp_tune_scheduling();
}
static atomic_t smp_commenced = ATOMIC_INIT(0);
diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c
index ae096d28f..7d136db6f 100644
--- a/arch/mips64/sgi-ip27/ip27-irq.c
+++ b/arch/mips64/sgi-ip27/ip27-irq.c
@@ -18,6 +18,7 @@
#include <linux/random.h>
#include <linux/smp_lock.h>
#include <linux/kernel_stat.h>
+#include <linux/delay.h>
#include <asm/bitops.h>
#include <asm/bootinfo.h>
@@ -51,11 +52,6 @@
irq_cpustat_t irq_stat [NR_CPUS];
-#ifdef CONFIG_SMP
-int global_irq_holder = NO_PROC_ID;
-spinlock_t global_irq_lock;
-#endif
-
extern asmlinkage void ip27_irq(void);
int (*irq_cannonicalize)(int irq);
@@ -369,6 +365,7 @@ void free_irq(unsigned int irq, void *dev_id)
/* Useless ISA nonsense. */
unsigned long probe_irq_on (void)
{
+ panic("probe_irq_on called!\n");
return 0;
}
@@ -389,3 +386,190 @@ void __init init_IRQ(void)
bridge_init();
set_except_vector(0, ip27_irq);
}
+
+
+#ifdef CONFIG_SMP
+
+/*
+ * This following are the global intr on off routines, copied almost
+ * entirely from i386 code.
+ */
+
+int global_irq_holder = NO_PROC_ID;
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+
+extern void show_stack(unsigned long* esp);
+
+static void show(char * str)
+{
+ int i;
+ int cpu = smp_processor_id();
+
+ printk("\n%s, CPU %d:\n", str, cpu);
+ printk("irq: %d [",irqs_running());
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_irq_count(i));
+ printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_bh_count(i));
+
+ printk(" ]\nStack dumps:");
+ for(i = 0; i < smp_num_cpus; i++) {
+ unsigned long esp;
+ if (i == cpu)
+ continue;
+ printk("\nCPU %d:",i);
+ printk("Code not developed yet\n");
+ /* show_stack(0); */
+ }
+ printk("\nCPU %d:",cpu);
+ printk("Code not developed yet\n");
+ /* show_stack(NULL); */
+ printk("\n");
+}
+
+#define MAXCOUNT 100000000
+#define SYNC_OTHER_CORES(x) udelay(x+1)
+
+static inline void wait_on_irq(int cpu)
+{
+ int count = MAXCOUNT;
+
+ for (;;) {
+
+ /*
+ * Wait until all interrupts are gone. Wait
+ * for bottom half handlers unless we're
+ * already executing in one..
+ */
+ if (!irqs_running())
+ if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
+ break;
+
+ /* Duh, we have to loop. Release the lock to avoid deadlocks */
+ spin_unlock(&global_irq_lock);
+
+ for (;;) {
+ if (!--count) {
+ show("wait_on_irq");
+ count = ~0;
+ }
+ __sti();
+ SYNC_OTHER_CORES(cpu);
+ __cli();
+ if (irqs_running())
+ continue;
+ if (spin_is_locked(&global_irq_lock))
+ continue;
+ if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
+ continue;
+ if (spin_trylock(&global_irq_lock))
+ break;
+ }
+ }
+}
+
+void synchronize_irq(void)
+{
+ if (irqs_running()) {
+ /* Stupid approach */
+ cli();
+ sti();
+ }
+}
+
+static inline void get_irqlock(int cpu)
+{
+ if (!spin_trylock(&global_irq_lock)) {
+ /* do we already hold the lock? */
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ /* Uhhuh.. Somebody else got it. Wait.. */
+ spin_lock(&global_irq_lock);
+ }
+ /*
+ * We also to make sure that nobody else is running
+ * in an interrupt context.
+ */
+ wait_on_irq(cpu);
+
+ /*
+ * Ok, finally..
+ */
+ global_irq_holder = cpu;
+}
+
+#define SR_IE 1
+
+void __global_cli(void)
+{
+ unsigned int flags;
+
+ __save_flags(flags);
+ if (flags & SR_IE) {
+ int cpu = smp_processor_id();
+ __cli();
+ if (!local_irq_count(cpu))
+ get_irqlock(cpu);
+ }
+}
+
+void __global_sti(void)
+{
+ int cpu = smp_processor_id();
+
+ if (!local_irq_count(cpu))
+ release_irqlock(cpu);
+ __sti();
+}
+
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
+unsigned long __global_save_flags(void)
+{
+ int retval;
+ int local_enabled;
+ unsigned long flags;
+ int cpu = smp_processor_id();
+
+ __save_flags(flags);
+ local_enabled = (flags & SR_IE);
+ /* default to local */
+ retval = 2 + local_enabled;
+
+ /* check for global flags if we're not in an interrupt */
+ if (!local_irq_count(cpu)) {
+ if (local_enabled)
+ retval = 1;
+ if (global_irq_holder == cpu)
+ retval = 0;
+ }
+ return retval;
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ switch (flags) {
+ case 0:
+ __global_cli();
+ break;
+ case 1:
+ __global_sti();
+ break;
+ case 2:
+ __cli();
+ break;
+ case 3:
+ __sti();
+ break;
+ default:
+ printk("global_restore_flags: %08lx\n", flags);
+ }
+}
+
+#endif /* CONFIG_SMP */
diff --git a/include/asm-mips64/system.h b/include/asm-mips64/system.h
index 2d8559aee..e70c6141b 100644
--- a/include/asm-mips64/system.h
+++ b/include/asm-mips64/system.h
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.4 1999/12/04 03:59:12 ralf Exp $
+/* $Id: system.h,v 1.5 2000/01/27 07:48:08 kanoj Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -105,14 +105,27 @@ __restore_flags(int flags)
: "$8", "$9", "memory");
}
-/*
- * Non-SMP versions ...
- */
-#define sti() __sti()
+#ifdef __SMP__
+
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
+extern void __global_restore_flags(unsigned long);
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define save_flags(x) ((x)=__global_save_flags())
+#define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(flags); cli(); } while(0)
+
+#else
+
#define cli() __cli()
+#define sti() __sti()
#define save_flags(x) __save_flags(x)
-#define save_and_cli(x) __save_and_cli(x)
#define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+
+#endif /* __SMP__ */
/* For spinlocks etc */
#define local_irq_save(x) __save_and_cli(x);