summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
authorMiguel de Icaza <miguel@nuclecu.unam.mx>1997-08-06 19:14:48 +0000
committerMiguel de Icaza <miguel@nuclecu.unam.mx>1997-08-06 19:14:48 +0000
commite2819e52a162873ff5061de81bb749831bdb5de9 (patch)
tree6067ea700202750ba335a423696f2972700e5f76 /arch/sparc64/kernel
parent17a005074429bbf143e40401f405ae4363e56828 (diff)
Merge to 2.1.38.
IMPORTANT NOTE: I could not figure out what information is the one that should be used for the following files (ie, those that were in our tree, or those that came from Linus' patch), please, check these: include/asm-mips/jazz.h include/asm-mips/jazzdma.h include/asm-mips/ioctls.h
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/Makefile20
-rw-r--r--arch/sparc64/kernel/auxio.c3
-rw-r--r--arch/sparc64/kernel/cpu.c9
-rw-r--r--arch/sparc64/kernel/devices.c2
-rw-r--r--arch/sparc64/kernel/entry.S4
-rw-r--r--arch/sparc64/kernel/ioctl32.c19
-rw-r--r--arch/sparc64/kernel/ioport.c4
-rw-r--r--arch/sparc64/kernel/irq.c229
-rw-r--r--arch/sparc64/kernel/process.c66
-rw-r--r--arch/sparc64/kernel/setup.c8
-rw-r--r--arch/sparc64/kernel/smp.c136
-rw-r--r--arch/sparc64/kernel/time.c63
12 files changed, 381 insertions, 182 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 9e9013735..aecb9fd47 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.28 1997/07/05 09:52:20 davem Exp $
+# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -7,12 +7,24 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
+ifdef SMP
+
+.S.s:
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
+else
+
.S.s:
$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
.S.o:
$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+endif
+
all: kernel.o head.o init_task.o
O_TARGET := kernel.o
@@ -22,6 +34,10 @@ O_OBJS := process.o setup.o cpu.o idprom.o \
unaligned.o sys_sunos32.o sunos_ioctl32.o
OX_OBJS := sparc64_ksyms.o
+ifdef SMP
+O_OBJS += smp.o trampoline.o
+endif
+
ifdef CONFIG_SPARC32_COMPAT
O_OBJS += sys32.o sys_sparc32.o signal32.o ioctl32.o
endif
@@ -36,7 +52,7 @@ endif
head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \
winfixup.S entry.S
- $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
#
# This is just to get the dependencies...
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 6c3ff9174..00e5f2722 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -4,6 +4,9 @@
*/
#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
#include <linux/init.h>
#include <asm/oplib.h>
#include <asm/io.h>
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index d6cdf9162..2c96a83e9 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -6,6 +6,8 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
#include <asm/asi.h>
#include <asm/system.h>
#include <asm/fpumacro.h>
@@ -56,12 +58,7 @@ __initfunc(void cpu_probe(void))
long ver, fpu_vers;
long fprs;
-#ifndef __SMP__
- cpuid = 0;
-#else
-#error SMP not supported on sparc64 yet
- /* cpuid = get_cpuid(); */
-#endif
+ cpuid = smp_processor_id();
fprs = fprs_read ();
fprs_write (FPRS_FEF);
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 5e6705896..9327058a8 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -13,7 +13,7 @@
#include <asm/system.h>
#include <asm/smp.h>
-struct prom_cpuinfo linux_cpus[NCPUS];
+struct prom_cpuinfo linux_cpus[NR_CPUS];
int linux_num_cpus = 0;
extern void cpu_probe(void);
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index a410cfe80..425c2d873 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.50 1997/07/15 16:53:00 davem Exp $
+/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -206,7 +206,7 @@ fpdis_exit:
* flushing very quickly.
*/
.align 32
- .globl do_ivec
+ .globl do_ivec, do_ivec_return
do_ivec:
ldxa [%g0] ASI_INTR_RECEIVE, %g1
andcc %g1, 0x20, %g0
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index b7a0f312d..81eb45e42 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $
+/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -30,6 +30,7 @@
#include <asm/kbio.h>
#include <asm/vuid_event.h>
#include <asm/rtc.h>
+#include <asm/openpromio.h>
/* As gcc will warn about casting u32 to some ptr, we have to cast it to
* unsigned long first, and that's what is A() for.
@@ -697,6 +698,22 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case RTCGET:
case RTCSET:
+ /* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have
+ * embedded pointers in the arg which we'd need to clean up...
+ */
+ case OPROMGETOPT:
+ case OPROMSETOPT:
+ case OPROMNXTOPT:
+ case OPROMSETOPT2:
+ case OPROMNEXT:
+ case OPROMCHILD:
+ case OPROMGETPROP:
+ case OPROMNXTPROP:
+ case OPROMU2P:
+ case OPROMGETCONS:
+ case OPROMGETFBNAME:
+ case OPROMGETBOOTARGS:
+
/* Socket level stuff */
case FIOSETOWN:
case SIOCSPGRP:
diff --git a/arch/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c
index 390c33517..7d1580b39 100644
--- a/arch/sparc64/kernel/ioport.c
+++ b/arch/sparc64/kernel/ioport.c
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.10 1997/06/30 09:24:02 jj Exp $
+/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -83,7 +83,7 @@ void sparc_free_io (void *virtual, int len)
unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
- if (virtual >= PAGE_OFFSET + 0x10000000000UL)
+ if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL)
return;
release_region(vaddr, plen);
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index c4e7f0e74..f76c27c57 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.16 1997/07/11 03:03:08 davem Exp $
+/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -23,6 +23,7 @@
#include <asm/iommu.h>
#include <asm/upa.h>
#include <asm/oplib.h>
+#include <asm/timer.h>
#include <asm/smp.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
@@ -76,7 +77,7 @@ int get_irq_list(char *buf)
}
/* INO number to Sparc PIL level. */
-static unsigned char ino_to_pil[] = {
+unsigned char ino_to_pil[] = {
0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 0 */
0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 1 */
0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 2 */
@@ -391,7 +392,116 @@ int __sparc64_bh_counter = 0;
#define irq_exit(cpu, irq) (local_irq_count[cpu]--)
#else
-#error SMP not supported on sparc64 just yet
+
+atomic_t __sparc64_bh_counter = ATOMIC_INIT(0);
+
+/* Who has global_irq_lock. */
+unsigned char global_irq_holder = NO_PROC_ID;
+
+/* This protects IRQ's. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
+
+/* Global IRQ locking depth. */
+atomic_t global_irq_count = ATOMIC_INIT(0);
+
+static inline void wait_on_irq(int cpu)
+{
+ int local_count = local_irq_count[cpu];
+
+ while(local_count != atomic_read(&global_irq_count)) {
+ atomic_sub(local_count, &global_irq_count);
+ spin_unlock(&global_irq_lock);
+ for(;;) {
+ if (atomic_read(&global_irq_count))
+ continue;
+ if (*((unsigned char *)&global_irq_lock))
+ continue;
+ if (spin_trylock(&global_irq_lock))
+ break;
+ }
+ atomic_add(local_count, &global_irq_count);
+ }
+}
+
+static inline void get_irqlock(int cpu)
+{
+ if (!spin_trylock(&global_irq_lock)) {
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ do {
+ barrier();
+ } while (!spin_trylock(&global_irq_lock));
+ }
+ wait_on_irq(cpu);
+ global_irq_holder = cpu;
+}
+
+void __global_cli(void)
+{
+ int cpu = smp_processor_id();
+
+ __cli();
+ get_irqlock(cpu);
+}
+
+void __global_sti(void)
+{
+ release_irqlock(smp_processor_id());
+ __sti();
+}
+
+unsigned long __global_save_flags(void)
+{
+ return global_irq_holder == (unsigned char) smp_processor_id();
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ if (flags & 1) {
+ __global_cli();
+ } else {
+ if (global_irq_holder == (unsigned char) smp_processor_id()) {
+ global_irq_holder = NO_PROC_ID;
+ spin_unlock(&global_irq_lock);
+ }
+ if (!(flags & 2))
+ __sti();
+ }
+}
+
+void irq_enter(int cpu, int irq)
+{
+ hardirq_enter(cpu);
+ barrier();
+ while (*((unsigned char *)&global_irq_lock)) {
+ if ((unsigned char) cpu == global_irq_holder)
+ printk("irq_enter: Frosted Lucky Charms, "
+ "they're magically delicious!\n");
+ barrier();
+ }
+}
+
+void irq_exit(int cpu, int irq)
+{
+ hardirq_exit(cpu);
+ release_irqlock(cpu);
+}
+
+void synchronize_irq(void)
+{
+ int cpu = smp_processor_id();
+ int local_count = local_irq_count[cpu];
+ unsigned long flags;
+
+ if (local_count != atomic_read(&global_irq_count)) {
+ save_and_cli(flags);
+ restore_flags(flags);
+ }
+}
+
#endif /* __SMP__ */
void report_spurious_ivec(struct pt_regs *regs)
@@ -432,9 +542,7 @@ void handler_irq(int irq, struct pt_regs *regs)
struct irqaction *action;
int cpu = smp_processor_id();
- /* XXX */
- if(irq != 14)
- clear_softint(1 << irq);
+ clear_softint(1 << irq);
irq_enter(cpu, irq);
action = *(irq + irq_action);
@@ -575,53 +683,46 @@ int probe_irq_off(unsigned long mask)
return 0;
}
-/* XXX This is a hack, make it per-cpu so that SMP port will work correctly
- * XXX with mixed MHZ Ultras in the machine. -DaveM
- */
-static unsigned long cpu_cfreq;
-static unsigned long tick_offset;
+struct sun5_timer *linux_timers = NULL;
-/* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */
-static void timer_handler(int irq, void *dev_id, struct pt_regs *regs)
+/* This is called from sbus_init() to get the jiffies timer going.
+ * We need to call this after there exists a valid SBus_chain so
+ * that the IMAP/ICLR registers can be accessed.
+ *
+ * XXX That is because the whole startup sequence is broken. I will
+ * XXX fix it all up very soon. -DaveM
+ */
+void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
{
- if (!(get_softint () & 1)) {
- /* Just to be sure... */
- clear_softint(1 << 14);
- printk("Spurious level14 at %016lx\n", regs->tpc);
- return;
- } else {
- unsigned long compare, tick;
-
- do {
- extern void timer_interrupt(int, void *, struct pt_regs *);
-
- timer_interrupt(irq, dev_id, regs);
-
- /* Acknowledge INT_TIMER */
- clear_softint(1 << 0);
+ struct linux_prom64_registers pregs[3];
+ u32 pirqs[2];
+ int node, err;
- /* Set up for next timer tick. */
- __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
- "add %0, %2, %0\n\t"
- "wr %0, 0x0, %%tick_cmpr\n\t"
- "rd %%tick, %1"
- : "=&r" (compare), "=r" (tick)
- : "r" (tick_offset));
- } while(tick >= compare);
+ node = prom_finddevice("/counter-timer");
+ if(node == 0) {
+ prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
+ prom_halt();
}
-}
+ err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+ if(err == -1) {
+ prom_printf("init_timers: Cannot obtain 'reg' for counter-timer.\n");
+ prom_halt();
+ }
+ err = prom_getproperty(node, "interrupts", (char *)&pirqs[0], sizeof(pirqs));
+ if(err == -1) {
+ prom_printf("init_timers: Cannot obtain 'interrupts' "
+ "for counter-timer.\n");
+ prom_halt();
+ }
+ linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
-/* This is called from time_init() to get the jiffies timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
-{
- int node, err;
+ /* Shut it up first. */
+ linux_timers->limit0 = 0;
+
+ /* Register IRQ handler. */
+ err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
+ cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
- /* XXX FIX this for SMP -JJ */
- node = linux_cpus [0].prom_node;
- cpu_cfreq = prom_getint(node, "clock-frequency");
- tick_offset = cpu_cfreq / HZ;
- err = request_irq(14, timer_handler, (SA_INTERRUPT|SA_STATIC_ALLOC),
- "timer", NULL);
if(err) {
prom_printf("Serious problem, cannot register timer interrupt\n");
prom_halt();
@@ -630,27 +731,33 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
save_and_cli(flags);
- __asm__ __volatile__("wr %0, 0x0, %%tick_cmpr\n\t"
- "wrpr %%g0, 0x0, %%tick"
- : /* No outputs */
- : "r" (tick_offset));
-
- clear_softint (get_softint ());
+ /* Set things up so user can access tick register for profiling
+ * purposes.
+ */
+ __asm__ __volatile__("
+ sethi %%hi(0x80000000), %%g1
+ sllx %%g1, 32, %%g1
+ rd %%tick, %%g2
+ add %%g2, 6, %%g2
+ andn %%g2, %%g1, %%g2
+ wrpr %%g2, 0, %%tick
+" : /* no outputs */
+ : /* no inputs */
+ : "g1", "g2");
+
+ linux_timers->limit0 =
+ (SUN5_LIMIT_ENABLE | SUN5_LIMIT_ZRESTART | SUN5_LIMIT_TOZERO |
+ (SUN5_HZ_TO_LIMIT(HZ) & SUN5_LIMIT_CMASK));
restore_flags(flags);
}
+
sti();
}
-/* We use this nowhere else, so only define it's layout here. */
-struct sun5_timer {
- volatile u32 count0, _unused0;
- volatile u32 limit0, _unused1;
- volatile u32 count1, _unused2;
- volatile u32 limit1, _unused3;
-} *prom_timers;
+struct sun5_timer *prom_timers;
-static u32 prom_limit0, prom_limit1;
+static u64 prom_limit0, prom_limit1;
static void map_prom_timers(void)
{
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 89f63f78f..afd5af8d0 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $
+/* $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -50,9 +50,12 @@ asmlinkage int sys_idle(void)
return -EPERM;
/* endless idle loop with no priority at all */
+ current->priority = -100;
current->counter = -100;
- for (;;)
+ for (;;) {
+ run_task_queue(&tq_scheduler);
schedule();
+ }
return 0;
}
@@ -61,42 +64,27 @@ asmlinkage int sys_idle(void)
/*
* the idle loop on a UltraMultiPenguin...
*/
-asmlinkage int sys_idle(void)
+asmlinkage int cpu_idle(void)
{
- if (current->pid != 0)
- return -EPERM;
-
- /* endless idle loop with no priority at all */
- current->counter = -100;
- schedule();
- return 0;
+ current->priority = -100;
+ while(1) {
+ if(tq_scheduler) {
+ lock_kernel();
+ run_task_queue(&tq_scheduler);
+ unlock_kernel();
+ }
+ current->counter = -100;
+ schedule();
+ }
}
-/* This is being executed in task 0 'user space'. */
-int cpu_idle(void *unused)
+asmlinkage int sys_idle(void)
{
- volatile int *spap = &smp_process_available;
- volatile int cval;
+ if(current->pid != 0)
+ return -EPERM;
- while(1) {
- if(0==*spap)
- continue;
- cli();
- /* Acquire exclusive access. */
- while((cval = smp_swap(spap, -1)) == -1)
- while(*spap == -1)
- ;
- if (0==cval) {
- /* ho hum, release it. */
- *spap = 0;
- sti();
- continue;
- }
- /* Something interesting happened, whee... */
- *spap = (cval - 1);
- sti();
- idle();
- }
+ cpu_idle();
+ return 0;
}
#endif
@@ -467,7 +455,11 @@ void fault_in_user_windows(struct pt_regs *regs)
* allocate the task_struct and kernel stack in
* do_fork().
*/
+#ifdef __SMP__
+extern void ret_from_smpfork(void);
+#else
extern void ret_from_syscall(void);
+#endif
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
struct task_struct *p, struct pt_regs *regs)
@@ -485,7 +477,11 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
child_trap_frame = ((char *)p) + stack_offset;
memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size);
p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
+#ifdef __SMP__
+ p->tss.kpc = ((unsigned long) ret_from_smpfork) - 0x8;
+#else
p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
+#endif
p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
p->tss.cwp = regs->u_regs[UREG_G0];
if(regs->tstate & TSTATE_PRIV) {
@@ -495,6 +491,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.ctx = 0;
p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
} else {
+ if(current->tss.flags & SPARC_FLAG_32BIT) {
+ sp &= 0x00000000ffffffff;
+ regs->u_regs[UREG_FP] &= 0x00000000ffffffff;
+ }
p->tss.kregs->u_regs[UREG_FP] = sp;
p->tss.flags &= ~SPARC_FLAG_KTHREAD;
p->tss.current_ds = USER_DS;
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 680baf7de..7eb47e976 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.10 1997/07/08 11:07:47 jj Exp $
+/* $Id: setup.c,v 1.11 1997/07/24 12:15:05 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -405,11 +405,7 @@ extern char *mmu_info(void);
int get_cpuinfo(char *buffer)
{
-#ifndef __SMP__
- int cpuid=0;
-#else
-#error SMP not supported on sparc64 yet
-#endif
+ int cpuid=smp_processor_id();
return sprintf(buffer, "cpu\t\t: %s\n"
"fpu\t\t: %s\n"
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 88d7a8ecf..77ccf40a0 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -3,6 +3,26 @@
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tasks.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -13,8 +33,9 @@ volatile int smp_processors_ready = 0;
unsigned long cpu_present_map = 0;
int smp_num_cpus = 1;
int smp_threads_ready = 0;
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-struct cpuinfo_sparc64 cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS];
static unsigned char boot_cpu_id = 0;
static int smp_activated = 0;
@@ -52,11 +73,11 @@ void smp_store_cpu_info(int id)
void smp_commence(void)
{
- local_flush_cache_all();
- local_flush_tlb_all();
+ flush_cache_all();
+ flush_tlb_all();
smp_commenced = 1;
- local_flush_cache_all();
- local_flush_tlb_all();
+ flush_cache_all();
+ flush_tlb_all();
}
static void smp_setup_percpu_timer(void);
@@ -67,8 +88,8 @@ void smp_callin(void)
{
int cpuid = hard_smp_processor_id();
- local_flush_cache_all();
- local_flush_tlb_all();
+ flush_cache_all();
+ flush_tlb_all();
smp_setup_percpu_timer();
@@ -76,7 +97,7 @@ void smp_callin(void)
smp_store_cpu_info(cpuid);
callin_flag = 1;
__asm__ __volatile__("membar #Sync\n\t"
- "flush %g6" : : : "memory");
+ "flush %%g6" : : : "memory");
while(!task[cpuid])
barrier();
@@ -103,11 +124,18 @@ int start_secondary(void *unused)
return cpu_idle(NULL);
}
+void cpu_panic(void)
+{
+ printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
+ panic("SMP bolixed\n");
+}
+
extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+extern unsigned long sparc64_cpu_startup;
void smp_boot_cpus(void)
{
- int cpucount = 0, i, first, prev;
+ int cpucount = 0, i;
printk("Entering UltraSMPenguin Mode...\n");
__sti();
@@ -133,15 +161,15 @@ void smp_boot_cpus(void)
continue;
if(cpu_present_map & (1 << i)) {
- extern unsigned long sparc64_cpu_startup;
- unsigned long entry = (unsigned long)&sparc_cpu_startup;
struct task_struct *p;
int timeout;
kernel_thread(start_secondary, NULL, CLONE_PID);
p = task[++cpucount];
p->processor = i;
- prom_startcpu(linux_cpus[i].prom_node, entry, i);
+ prom_startcpu(linux_cpus[i].prom_node,
+ ((unsigned long)&sparc64_cpu_startup),
+ ((unsigned long)p));
for(timeout = 0; timeout < 5000000; timeout++) {
if(cpu_callin_map[i])
break;
@@ -190,49 +218,46 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
barrier();
}
-/* XXX Make it fast later. */
+static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
+{
+ u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
+
+ __asm__ __volatile__("
+ wrpr %0, %1, %%pstate
+ wr %%g0, %2, %%asi
+ stxa %3, [0x40] %%asi
+ stxa %4, [0x50] %%asi
+ stxa %5, [0x60] %%asi
+ stxa %%g0, [%6] %%asi
+ membar #Sync"
+ : /* No outputs */
+ : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
+ "r" (data0), "r" (data1), "r" (data2), "r" (target));
+
+ /* NOTE: PSTATE_IE is still clear. */
+ do {
+ __asm__ __volatile__("ldxa [%%g0] %1, %0"
+ : "=r" (result)
+ : "i" (ASI_INTR_DISPATCH_STAT));
+ } while(result & 0x1);
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+ : : "r" (pstate));
+ if(result & 0x2)
+ panic("Penguin NACK's master!");
+}
+
void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
{
if(smp_processors_ready) {
- unsigned long mask;
- u64 data0 = (((unsigned long)ctx)<<32 |
- (((unsigned long)func) & 0xffffffff));
- u64 pstate;
+ unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+ u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
int i, ncpus = smp_num_cpus;
__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
- mask = (cpu_present_map & ~(1 << smp_processor_id()));
for(i = 0; i < ncpus; i++) {
- if(mask & (1 << i)) {
- u64 target = mid<<14 | 0x70;
- u64 result;
-
- __asm__ __volatile__("
- wrpr %0, %1, %%pstate
- wrpr %%g0, %2, %%asi
- stxa %3, [0x40] %%asi
- stxa %4, [0x50] %%asi
- stxa %5, [0x60] %%asi
- stxa %%g0, [%6] %7
- membar #Sync"
- : /* No outputs */
- : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
- "r" (data0), "r" (data1), "r" (data2),
- "r" (target), "i" (ASI_UDB_INTR_W));
-
- /* NOTE: PSTATE_IE is still clear. */
- do {
- __asm__ __volatile__("ldxa [%%g0] %1, %0",
- : "=r" (result)
- : "i" (ASI_INTR_DISPATCH_STAT));
- } while(result & 0x1);
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
- : : "r" (pstate));
- if(result & 0x2)
- panic("Penguin NACK's master!");
- }
+ if(mask & (1 << i))
+ xcall_deliver(data0, data1, data2, pstate, i);
}
-
/* NOTE: Caller runs local copy on master. */
}
}
@@ -246,17 +271,19 @@ extern unsigned long xcall_flush_cache_all;
void smp_flush_cache_all(void)
{
smp_cross_call(&xcall_flush_cache_all, 0, 0, 0);
+ __flush_cache_all();
}
void smp_flush_tlb_all(void)
{
smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0);
+ __flush_tlb_all();
}
void smp_flush_tlb_mm(struct mm_struct *mm)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
__flush_tlb_mm(ctx);
}
@@ -265,7 +292,7 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
__flush_tlb_range(ctx, start, end);
}
@@ -275,7 +302,7 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
struct mm_struct *mm = vma->vm_mm;
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
__flush_tlb_page(ctx, page);
}
@@ -308,12 +335,12 @@ extern void update_one_process(struct task_struct *p, unsigned long ticks,
void smp_percpu_timer_interrupt(struct pt_regs *regs)
{
int cpu = smp_processor_id();
+ int user = user_mode(regs);
- clear_profile_irq(cpu);
- if(!user_mode(regs))
- sparc_do_profile(regs->pc);
+ /* XXX clear_profile_irq(cpu); */
+ if(!user)
+ sparc64_do_profile(regs->tpc);
if(!--prof_counter[cpu]) {
- int user = user_mode(regs);
if(current->pid) {
update_one_process(current, 1, user, !user);
if(--current->counter < 0) {
@@ -344,4 +371,5 @@ static void smp_setup_percpu_timer(void)
int setup_profiling_timer(unsigned int multiplier)
{
/* XXX implement me */
+ return 0;
}
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index ad40a5fb5..df6a1c05e 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.3 1997/06/17 13:25:29 jj Exp $
+/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,7 @@
#include <asm/oplib.h>
#include <asm/mostek.h>
+#include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -35,11 +36,17 @@ static int set_rtc_mmss(unsigned long);
* NOTE: On SUN5 systems the ticker interrupt comes in using 2
* interrupts, one at level14 and one with softint bit 0.
*/
-void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+extern struct sun5_timer *linux_timers;
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
/* last time the cmos clock got updated */
static long last_rtc_update=0;
+ __asm__ __volatile__("ldx [%0], %%g0"
+ : /* no outputs */
+ : "r" (&((linux_timers)->limit0)));
+
do_timer(regs);
/* Determine when to update the Mostek clock. */
@@ -239,14 +246,12 @@ __initfunc(static void clock_probe(void))
__initfunc(void time_init(void))
{
- extern void init_timers(void (*func)(int, void *, struct pt_regs *));
unsigned int year, mon, day, hour, min, sec;
struct mostek48t02 *mregs;
do_get_fast_time = do_gettimeofday;
clock_probe();
- init_timers(timer_interrupt);
mregs = mstk48t02_regs;
if(!mregs) {
@@ -266,6 +271,13 @@ __initfunc(void time_init(void))
mregs->creg &= ~MSTK_CREG_READ;
}
+extern void init_timers(void (*func)(int, void *, struct pt_regs *));
+
+__initfunc(void sun4u_start_timers(void))
+{
+ init_timers(timer_interrupt);
+}
+
static __inline__ unsigned long do_gettimeoffset(void)
{
unsigned long offset = 0;
@@ -286,16 +298,39 @@ static __inline__ unsigned long do_gettimeoffset(void)
void do_gettimeofday(struct timeval *tv)
{
- unsigned long flags;
-
- save_and_cli(flags);
- *tv = xtime;
- tv->tv_usec += do_gettimeoffset();
- if(tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
- }
- restore_flags(flags);
+ /* Load doubles must be used on xtime so that what we get
+ * is guarenteed to be atomic, this is why we can run this
+ * with interrupts on full blast. Don't touch this... -DaveM
+ */
+ __asm__ __volatile__("
+ sethi %hi(linux_timers), %o1
+ sethi %hi(xtime), %g2
+ ldx [%o1 + %lo(linux_timers)], %g3
+1: ldd [%g2 + %lo(xtime)], %o4
+ ldx [%g3], %o1
+ ldd [%g2 + %lo(xtime)], %o2
+ xor %o4, %o2, %o2
+ xor %o5, %o3, %o3
+ orcc %o2, %o3, %g0
+ bne,pn %icc, 1b
+ cmp %o1, 0
+ bge,pt %icc, 1f
+ sethi %hi(tick), %o3
+ ld [%o3 + %lo(tick)], %o3
+ sethi %hi(0x1fffff), %o2
+ or %o2, %lo(0x1fffff), %o2
+ add %o5, %o3, %o5
+ and %o1, %o2, %o1
+1: add %o5, %o1, %o5
+ sethi %hi(1000000), %o2
+ or %o2, %lo(1000000), %o2
+ cmp %o5, %o2
+ bl,a,pn %icc, 1f
+ st %o4, [%o0 + 0x0]
+ add %o4, 0x1, %o4
+ sub %o5, %o2, %o5
+ st %o4, [%o0 + 0x0]
+1: st %o5, [%o0 + 0x4]");
}
void do_settimeofday(struct timeval *tv)