From 048fea6c1fbbae09d78dd5d81f27437f01edc33e Mon Sep 17 00:00:00 2001 From: Kanoj Sarcar Date: Sun, 26 Mar 2000 03:56:59 +0000 Subject: ip27-irq.c, system.h: implement SMP intr on/off primitives similar to i386. process.c, smp.c: minor initialization code. SMP compiles still hang at the scsi probing stage, no improvements. --- arch/mips64/kernel/process.c | 1 + arch/mips64/kernel/smp.c | 10 +++ arch/mips64/sgi-ip27/ip27-irq.c | 194 ++++++++++++++++++++++++++++++++++++++-- include/asm-mips64/system.h | 25 ++++-- 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 #include #include +#include #include #include #include +#include /* 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 #include #include +#include #include #include @@ -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); -- cgit v1.2.3