diff options
-rw-r--r-- | arch/mips/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/kernel/entry.S | 1 | ||||
-rw-r--r-- | arch/mips/kernel/head.S | 49 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 30 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_misc.S | 17 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_switch.S | 12 | ||||
-rw-r--r-- | arch/mips/kernel/smp.c | 403 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 3 | ||||
-rw-r--r-- | include/asm-mips/hardirq.h | 49 | ||||
-rw-r--r-- | include/asm-mips/mmu_context.h | 22 | ||||
-rw-r--r-- | include/asm-mips/pgalloc.h | 2 | ||||
-rw-r--r-- | include/asm-mips/processor.h | 1 | ||||
-rw-r--r-- | include/asm-mips/smp.h | 30 | ||||
-rw-r--r-- | include/asm-mips/spinlock.h | 3 | ||||
-rw-r--r-- | include/asm-mips/stackframe.h | 24 | ||||
-rw-r--r-- | include/asm-mips/system.h | 29 |
16 files changed, 636 insertions, 40 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index ec2eae67e..10b8240aa 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -38,6 +38,7 @@ endif endif endif +obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MIPS_FPE_MODULE) += fpe.o ifndef CONFIG_MIPS_FPU_EMULATOR obj-y += softfp.o diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index bc56db51b..59bc8c2c9 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -12,6 +12,7 @@ #include <linux/config.h> #include <linux/sys.h> +#include <asm/addrspace.h> #include <asm/asm.h> #include <asm/current.h> #include <asm/errno.h> diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 529ebb57d..fb73d3db0 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -59,9 +59,19 @@ .set noat LEAF(except_vec0_r4000) .set mips3 +#ifdef CONFIG_SMP + mfc0 k1, CP0_CONTEXT + la k0, current_pgd + srl k1, 23 + sll k1, 2 + addu k1, k0, k1 + lw k1, (k1) +#else + lw k1, current_pgd # get pgd pointer +#endif mfc0 k0, CP0_BADVADDR # Get faulting address srl k0, k0, 22 # get pgd only bits - lw k1, current_pgd # get pgd pointer + sll k0, k0, 2 addu k1, k1, k0 # add in pgd offset mfc0 k0, CP0_CONTEXT # get context reg @@ -442,9 +452,9 @@ NESTED(kernel_entry, 16, sp) */ la $28, init_task_union addiu t0, $28, KERNEL_STACK_SIZE-32 - sw t0, kernelsp subu sp, t0, 4*SZREG + sw t0, kernelsp /* The firmware/bootloader passes argc/argp/envp * to us as arguments. But clear bss first because * the romvec and other important info is stored there @@ -462,6 +472,30 @@ NESTED(kernel_entry, 16, sp) nop END(kernel_entry) + +#ifdef CONFIG_SMP + +/* + * SMP slave cpus entry point. Board specific code + * for bootstrap calls this function after setting up + * the stack and gp registers. + */ + LEAF(smp_bootstrap) + .set push + .set noreorder + mtc0 zero, CP0_WIRED + CLI + mfc0 t0, CP0_STATUS + li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_BEV); + and t0, t1 + or t0, (ST0_CU0|ST0_KX|ST0_SX|ST0_FR); + addiu a0, zero, 0 + jal start_secondary + mtc0 t0, CP0_STATUS + .set pop + END(smp_bootstrap) +#endif + /* * This buffer is reserved for the use of the cache error handler. */ @@ -469,12 +503,19 @@ NESTED(kernel_entry, 16, sp) EXPORT(cache_error_buffer) .fill 32*4,1,0 +#ifndef CONFIG_SMP EXPORT(kernelsp) PTR 0 EXPORT(current_pgd) - PTR 0 + PTR 0 +#else + /* There's almost certainly a better way to do this with the macros...*/ + .globl kernelsp + .comm kernelsp, NR_CPUS * 8, 8 + .globl current_pgd + .comm current_pgd, NR_CPUS * 8, 8 +#endif .text - .org 0x1000 EXPORT(swapper_pg_dir) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 6cda842fd..9284db514 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -162,21 +162,21 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) long retval; __asm__ __volatile__( - ".set\tnoreorder\n\t" - "move\t$6,$sp\n\t" - "move\t$4,%5\n\t" - "li\t$2,%1\n\t" - "syscall\n\t" - "beq\t$6,$sp,1f\n\t" - "subu\t$sp,32\n\t" /* delay slot */ - "jalr\t%4\n\t" - "move\t$4,%3\n\t" /* delay slot */ - "move\t$4,$2\n\t" - "li\t$2,%2\n\t" - "syscall\n" - "1:\taddiu\t$sp,32\n\t" - "move\t%0,$2\n\t" - ".set\treorder" + ".set noreorder \n" + " move $6,$sp \n" + " move $4,%5 \n" + " li $2,%1 \n" + " syscall \n" + " beq $6,$sp,1f \n" + " subu $sp,32 \n" /* delay slot */ + " jalr %4 \n" + " move $4,%3 \n" /* delay slot */ + " move $4,$2 \n" + " li $2,%2 \n" + " syscall \n" + "1: addiu $sp,32 \n" + " move %0,$2 \n" + ".set reorder" :"=r" (retval) :"i" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn), diff --git a/arch/mips/kernel/r4k_misc.S b/arch/mips/kernel/r4k_misc.S index bfa3cb82c..e16820f88 100644 --- a/arch/mips/kernel/r4k_misc.S +++ b/arch/mips/kernel/r4k_misc.S @@ -35,10 +35,25 @@ * in register PTE, a ptr into the table in which * the pte belongs is in PTR. */ + +#ifdef CONFIG_SMP +#define GET_PGD(scratch, ptr) \ + mfc0 ptr, CP0_CONTEXT; \ + la scratch, current_pgd;\ + srl ptr, 23; \ + sll ptr, 2; \ + addu ptr, scratch, ptr; \ + lw ptr, (ptr); +#else +#define GET_PGD(scratch, ptr) \ + lw ptr, current_pgd; +#endif + + #define LOAD_PTE(pte, ptr) \ + GET_PGD(pte, ptr) \ mfc0 pte, CP0_BADVADDR; \ srl pte, pte, 22; \ - lw ptr, current_pgd; \ sll pte, pte, 2; \ addu ptr, ptr, pte; \ mfc0 pte, CP0_BADVADDR; \ diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index e1d10f92d..10328f4ad 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -1,5 +1,4 @@ -/* $Id: r4k_switch.S,v 1.9 1999/08/18 23:37:44 ralf 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 * for more details. @@ -50,7 +49,16 @@ move $28, a1 CPU_RESTORE_NONSCRATCH($28) addiu t0, $28, KERNEL_STACK_SIZE-32 +#ifdef CONFIG_SMP + mfc0 a3, CP0_CONTEXT + la t1, kernelsp + srl a3, 23 + sll a3, 2 + addu t1, a3, t1 + sw t0, (t1) +#else sw t0, kernelsp +#endif mfc0 t1, CP0_STATUS /* Do we really need this? */ li a3, 0xff00 and t1, a3 diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c new file mode 100644 index 000000000..12653eb87 --- /dev/null +++ b/arch/mips/kernel/smp.c @@ -0,0 +1,403 @@ +/* + * + * arch/mips/kernel/smp.c + * + * Copyright (C) 2000 Sibyte + * + * Written by Justin Carlson (carlson@sibyte.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that 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. + * + */ + + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/threads.h> +#include <linux/time.h> +#include <linux/timex.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include <asm/atomic.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/hardirq.h> +#include <asm/softirq.h> +#include <asm/mmu_context.h> +#include <asm/delay.h> +#include <asm/smp.h> + +/* + * This was written with the BRCM12500 MP SOC in mind, but tries to + * be generic. It's modelled on the mips64 smp.c code, which is + * derived from Sparc, I'm guessing, which is derived from... + * + * It's probably horribly designed for very large ccNUMA systems + * as it doesn't take any node clustering into account. +*/ + + +/* Ze Big Kernel Lock! */ +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +int smp_threads_ready; /* Not used */ +int smp_num_cpus; +int global_irq_holder = NO_PROC_ID; +spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; +struct mips_cpuinfo cpu_data[NR_CPUS]; + +struct smp_fn_call_struct smp_fn_call = +{ SPIN_LOCK_UNLOCKED, ATOMIC_INIT(0), NULL, NULL}; + +static atomic_t cpus_booted = ATOMIC_INIT(0); + + +/* These are defined by the board-specific code. */ + +/* Cause the function described by smp_fn_call + to be executed on the passed cpu. When the function + has finished, increment the finished field of + smp_fn_call. */ + +void core_call_function(int cpu); + +/* + Clear all undefined state in the cpu, set up sp and gp to the passed + values, and kick the cpu into smp_bootstrap(); +*/ +void prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp); + +/* + * After we've done initial boot, this function is called to allow the + * board code to clean up state, if needed + */ + +void prom_init_secondary(void); + + +void cpu_idle(void); + +/* Do whatever setup needs to be done for SMP at the board level. Return + the number of cpus in the system, including this one */ +int prom_setup_smp(void); + +int start_secondary(void *unused) +{ + prom_init_secondary(); + write_32bit_cp0_register(CP0_CONTEXT, smp_processor_id()<<23); + current_pgd[smp_processor_id()] = init_mm.pgd; + printk("Slave cpu booted successfully\n"); + atomic_inc(&cpus_booted); + cpu_idle(); + return 0; +} + +void __init smp_boot_cpus(void) +{ + int i; + smp_num_cpus = prom_setup_smp(); + init_new_context(current, &init_mm); + current->processor = 0; + atomic_set(&cpus_booted, 1); /* Master CPU is already booted... */ + init_idle(); + for (i = 1; i < smp_num_cpus; i++) { + struct task_struct *p; + struct pt_regs regs; + printk("Starting CPU %d... ", i); + + /* Spawn a new process normally. Grab a pointer to + its task struct so we can mess with it */ + do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); + p = init_task.prev_task; + + /* Schedule the first task manually */ + + p->processor = i; + p->has_cpu = 1; + + /* Attach to the address space of init_task. */ + atomic_inc(&init_mm.mm_count); + p->active_mm = &init_mm; + init_tasks[i] = p; + + del_from_runqueue(p); + unhash_process(p); + + prom_boot_secondary(i, + (unsigned long)p + KERNEL_STACK_SIZE - 32, + (unsigned long)p); + +#if 0 + + /* This is copied from the ip-27 code in the mips64 tree */ + + struct task_struct *p; + + /* + * The following code is purely to make sure + * Linux can schedule processes on this slave. + */ + kernel_thread(0, NULL, CLONE_PID); + p = init_task.prev_task; + sprintf(p->comm, "%s%d", "Idle", i); + init_tasks[i] = p; + p->processor = i; + p->has_cpu = 1; /* we schedule the first task manually */ + del_from_runqueue(p); + unhash_process(p); + /* Attach to the address space of init_task. */ + atomic_inc(&init_mm.mm_count); + p->active_mm = &init_mm; + prom_boot_secondary(i, + (unsigned long)p + KERNEL_STACK_SIZE - 32, + (unsigned long)p); +#endif + } + /* Wait for everyone to come up */ + while (atomic_read(&cpus_booted) != smp_num_cpus) {} +} + +void __init smp_commence(void) +{ + /* Not sure what to do here yet */ +} + +static void reschedule_this_cpu(void *dummy) +{ + current->need_resched = 1; +} + +void FASTCALL(smp_send_reschedule(int cpu)) +{ + smp_call_function(reschedule_this_cpu, NULL, 0, 0); +} + + +/* The caller of this wants the passed function to run on every cpu. If + wait is set, wait until all cpus have finished the function before + returning. The lock is here to protect the call structure. */ +int smp_call_function (void (*func) (void *info), void *info, int retry, + int wait) +{ + int i; + int cpus = smp_num_cpus - 1; + +// unsigned long flags; + + if (smp_num_cpus < 2) { + return 0; + } + + spin_lock_bh(&smp_fn_call.lock); + + atomic_set(&smp_fn_call.finished, 0); + smp_fn_call.fn = func; + smp_fn_call.data = info; + + for (i = 0; i < smp_num_cpus; i++) { + if (i != smp_processor_id()) { + /* Call the board specific routine */ + core_call_function(i); + } + } + + if (wait) { + while(atomic_read(&smp_fn_call.finished) != cpus) {} + } + + spin_unlock_bh(&smp_fn_call.lock); + return 0; +} + +void synchronize_irq(void) +{ + panic("synchronize_irq"); +} + +static void stop_this_cpu(void *dummy) +{ + printk("Cpu stopping\n"); + for (;;); +} + +void smp_send_stop(void) +{ + smp_call_function(stop_this_cpu, NULL, 1, 0); + smp_num_cpus = 1; +} + +/* Not really SMP stuff ... */ +int setup_profiling_timer(unsigned int multiplier) +{ + return 0; +} + + +/* Most of this code is take from the mips64 tree (ip27-irq.c). It's virtually identical + to the i386 implentation in arh/i386/irq.c, with translations for the interrupt enable bit */ + + +#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) { + printk("Count spun out. Huh?\n"); + 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; + } + } +} + + +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; +} + + +/* + * A global "cli()" while in an interrupt context + * turns into just a local cli(). Interrupts + * should use spinlocks for the (very unlikely) + * case that they ever want to protect against + * each other. + * + * If we already have local interrupts disabled, + * this will not turn a local disable into a + * global one (problems with spinlocks: this makes + * save_flags+cli+sti usable inside a spinlock). + */ +void __global_cli(void) +{ + unsigned int flags; + + __save_flags(flags); + if (flags & ST0_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 & ST0_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); + } +} + + + diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e2c3663cb..85767362e 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -938,5 +938,6 @@ void __init trap_init(void) atomic_inc(&init_mm.mm_count); /* XXX UP? */ current->active_mm = &init_mm; - current_pgd = init_mm.pgd; + write_32bit_cp0_register(CP0_CONTEXT, smp_processor_id()<<23); + current_pgd[0] = init_mm.pgd; } diff --git a/include/asm-mips/hardirq.h b/include/asm-mips/hardirq.h index 3896706c7..28340dff3 100644 --- a/include/asm-mips/hardirq.h +++ b/include/asm-mips/hardirq.h @@ -12,6 +12,7 @@ #include <linux/config.h> #include <linux/threads.h> #include <linux/irq.h> +#include <linux/spinlock.h> /* entry.S is sensitive to the offsets of these fields */ typedef struct { @@ -44,7 +45,53 @@ typedef struct { #else -#error No habla MIPS SMP +#include <asm/atomic.h> +#include <linux/spinlock.h> +#include <asm/smp.h> + +extern int global_irq_holder; +extern spinlock_t global_irq_lock; + +static inline int irqs_running (void) +{ + int i; + + for (i = 0; i < smp_num_cpus; i++) + if (local_irq_count(i)) + return 1; + return 0; +} + +static inline void release_irqlock(int cpu) +{ + /* if we didn't own the irq lock, just ignore.. */ + if (global_irq_holder == cpu) { + global_irq_holder = NO_PROC_ID; + spin_unlock(&global_irq_lock); + } +} + +static inline int hardirq_trylock(int cpu) +{ + return !local_irq_count(cpu) && !spin_is_locked(&global_irq_lock); +} + +#define hardirq_endlock(cpu) do { } while (0) + +static inline void irq_enter(int cpu, int irq) +{ + ++local_irq_count(cpu); + + while (spin_is_locked(&global_irq_lock)) + barrier(); +} + +static inline void irq_exit(int cpu, int irq) +{ + --local_irq_count(cpu); +} + +extern void synchronize_irq(void); #endif /* CONFIG_SMP */ #endif /* _ASM_HARDIRQ_H */ diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h index 5912b9966..775e2d370 100644 --- a/include/asm-mips/mmu_context.h +++ b/include/asm-mips/mmu_context.h @@ -1,5 +1,4 @@ -/* $Id: mmu_context.h,v 1.7 2000/02/04 07:40:53 ralf Exp $ - * +/* * Switch a MMU context. * * This file is subject to the terms and conditions of the GNU General Public @@ -13,11 +12,12 @@ #define _ASM_MMU_CONTEXT_H #include <linux/config.h> +#include <linux/slab.h> #include <asm/pgalloc.h> /* Fuck. The f-word is here so you can grep for it :-) */ extern unsigned long asid_cache; -extern pgd_t *current_pgd; +extern pgd_t *current_pgd[]; #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R3912) @@ -60,7 +60,19 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long asid) extern inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { +#ifndef CONFIG_SMP mm->context = 0; +#else + mm->context = (unsigned long)kmalloc(smp_num_cpus * + sizeof(unsigned long), GFP_KERNEL); + /* + * Init the "context" values so that a tlbpid allocation + * happens on the first switch. + */ + if (mm->context == 0) + return -ENOMEM; + memset((void *)mm->context, 0, smp_num_cpus * sizeof(unsigned long)); +#endif return 0; } @@ -73,7 +85,7 @@ extern inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, if ((next->context ^ asid) & ASID_VERSION_MASK) get_new_mmu_context(next, asid); - current_pgd = next->pgd; + current_pgd[cpu] = next->pgd; set_entryhi(next->context); } @@ -96,7 +108,7 @@ activate_mm(struct mm_struct *prev, struct mm_struct *next) /* Unconditionally get a new ASID. */ get_new_mmu_context(next, asid_cache); - current_pgd = next->pgd; + current_pgd[smp_processor_id()] = next->pgd; set_entryhi(next->context); } diff --git a/include/asm-mips/pgalloc.h b/include/asm-mips/pgalloc.h index 4f8c74dcf..0fa39f666 100644 --- a/include/asm-mips/pgalloc.h +++ b/include/asm-mips/pgalloc.h @@ -10,6 +10,7 @@ #define _ASM_PGALLOC_H #include <linux/config.h> +#include <linux/mm.h> /* TLB flushing: * @@ -177,6 +178,7 @@ extern inline void pmd_free(pmd_t * pmd) extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address) { + /* Two level page tables. This level is a nop */ return (pmd_t *) pgd; } diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h index d658a010e..b0273cca1 100644 --- a/include/asm-mips/processor.h +++ b/include/asm-mips/processor.h @@ -29,6 +29,7 @@ #include <asm/system.h> struct mips_cpuinfo { + unsigned long udelay_val; unsigned long *pgd_quick; unsigned long *pte_quick; unsigned long pgtable_cache_sz; diff --git a/include/asm-mips/smp.h b/include/asm-mips/smp.h index 601826429..831dccafd 100644 --- a/include/asm-mips/smp.h +++ b/include/asm-mips/smp.h @@ -1,6 +1,36 @@ #ifndef __ASM_MIPS_SMP_H #define __ASM_MIPS_SMP_H +#include <linux/config.h> +#include <asm/spinlock.h> +#include <asm/atomic.h> +#include <asm/current.h> + +#ifdef CONFIG_SMP + + +/* Mappings are straight across. If we want + to add support for disabling cpus and such, + we'll have to do what the mips64 port does here */ #define cpu_logical_map(cpu) (cpu) +#define cpu_number_map(cpu) (cpu) + +#define smp_processor_id() (current->processor) + + +/* I've no idea what the real meaning of this is */ +#define PROC_CHANGE_PENALTY 20 + +#define NO_PROC_ID (-1) + +struct smp_fn_call_struct { + spinlock_t lock; + atomic_t finished; + void (*fn)(void *); + void *data; +}; + +extern struct smp_fn_call_struct smp_fn_call; +#endif /* CONFIG_SMP */ #endif /* __ASM_MIPS_SMP_H */ diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h index 4ac282bbc..61ebfa660 100644 --- a/include/asm-mips/spinlock.h +++ b/include/asm-mips/spinlock.h @@ -21,6 +21,9 @@ typedef struct { #define spin_lock_init(x) do { (x)->lock = 0; } while(0); +#define spin_is_locked(x) ((x)->lock != 0) +#define spin_unlock_wait(x) ({ do { barrier(); } while ((x)->lock); }) + /* * Simple spin lock operations. There are two variants, one clears IRQ's * on the local processor, one does not. diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h index 2f436e79f..127654aab 100644 --- a/include/asm-mips/stackframe.h +++ b/include/asm-mips/stackframe.h @@ -8,6 +8,9 @@ #ifndef __ASM_MIPS_STACKFRAME_H #define __ASM_MIPS_STACKFRAME_H +#include <asm/addrspace.h> +#include <asm/mipsregs.h> +#include <asm/processor.h> #include <asm/asm.h> #include <asm/offset.h> #include <linux/config.h> @@ -70,6 +73,22 @@ __asm__ ( \ /* Used in declaration of save_static functions. */ #define static_unused static __attribute__((unused)) + +#ifdef CONFIG_SMP +# define GET_SAVED_SP \ + mfc0 k0, CP0_CONTEXT; \ + lui k1, %hi(kernelsp); \ + srl k0, k0, 23; \ + sll k0, k0, 2; \ + addu k1, k0; \ + lw k1, %lo(kernelsp)(k1); + +#else +# define GET_SAVED_SP \ + lui k1, %hi(kernelsp); \ + lw k1, %lo(kernelsp)(k1); +#endif + #define SAVE_SOME \ .set push; \ .set reorder; \ @@ -80,13 +99,12 @@ __asm__ ( \ move k1, sp; \ .set reorder; \ /* Called from user mode, new stack. */ \ - lui k1, %hi(kernelsp); \ - lw k1, %lo(kernelsp)(k1); \ + GET_SAVED_SP \ 8: \ move k0, sp; \ subu sp, k1, PT_SIZE; \ sw k0, PT_R29(sp); \ - sw $3, PT_R3(sp); \ + sw $3, PT_R3(sp); \ sw $0, PT_R0(sp); \ mfc0 v1, CP0_STATUS; \ sw $2, PT_R2(sp); \ diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index 68117be89..1c1c8c575 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -115,14 +115,27 @@ do { \ : "$1", "memory"); \ } while(0) -/* - * Non-SMP versions ... - */ -#define sti() __sti() -#define cli() __cli() -#define save_flags(x) __save_flags(x) -#define save_and_cli(x) __save_and_cli(x) -#define restore_flags(x) __restore_flags(x) +#ifdef CONFIG_SMP + +extern void __global_sti(void); +extern void __global_cli(void); +extern unsigned long __global_save_flags(void); +extern void __global_restore_flags(unsigned long); +# define sti() __global_sti() +# define cli() __global_cli() +# define save_flags(x) do { x = __global_save_flags(); } while (0) +# define restore_flags(x) __global_restore_flags(x) +# define save_and_cli(x) do { save_flags(x); cli(); } while(0) + +#else /* Single processor */ + +# define sti() __sti() +# define cli() __cli() +# define save_flags(x) __save_flags(x) +# define save_and_cli(x) __save_and_cli(x) +# define restore_flags(x) __restore_flags(x) + +#endif /* SMP */ /* For spinlocks etc */ #define local_irq_save(x) __save_and_cli(x); |