summaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/Makefile2
-rw-r--r--arch/sparc/kernel/devices.c18
-rw-r--r--arch/sparc/kernel/entry.S40
-rw-r--r--arch/sparc/kernel/head.S19
-rw-r--r--arch/sparc/kernel/irq.c201
-rw-r--r--arch/sparc/kernel/pcic.c9
-rw-r--r--arch/sparc/kernel/process.c131
-rw-r--r--arch/sparc/kernel/ptrace.c12
-rw-r--r--arch/sparc/kernel/setup.c24
-rw-r--r--arch/sparc/kernel/signal.c76
-rw-r--r--arch/sparc/kernel/smp.c1
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c7
-rw-r--r--arch/sparc/kernel/sun4d_irq.c4
-rw-r--r--arch/sparc/kernel/sun4d_smp.c2
-rw-r--r--arch/sparc/kernel/sun4m_irq.c4
-rw-r--r--arch/sparc/kernel/sun4m_smp.c6
-rw-r--r--arch/sparc/kernel/sys_sparc.c13
-rw-r--r--arch/sparc/kernel/systbls.S8
-rw-r--r--arch/sparc/kernel/time.c19
-rw-r--r--arch/sparc/kernel/traps.c28
-rw-r--r--arch/sparc/kernel/unaligned.c4
21 files changed, 402 insertions, 226 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index d5f65dda3..f4d5e3f67 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.48 1998/09/21 05:04:46 jj Exp $
+# $Id: Makefile,v 1.49 1999/01/02 16:45:37 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index 69f3070e5..11f1587dd 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -29,24 +29,25 @@ device_scan(unsigned long mem_start))
prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+ prom_printf("Booting Linux...\n");
if(strcmp(node_str, "cpu") == 0) {
linux_num_cpus++;
} else {
int scan;
scan = prom_getchild(prom_root_node);
- prom_printf("root child is %08lx\n", (unsigned long) scan);
+ /* One can look it up in PROM instead */
+ /* prom_printf("root child is %08lx\n", (unsigned long) scan); */
while((scan = prom_getsibling(scan)) != 0) {
prom_getstring(scan, "device_type", node_str, sizeof(node_str));
if(strcmp(node_str, "cpu") == 0) {
linux_cpus[linux_num_cpus].prom_node = scan;
prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
linux_cpus[linux_num_cpus].mid = thismid;
- prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
- linux_num_cpus, (unsigned long) scan,
- thismid);
+ /* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid); */
+ printk("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid);
linux_num_cpus++;
}
- };
+ }
if(linux_num_cpus == 0) {
if (sparc_cpu_model == sun4d) {
scan = prom_getchild(prom_root_node);
@@ -59,9 +60,10 @@ device_scan(unsigned long mem_start))
prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
linux_cpus[linux_num_cpus].prom_node = node;
linux_cpus[linux_num_cpus].mid = thismid;
- prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
- linux_num_cpus, (unsigned long) node,
- thismid);
+ /* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
+ linux_num_cpus, (unsigned long) node, thismid); */
+ printk("Found CPU %d <node=%08lx,mid=%d>\n",
+ linux_num_cpus, (unsigned long) node, thismid);
linux_num_cpus++;
}
}
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index d628c0c8d..8eeac72b0 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1,10 +1,10 @@
-/* $Id: entry.S,v 1.153 1998/11/11 15:12:33 jj Exp $
+/* $Id: entry.S,v 1.159 1999/05/08 03:00:03 davem Exp $
* arch/sparc/kernel/entry.S: Sparc trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
*/
@@ -874,7 +874,7 @@ C_LABEL(vac_hwflush_patch2_on): sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG
! We want error in %l5, vaddr in %l6
sun4c_fault:
#ifdef CONFIG_SUN4
- sethi C_LABEL(sun4c_memerr_reg), %l4
+ sethi %hi(C_LABEL(sun4c_memerr_reg)), %l4
ld [%l4+%lo(C_LABEL(sun4c_memerr_reg))], %l4 ! memerr ctrl reg addr
ld [%l4], %l6 ! memerr ctrl reg
ld [%l4 + 4], %l5 ! memerr vaddr reg
@@ -956,7 +956,7 @@ sun4c_fault:
sll %l6, 2, %l6
ld [%l4 + %l6], %l4
#ifdef CONFIG_SUN4
- sethi PAGE_MASK, %l6
+ sethi %hi(PAGE_MASK), %l6
andcc %l4, %l6, %g0
#else
andcc %l4, PAGE_MASK, %g0
@@ -1117,7 +1117,7 @@ C_LABEL(num_context_patch2):
#ifndef CONFIG_SUN4
and %l4, PAGE_MASK, %l4
#else
- sethi PAGE_MASK, %l6
+ sethi %hi(PAGE_MASK), %l6
and %l4, %l6, %l4
#endif
@@ -1380,11 +1380,13 @@ C_LABEL(sys_rt_sigreturn):
/* Now that we have a real sys_clone, sys_fork() is
* implemented in terms of it. Our _real_ implementation
- * of SunOS vfork() will use sys_clone() instead.
+ * of SunOS vfork() will use sys_vfork().
+ *
+ * XXX These three should be consolidated into mostly shared
+ * XXX code just like on sparc64... -DaveM
*/
.align 4
- .globl C_LABEL(sys_fork), C_LABEL(sys_vfork), flush_patch_two
-C_LABEL(sys_vfork):
+ .globl C_LABEL(sys_fork), flush_patch_two
C_LABEL(sys_fork):
mov %o7, %l5
flush_patch_two:
@@ -1422,6 +1424,23 @@ flush_patch_three:
call C_LABEL(do_fork)
mov %l5, %o7
+ /* Whee, real vfork! */
+ .globl C_LABEL(sys_vfork), flush_patch_four
+C_LABEL(sys_vfork):
+flush_patch_four:
+ FLUSH_ALL_KERNEL_WINDOWS;
+ rd %psr, %g4
+ WRITE_PAUSE
+ rd %wim, %g5
+ WRITE_PAUSE
+ std %g4, [%curptr + AOFF_task_tss + AOFF_thread_fork_kpsr]
+ sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0
+ mov %fp, %o1
+ or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
+ sethi %hi(C_LABEL(do_fork)), %l1
+ jmpl %l1 + %lo(C_LABEL(do_fork)), %g0
+ add %sp, REGWIN_SZ, %o2
+
.align 4
linux_sparc_ni_syscall:
sethi %hi(C_LABEL(sys_ni_syscall)), %l7
@@ -1454,11 +1473,10 @@ C_LABEL(ret_from_syscall):
#ifdef __SMP__
.globl C_LABEL(ret_from_smpfork)
C_LABEL(ret_from_smpfork):
- /* Nowadays all we need to do is drop the scheduler lock. */
- sethi %hi(C_LABEL(scheduler_lock)), %o4
- stb %g0, [%o4 + %lo(C_LABEL(scheduler_lock))]
wr %l0, PSR_ET, %psr
WRITE_PAUSE
+ call schedule_tail
+ mov %g3, %o0
b C_LABEL(ret_sys_call)
ld [%sp + REGWIN_SZ + PT_I0], %o0
#endif
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 9c396c928..0020770e0 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.92 1998/06/10 07:21:55 davem Exp $
+/* $Id: head.S,v 1.95 1999/04/13 07:40:34 anton Exp $
* head.S: The initial boot code for the Sparc port of Linux.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -408,13 +408,11 @@ C_LABEL(trapbase_cpu3):
/* This was the only reasonable way I could think of to properly align
* these page-table data structures.
*/
- .globl C_LABEL(bootup_user_stack)
.globl C_LABEL(pg0), C_LABEL(pg1), C_LABEL(pg2), C_LABEL(pg3)
.globl C_LABEL(empty_bad_page)
.globl C_LABEL(empty_bad_page_table)
.globl C_LABEL(empty_zero_page)
.globl C_LABEL(swapper_pg_dir)
-C_LABEL(bootup_user_stack): .skip 0x2000
C_LABEL(swapper_pg_dir): .skip PAGE_SIZE
C_LABEL(pg0): .skip PAGE_SIZE
C_LABEL(pg1): .skip PAGE_SIZE
@@ -427,8 +425,8 @@ C_LABEL(empty_zero_page): .skip PAGE_SIZE
.global C_LABEL(root_flags)
.global C_LABEL(ram_flags)
.global C_LABEL(root_dev)
- .global C_LABEL(ramdisk_image)
- .global C_LABEL(ramdisk_size)
+ .global C_LABEL(sparc_ramdisk_image)
+ .global C_LABEL(sparc_ramdisk_size)
/* This stuff has to be in sync with SILO and other potential boot loaders
* Fields should be kept upward compatible and whenever any change is made,
@@ -443,9 +441,9 @@ C_LABEL(root_dev):
.half 0
C_LABEL(ram_flags):
.half 0
-C_LABEL(ramdisk_image):
+C_LABEL(sparc_ramdisk_image):
.word 0
-C_LABEL(ramdisk_size):
+C_LABEL(sparc_ramdisk_size):
.word 0
.word C_LABEL(reboot_command)
@@ -1005,8 +1003,8 @@ sun4c_continue_boot:
WRITE_PAUSE
/* I want a kernel stack NOW! */
- set C_LABEL(bootup_user_stack), %g1
- set (0x2000 - REGWIN_SZ), %g2
+ set C_LABEL(init_task_union), %g1
+ set (TASK_UNION_SIZE - REGWIN_SZ), %g2
add %g1, %g2, %sp
mov 0, %fp /* And for good luck */
@@ -1110,6 +1108,9 @@ sun4c_continue_boot:
set flush_patch_three, %g5
st %g4, [%g5 + 0x18]
st %g4, [%g5 + 0x1c]
+ set flush_patch_four, %g5
+ st %g4, [%g5 + 0x18]
+ st %g4, [%g5 + 0x1c]
set flush_patch_exception, %g5
st %g4, [%g5 + 0x18]
st %g4, [%g5 + 0x1c]
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 4c8f78c8a..26f3194bd 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj Exp $
+/* $Id: irq.c,v 1.93 1999/04/21 06:15:45 anton Exp $
* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
@@ -8,7 +8,7 @@
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com)
* Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
- * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au)
*/
#include <linux/config.h>
@@ -24,6 +24,8 @@
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/tasks.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -192,12 +194,18 @@ void free_irq(unsigned int irq, void *dev_id)
restore_flags(flags);
}
-/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */
+#ifndef __SMP__
+unsigned int local_bh_count;
+unsigned int local_irq_count;
+
+#else
+/* SMP interrupt locking on Sparc. */
+
unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
-#ifdef __SMP__
-/* SMP interrupt locking on Sparc. */
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED;
/* Who has global_irq_lock. */
unsigned char global_irq_holder = NO_PROC_ID;
@@ -208,58 +216,71 @@ spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
/* Global IRQ locking depth. */
atomic_t global_irq_count = ATOMIC_INIT(0);
-atomic_t global_bh_count = ATOMIC_INIT(0);
-atomic_t global_bh_lock = ATOMIC_INIT(0);
-
/* This protects BH software state (masks, things like that). */
spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED;
-#ifdef DEBUG_IRQLOCK
+void smp_show_backtrace_all_cpus(void);
+void show_backtrace(void);
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+#define MAXCOUNT 100000000
+#define VERBOSE_DEBUG_IRQLOCK
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_bh CPU#%d stuck at %08lx\n", cpu, where); stuck = INIT_STUCK; }
-
-static inline void wait_on_bh(int cpu, unsigned long where)
+static void show(char * str)
{
- int stuck = INIT_STUCK;
- do {
- STUCK;
- /* nothing .. wait for the other bh's to go away */
- } while (atomic_read(&global_bh_count) != 0);
-}
+ int i;
+ int cpu = smp_processor_id();
+
+ printk("\n%s, CPU %d:\n", str, cpu);
+ printk("irq: %d [ ", atomic_read(&global_irq_count));
-static unsigned long previous_irqholder;
+ for (i = 0; i < NR_CPUS; i++) {
+ printk("%d ", local_irq_count[i]);
+ }
+ printk("]\n");
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+ printk("bh: %d [ ", (spin_is_locked(&global_bh_count) ? 1 : 0));
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+ for (i = 0; i < NR_CPUS; i++) {
+ printk("%d ", local_bh_count[cpu]);
+ }
+ printk("]\n");
+
+#ifdef VERBOSE_DEBUG_IRQLOCK
+ smp_show_backtrace_all_cpus();
+#else
+ show_backtrace();
+#endif
+}
+
+static inline void wait_on_bh(void)
+{
+ int count = MAXCOUNT;
+ do {
+ if(!--count) {
+ show("wait_on_bh");
+ count = 0;
+ }
+ barrier();
+ } while(spin_is_locked(&global_bh_count));
+}
/*
* We have to allow irqs to arrive between __sti and __cli
*/
-#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+#define SYNC_OTHER_CORES(x) udelay(x+1)
-static inline void wait_on_irq(int cpu, unsigned long where)
+static inline void wait_on_irq(int cpu)
{
- int stuck = INIT_STUCK;
- int local_count = local_irq_count[cpu];
+ int count = MAXCOUNT;
for (;;) {
-
/*
* Wait until all interrupts are gone. Wait
* for bottom half handlers unless we're
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
- if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+ if (local_bh_count[cpu] || !spin_is_locked(&global_bh_count))
break;
}
@@ -267,17 +288,18 @@ static inline void wait_on_irq(int cpu, unsigned long where)
spin_unlock(&global_irq_lock);
for (;;) {
- STUCK;
-
+ if (!--count) {
+ show("wait_on_irq");
+ count = ~0;
+ }
__sti();
SYNC_OTHER_CORES(cpu);
__cli();
-
if (atomic_read(&global_irq_count))
continue;
- if (*((unsigned char *)&global_irq_lock))
+ if (spin_is_locked (&global_irq_lock))
continue;
- if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+ if (!local_bh_count[cpu] && spin_is_locked(&global_bh_count))
continue;
if (spin_trylock(&global_irq_lock))
break;
@@ -295,14 +317,8 @@ static inline void wait_on_irq(int cpu, unsigned long where)
*/
void synchronize_bh(void)
{
- unsigned long where;
-
- __asm__("mov %%i7, %0" : "=r" (where));
-
- if (atomic_read(&global_bh_count) && !in_interrupt()) {
- int cpu = smp_processor_id();
- wait_on_bh(cpu, where);
- }
+ if (spin_is_locked (&global_bh_count) && !in_interrupt())
+ wait_on_bh();
}
/*
@@ -321,16 +337,9 @@ void synchronize_irq(void)
}
}
-#undef INIT_STUCK
-#define INIT_STUCK 10000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
-
-static inline void get_irqlock(int cpu, unsigned long where)
+static inline void get_irqlock(int cpu)
{
- int stuck = INIT_STUCK;
+ int count = MAXCOUNT;
if (!spin_trylock(&global_irq_lock)) {
/* do we already hold the lock? */
@@ -338,23 +347,25 @@ static inline void get_irqlock(int cpu, unsigned long where)
return;
/* Uhhuh.. Somebody else got it. Wait.. */
do {
- do {
- STUCK;
+ while (spin_is_locked(&global_irq_lock)) {
+ if (!--count) {
+ show("get_irqlock");
+ count = ~0;
+ }
barrier();
- } while (*((volatile unsigned char *)&global_irq_lock));
+ }
} while (!spin_trylock(&global_irq_lock));
}
/*
* We also to make sure that nobody else is running
* in an interrupt context.
*/
- wait_on_irq(cpu, where);
+ wait_on_irq(cpu);
/*
* Ok, finally..
*/
global_irq_holder = cpu;
- previous_irqholder = where;
}
/*
@@ -372,9 +383,6 @@ static inline void get_irqlock(int cpu, unsigned long where)
void __global_cli(void)
{
unsigned int flags;
- unsigned long where;
-
- __asm__("mov %%i7, %0" : "=r" (where));
__save_flags(flags);
@@ -382,7 +390,7 @@ void __global_cli(void)
int cpu = smp_processor_id();
__cli();
if (!local_irq_count[cpu])
- get_irqlock(cpu, where);
+ get_irqlock(cpu);
}
}
@@ -442,65 +450,14 @@ void __global_restore_flags(unsigned long flags)
__sti();
break;
default:
- printk("global_restore_flags: %08lx (%08lx)\n",
- flags, (&flags)[-1]);
+ {
+ unsigned long pc;
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (pc));
+ printk("global_restore_flags: Bogon flags(%08lx) caller %08lx\n", flags, pc);
}
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 200000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
-
-#define VERBOSE_IRQLOCK_DEBUGGING
-
-void irq_enter(int cpu, int irq, void *_opaque)
-{
-#ifdef VERBOSE_IRQLOCK_DEBUGGING
- extern void smp_show_backtrace_all_cpus(void);
-#endif
- int stuck = INIT_STUCK;
-
- hardirq_enter(cpu);
- barrier();
- while (*((volatile unsigned char *)&global_irq_lock)) {
- if ((unsigned char) cpu == global_irq_holder) {
- struct pt_regs *regs = _opaque;
- int sbh_cnt = atomic_read(&global_bh_count);
- int globl_locked = *((unsigned char *)&global_irq_lock);
- int globl_icount = atomic_read(&global_irq_count);
- int local_count = local_irq_count[cpu];
- unsigned long pc = regs->pc;
-
- /* It is very important that we load the state variables
- * before we do the first call to printk() as printk()
- * could end up changing them...
- */
-
- printk("CPU[%d]: BAD! Local IRQ's enabled, global disabled "
- "interrupt at PC[%08lx]\n", cpu, pc);
- printk("CPU[%d]: bhcnt[%d] glocked[%d] gicnt[%d] licnt[%d]\n",
- cpu, sbh_cnt, globl_locked, globl_icount, local_count);
-#ifdef VERBOSE_IRQLOCK_DEBUGGING
- printk("Performing backtrace on all cpus, write this down!\n");
- smp_show_backtrace_all_cpus();
-#endif
- break;
- }
- STUCK;
- barrier();
}
}
-void irq_exit(int cpu, int irq)
-{
- hardirq_exit(cpu);
- release_irqlock(cpu);
-}
-
-#endif /* DEBUG_IRQLOCK */
#endif /* __SMP__ */
void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
@@ -542,7 +499,7 @@ void handler_irq(int irq, struct pt_regs * regs)
smp4m_irq_rotate(cpu);
#endif
#endif
- irq_enter(cpu, irq, regs);
+ irq_enter(cpu, irq);
action = *(irq + irq_action);
kstat.irqs[cpu][irq]++;
do {
@@ -563,7 +520,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
int cpu = smp_processor_id();
disable_pil_irq(irq);
- irq_enter(cpu, irq, regs);
+ irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
floppy_interrupt(irq, dev_id, regs);
irq_exit(cpu, irq);
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index aae13c515..a2beedbf1 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $
+/* $Id: pcic.c,v 1.5 1999/03/16 00:15:20 davem Exp $
* pcic.c: Sparc/PCI controller support
*
* Copyright (C) 1998 V. Roganov and G. Raiko
@@ -498,9 +498,10 @@ static void pci_do_settimeofday(struct timeval *tv)
tv->tv_sec--;
}
xtime = *tv;
- time_state = TIME_BAD;
- time_maxerror = 0x70000000;
- time_esterror = 0x70000000;
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
sti();
}
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 3aeee6f6b..301747c22 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.126 1998/09/21 05:05:18 jj Exp $
+/* $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -62,7 +62,9 @@ asmlinkage int sys_idle(void)
/* endless idle loop with no priority at all */
current->priority = 0;
- current->counter = 0;
+ current->counter = -100;
+ init_idle();
+
for (;;) {
if (ARCH_SUN4C_SUN4) {
static int count = HZ;
@@ -108,13 +110,17 @@ out:
/* This is being executed in task 0 'user space'. */
int cpu_idle(void *unused)
{
+ /* endless idle loop with no priority at all */
current->priority = 0;
+ current->counter = -100;
+ init_idle();
+
while(1) {
- check_pgt_cache();
- run_task_queue(&tq_scheduler);
- /* endless idle loop with no priority at all */
- current->counter = 0;
- schedule();
+ if(current->need_resched) {
+ schedule();
+ check_pgt_cache();
+ }
+ barrier(); /* or else gcc optimizes... */
}
}
@@ -203,8 +209,10 @@ void __show_backtrace(unsigned long fp)
int cpu = smp_processor_id();
spin_lock_irqsave(&sparc_backtrace_lock, flags);
- rw = (struct reg_window *) fp;
- while(rw) {
+
+ rw = (struct reg_window *)fp;
+ while(rw && (((unsigned long) rw) >= PAGE_OFFSET) &&
+ !(((unsigned long) rw) & 0x7)) {
printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
"FP[%08lx] CALLER[%08lx]\n", cpu,
rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
@@ -216,28 +224,21 @@ void __show_backtrace(unsigned long fp)
spin_unlock_irqrestore(&sparc_backtrace_lock, flags);
}
+#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
+#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
+#define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp))
+
void show_backtrace(void)
{
unsigned long fp;
- __asm__ __volatile__(
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "mov %%i6, %0" : "=r" (fp));
+ __SAVE; __SAVE; __SAVE; __SAVE;
+ __SAVE; __SAVE; __SAVE; __SAVE;
+ __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+ __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+
+ __GET_FP(fp);
+
__show_backtrace(fp);
}
@@ -379,8 +380,21 @@ void flush_thread(void)
current->tss.current_ds = USER_DS;
if (current->tss.flags & SPARC_FLAG_KTHREAD) {
current->tss.flags &= ~SPARC_FLAG_KTHREAD;
- switch_to_context(current);
+
+ /* We must fixup kregs as well. */
+ current->tss.kregs = (struct pt_regs *)
+ (((unsigned long)current) +
+ (TASK_UNION_SIZE - TRACEREG_SZ));
}
+
+ /* Exec'ing out of a vfork() shared address space is
+ * tricky on sparc32. exec_mmap will not set the mmu
+ * context because it sets the new current->mm after
+ * calling init_new_context and activate_context is
+ * a nop on sparc32, so we gotta catch it here. And
+ * clone()'s had the same problem. -DaveM
+ */
+ switch_to_context(current);
}
static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src)
@@ -440,10 +454,17 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src)
size = ((unsigned long)src->fp) - ((unsigned long)src);
sp = (struct sparc_stackf *)(((unsigned long)dst) - size);
+ /* do_fork() grabs the parent semaphore, we must release it
+ * temporarily so we can build the child clone stack frame
+ * without deadlocking.
+ */
+ up(&current->mm->mmap_sem);
if (copy_to_user(sp, src, size))
- return 0;
- if (put_user(dst, &sp->fp))
- return 0;
+ sp = (struct sparc_stackf *) 0;
+ else if (put_user(dst, &sp->fp))
+ sp = (struct sparc_stackf *) 0;
+ down(&current->mm->mmap_sem);
+
return sp;
}
@@ -505,14 +526,24 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.kpsr = current->tss.fork_kpsr;
#endif
p->tss.kwim = current->tss.fork_kwim;
- p->tss.kregs = childregs;
if(regs->psr & PSR_PS) {
- childregs->u_regs[UREG_FP] = p->tss.ksp;
+ extern struct pt_regs fake_swapper_regs;
+
+ p->tss.kregs = &fake_swapper_regs;
+ new_stack = (struct reg_window *)
+ ((((unsigned long)p) +
+ (TASK_UNION_SIZE)) -
+ (REGWIN_SZ));
+ childregs->u_regs[UREG_FP] = (unsigned long) new_stack;
p->tss.flags |= SPARC_FLAG_KTHREAD;
p->tss.current_ds = KERNEL_DS;
+ memcpy((void *)new_stack,
+ (void *)regs->u_regs[UREG_FP],
+ sizeof(struct reg_window));
childregs->u_regs[UREG_G6] = (unsigned long) p;
} else {
+ p->tss.kregs = childregs;
childregs->u_regs[UREG_FP] = sp;
p->tss.flags &= ~SPARC_FLAG_KTHREAD;
p->tss.current_ds = USER_DS;
@@ -658,3 +689,37 @@ out:
unlock_kernel();
return error;
}
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ long retval;
+
+ __asm__ __volatile("mov %4, %%g2\n\t" /* Set aside fn ptr... */
+ "mov %5, %%g3\n\t" /* and arg. */
+ "mov %1, %%g1\n\t"
+ "mov %2, %%o0\n\t" /* Clone flags. */
+ "mov 0, %%o1\n\t" /* usp arg == 0 */
+ "t 0x10\n\t" /* Linux/Sparc clone(). */
+ "cmp %%o1, 0\n\t"
+ "be 1f\n\t" /* The parent, just return. */
+ " nop\n\t" /* Delay slot. */
+ "jmpl %%g2, %%o7\n\t" /* Call the function. */
+ " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
+ "mov %3, %%g1\n\t"
+ "t 0x10\n\t" /* Linux/Sparc exit(). */
+ /* Notreached by child. */
+ "1: mov %%o0, %0\n\t" :
+ "=r" (retval) :
+ "i" (__NR_clone), "r" (flags | CLONE_VM),
+ "i" (__NR_exit), "r" (fn), "r" (arg) :
+ "g1", "g2", "g3", "o0", "o1", "memory", "cc");
+ return retval;
+}
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index ed8fe6a25..7f6ec54f9 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -528,6 +528,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH))
|| (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) {
+ unsigned long flags;
+
if(child == current) {
/* Try this under SunOS/Solaris, bwa haha
* You'll never be able to kill the process. ;-)
@@ -539,8 +541,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
(current->uid != child->euid) ||
(current->uid != child->uid) ||
(current->gid != child->egid) ||
- (current->gid != child->gid)) &&
- !capable(CAP_SYS_PTRACE)) {
+ (current->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) {
pt_error_return(regs, EPERM);
goto out;
}
@@ -550,14 +553,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
goto out;
}
child->flags |= PF_PTRACED;
+ write_lock_irqsave(&tasklist_lock, flags);
if(child->p_pptr != current) {
- unsigned long flags;
- write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
- write_unlock_irqrestore(&tasklist_lock, flags);
}
+ write_unlock_irqrestore(&tasklist_lock, flags);
send_sig(SIGSTOP, child, 1);
pt_succ_return(regs, 0);
goto out;
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 84190cf5a..d29c1cb66 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.103 1998/09/21 05:05:23 jj Exp $
+/* $Id: setup.c,v 1.105 1999/04/13 14:17:08 jj Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -271,8 +271,8 @@ extern unsigned long sun_serial_setup(unsigned long);
extern unsigned short root_flags;
extern unsigned short root_dev;
extern unsigned short ram_flags;
-extern unsigned ramdisk_image;
-extern unsigned ramdisk_size;
+extern unsigned sparc_ramdisk_image;
+extern unsigned sparc_ramdisk_size;
#define RAMDISK_IMAGE_START_MASK 0x07FF
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
@@ -285,7 +285,7 @@ enum sparc_cpu sparc_cpu_model;
struct tt_entry *sparc_ttable;
-static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
+struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
static void prom_cons_write(struct console *con, const char *str, unsigned count)
{
@@ -375,7 +375,7 @@ __initfunc(void setup_arch(char **cmdline_p,
sun4c_probe_vac();
load_mmu();
total = prom_probe_memory();
- *memory_start_p = (((unsigned long) &end));
+ *memory_start_p = PAGE_ALIGN(((unsigned long) &end));
if(!packed) {
for(i=0; sp_banks[i].num_bytes != 0; i++) {
@@ -404,10 +404,10 @@ __initfunc(void setup_arch(char **cmdline_p,
rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
#endif
#ifdef CONFIG_BLK_DEV_INITRD
- if (ramdisk_image) {
- initrd_start = ramdisk_image;
+ if (sparc_ramdisk_image) {
+ initrd_start = sparc_ramdisk_image;
if (initrd_start < KERNBASE) initrd_start += KERNBASE;
- initrd_end = initrd_start + ramdisk_size;
+ initrd_end = initrd_start + sparc_ramdisk_size;
if (initrd_end > *memory_end_p) {
printk(KERN_CRIT "initrd extends beyond end of memory "
"(0x%08lx > 0x%08lx)\ndisabling initrd\n",
@@ -417,6 +417,14 @@ __initfunc(void setup_arch(char **cmdline_p,
if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) {
initrd_below_start_ok = 1;
*memory_start_p = PAGE_ALIGN (initrd_end);
+ } else if (initrd_start && sparc_ramdisk_image < KERNBASE) {
+ switch (sparc_cpu_model) {
+ case sun4m:
+ case sun4d:
+ initrd_start -= KERNBASE;
+ initrd_end -= KERNBASE;
+ break;
+ }
}
}
#endif
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 287ed6cdc..e6023f43b 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $
+/* $Id: signal.c,v 1.91 1999/01/26 11:00:44 jj Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -38,6 +38,8 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
/* This turned off for production... */
/* #define DEBUG_SIGNALS 1 */
+/* #define DEBUG_SIGNALS_TRACE 1 */
+/* #define DEBUG_SIGNALS_MAPS 1 */
/* Signal frames: the original one (compatible with SunOS):
*
@@ -1004,6 +1006,59 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
}
}
+#ifdef DEBUG_SIGNALS_MAPS
+
+#define MAPS_LINE_FORMAT "%08lx-%08lx %s %08lx %s %lu "
+
+static inline void read_maps (void)
+{
+ struct vm_area_struct * map, * next;
+ char * buffer;
+ ssize_t i;
+
+ buffer = (char*)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return;
+
+ for (map = current->mm->mmap ; map ; map = next ) {
+ /* produce the next line */
+ char *line;
+ char str[5], *cp = str;
+ int flags;
+ kdev_t dev;
+ unsigned long ino;
+
+ /*
+ * Get the next vma now (but it won't be used if we sleep).
+ */
+ next = map->vm_next;
+ flags = map->vm_flags;
+
+ *cp++ = flags & VM_READ ? 'r' : '-';
+ *cp++ = flags & VM_WRITE ? 'w' : '-';
+ *cp++ = flags & VM_EXEC ? 'x' : '-';
+ *cp++ = flags & VM_MAYSHARE ? 's' : 'p';
+ *cp++ = 0;
+
+ dev = 0;
+ ino = 0;
+ if (map->vm_file != NULL) {
+ dev = map->vm_file->f_dentry->d_inode->i_dev;
+ ino = map->vm_file->f_dentry->d_inode->i_ino;
+ line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+ }
+ printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_offset,
+ kdevname(dev), ino);
+ if (map->vm_file != NULL)
+ printk("%s\n", line);
+ else
+ printk("\n");
+ }
+ free_page((unsigned long)buffer);
+ return;
+}
+#endif
+
/* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
@@ -1115,8 +1170,25 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
}
#ifdef DEBUG_SIGNALS
/* Very useful to debug dynamic linker problems */
- printk ("Sig ILL going...\n");
+ printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
show_regs (regs);
+#ifdef DEBUG_SIGNALS_TRACE
+ {
+ struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
+ unsigned int ins[8];
+
+ while(rw &&
+ !(((unsigned long) rw) & 0x3)) {
+ copy_from_user(ins, &rw->ins[0], sizeof(ins));
+ printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
+ rw = (struct reg_window *)(unsigned long)ins[6];
+ }
+ }
+#endif
+#ifdef DEBUG_SIGNALS_MAPS
+ printk("Maps:\n");
+ read_maps();
+#endif
#endif
/* fall through */
default:
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index f77d823aa..fb55c1ffa 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -52,6 +52,7 @@ unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */
int smp_activated = 0;
volatile int cpu_number_map[NR_CPUS];
volatile int __cpu_logical_map[NR_CPUS];
+cycles_t cacheflush_time = 0; /* XXX */
/* The only guaranteed locking primitive available on all Sparc
* processors is 'ldstub [%reg + immediate], %dest_reg' which atomically
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 43f963217..b043d647d 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.73 1998/11/06 13:49:54 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.77 1999/03/21 06:37:43 davem Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -66,6 +66,7 @@ extern char saved_command_line[];
extern void bcopy (const char *, char *, int);
extern int __ashrdi3(int, int);
+extern int __lshrdi3(int, int);
extern void dump_thread(struct pt_regs *, struct user *);
@@ -91,6 +92,7 @@ __attribute__((section("__ksymtab"))) = \
/* used by various drivers */
EXPORT_SYMBOL(sparc_cpu_model);
EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
+EXPORT_SYMBOL(kernel_thread);
#ifdef SPIN_LOCK_DEBUG
EXPORT_SYMBOL(_do_spin_lock);
EXPORT_SYMBOL(_do_spin_unlock);
@@ -118,6 +120,7 @@ EXPORT_SYMBOL_PRIVATE(_global_cli);
#endif
EXPORT_SYMBOL(page_offset);
+EXPORT_SYMBOL(sparc_valid_addr_bitmap);
#ifndef CONFIG_SUN4
EXPORT_SYMBOL(stack_top);
@@ -211,6 +214,7 @@ EXPORT_SYMBOL(saved_command_line);
EXPORT_SYMBOL(prom_apply_obio_ranges);
EXPORT_SYMBOL(prom_getname);
EXPORT_SYMBOL(prom_feval);
+EXPORT_SYMBOL(prom_getbool);
EXPORT_SYMBOL(prom_getstring);
EXPORT_SYMBOL(prom_apply_sbus_ranges);
EXPORT_SYMBOL(prom_getint);
@@ -268,6 +272,7 @@ EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memmove);
EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__lshrdi3);
EXPORT_SYMBOL_DOT(rem);
EXPORT_SYMBOL_DOT(urem);
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 93474714a..1d0de8d23 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -1,4 +1,4 @@
-/* $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $
+/* $Id: sun4d_irq.c,v 1.18 1999/04/20 13:22:30 anton Exp $
* arch/sparc/kernel/sun4d_irq.c:
* SS1000/SC2000 interrupt handling.
*
@@ -193,7 +193,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
cc_set_iclr(1 << irq);
- irq_enter(cpu, irq, regs);
+ irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
if (!sbusl) {
action = *(irq + irq_action);
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index af0aaf58d..edd736b41 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -190,6 +190,7 @@ __initfunc(void smp4d_boot_cpus(void))
current->processor = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
smp_setup_percpu_timer();
+ init_idle();
local_flush_cache_all();
if(linux_num_cpus == 1)
return; /* Not an MP box. */
@@ -211,6 +212,7 @@ __initfunc(void smp4d_boot_cpus(void))
p = task[++cpucount];
p->processor = i;
+ p->has_cpu = 1; /* we schedule the first task manually */
current_set[i] = p;
for (no = 0; no < linux_num_cpus; no++)
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index bd6fc8e20..4d7177dac 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -253,7 +253,7 @@ __initfunc(static void sun4m_init_timers(void (*counter_fn)(int, void *, struct
/* Map the per-cpu Counter registers. */
sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0,
- PAGE_SIZE*NCPUS, "counters_percpu",
+ PAGE_SIZE*SUN4M_NCPUS, "counters_percpu",
cnt_regs[0].which_io, 0x0);
/* Map the system Counter register. */
@@ -334,7 +334,7 @@ __initfunc(void sun4m_init_IRQ(void))
/* Map the interrupt registers for all possible cpus. */
sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0,
- PAGE_SIZE*NCPUS, "interrupts_percpu",
+ PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu",
int_regs[0].which_io, 0x0);
/* Map the system interrupt control registers. */
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 183ea7323..c9acf609c 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -161,6 +161,7 @@ __initfunc(void smp4m_boot_cpus(void))
smp_store_cpu_info(boot_cpu_id);
set_irq_udt(mid_xlate[boot_cpu_id]);
smp_setup_percpu_timer();
+ init_idle();
local_flush_cache_all();
if(linux_num_cpus == 1)
return; /* Not an MP box. */
@@ -180,6 +181,7 @@ __initfunc(void smp4m_boot_cpus(void))
p = task[++cpucount];
p->processor = i;
+ p->has_cpu = 1; /* we schedule the first task manually */
current_set[i] = p;
/* See trampoline.S for details... */
@@ -448,6 +450,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
if(!--prof_counter[cpu]) {
int user = user_mode(regs);
+ irq_enter(cpu, 0);
if(current->pid) {
update_one_process(current, 1, user, !user, cpu);
@@ -456,7 +459,6 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
current->need_resched = 1;
}
- spin_lock(&ticker_lock);
if(user) {
if(current->priority < DEF_PRIORITY) {
kstat.cpu_nice++;
@@ -469,9 +471,9 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
kstat.cpu_system++;
kstat.per_cpu_system[cpu]++;
}
- spin_unlock(&ticker_lock);
}
prof_counter[cpu] = prof_multiplier[cpu];
+ irq_exit(cpu, 0);
}
}
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index e5ea2e9b3..ed3918c10 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $
+/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $
* linux/arch/sparc/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -25,6 +25,8 @@
#include <asm/uaccess.h>
#include <asm/ipc.h>
+/* #define DEBUG_UNIMP_SYSCALL */
+
/* XXX Make this per-binary type, this way we can detect the type of
* XXX a binary. Every Sparc executable calls this very early on.
*/
@@ -189,6 +191,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
goto out;
}
retval = -ENOMEM;
+ len = PAGE_ALIGN(len);
if(!(flags & MAP_FIXED) && !addr) {
addr = get_unmapped_area(addr, len);
if(!addr)
@@ -202,6 +205,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
if(ARCH_SUN4C_SUN4) {
if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
+ /* VM hole */
retval = current->mm->brk;
goto out_putf;
}
@@ -223,9 +227,14 @@ out:
asmlinkage unsigned long
c_sys_nis_syscall (struct pt_regs *regs)
{
+ static int count = 0;
+
+ if (count++ > 5) return -ENOSYS;
lock_kernel();
- printk ("Unimplemented SPARC system call %d\n",(int)regs->u_regs[1]);
+ printk ("%s[%d]: Unimplemented SPARC system call %d\n", current->comm, current->pid, (int)regs->u_regs[1]);
+#ifdef DEBUG_UNIMP_SYSCALL
show_regs (regs);
+#endif
unlock_kernel();
return -ENOSYS;
}
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 5508f850a..4d0dfff5f 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.80 1998/09/21 05:04:59 jj Exp $
+/* $Id: systbls.S,v 1.83 1999/04/07 17:14:06 davem Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -25,7 +25,7 @@ sys_call_table:
/*30*/ .long sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
/*35*/ .long sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile
/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall
-/*45*/ .long sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*45*/ .long sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
/*55*/ .long sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
/*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
@@ -47,7 +47,7 @@ sys_call_table:
/*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
/*145*/ .long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
-/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
/*160*/ .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
/*165*/ .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
/*170*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
@@ -129,7 +129,7 @@ sunos_sys_table:
/*150*/ .long sys_getsockname, sunos_nosys, sunos_nosys
.long sys_poll, sunos_nosys, sunos_nosys
.long sunos_getdirentries, sys_statfs, sys_fstatfs
- .long sys_umount, sunos_nosys, sunos_nosys
+ .long sys_oldumount, sunos_nosys, sunos_nosys
.long sys_getdomainname, sys_setdomainname
.long sunos_nosys, sys_quotactl, sunos_nosys
.long sunos_mount, sys_ustat, sunos_semsys
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 9e5afcfcf..633ef2adb 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.39 1998/09/29 09:46:15 davem Exp $
+/* $Id: time.c,v 1.43 1999/03/15 22:13:31 davem Exp $
* linux/arch/sparc/kernel/time.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -39,6 +39,8 @@
#include <asm/sun4paddr.h>
#include <asm/page.h>
+extern rwlock_t xtime_lock;
+
enum sparc_clock_type sp_clock_typ;
struct mostek48t02 *mstk48t02_regs = 0;
struct mostek48t08 *mstk48t08_regs = 0;
@@ -80,7 +82,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifdef CONFIG_SUN4
if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
- (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
+ (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
int temp;
intersil_read_intr(intersil_clock, temp);
/* re-enable the irq */
@@ -89,6 +91,8 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#endif
clear_clock_irq();
+ write_lock(&xtime_lock);
+
do_timer(regs);
/* Determine when to update the Mostek clock. */
@@ -101,6 +105,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
+ write_unlock(&xtime_lock);
}
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -436,6 +441,9 @@ extern __inline__ unsigned long do_gettimeoffset(void)
return offset + count;
}
+/* This need not obtain the xtime_lock as it is coded in
+ * an implicitly SMP safe way already.
+ */
void do_gettimeofday(struct timeval *tv)
{
#if CONFIG_AP1000
@@ -485,12 +493,13 @@ void do_gettimeofday(struct timeval *tv)
void do_settimeofday(struct timeval *tv)
{
+ write_lock_irq(&xtime_lock);
bus_do_settimeofday(tv);
+ write_unlock_irq(&xtime_lock);
}
static void sbus_do_settimeofday(struct timeval *tv)
{
- cli();
#if !CONFIG_AP1000
tv->tv_usec -= do_gettimeoffset();
if(tv->tv_usec < 0) {
@@ -501,10 +510,8 @@ static void sbus_do_settimeofday(struct timeval *tv)
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti();
}
/*
@@ -544,7 +551,7 @@ static int set_rtc_mmss(unsigned long nowtime)
} else {
printk(KERN_WARNING
"set_rtc_mmss: can't update from %d to %d\n",
- cmos_minutes, real_minutes);
+ mostek_minutes, real_minutes);
return -1;
}
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 86d632409..b9afa02f7 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.57 1998/09/17 11:04:51 jj Exp $
+/* $Id: traps.c,v 1.59 1999/03/06 12:07:31 anton Exp $
* arch/sparc/kernel/traps.c
*
* Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -82,8 +82,13 @@ void instruction_dump (unsigned long *pc)
printk("\n");
}
+#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
+#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
+
void die_if_kernel(char *str, struct pt_regs *regs)
{
+ int count = 0;
+
/* Amuse the user. */
printk(
" \\|/ ____ \\|/\n"
@@ -93,6 +98,27 @@ void die_if_kernel(char *str, struct pt_regs *regs)
printk("%s(%d): %s\n", current->comm, current->pid, str);
show_regs(regs);
+
+ __SAVE; __SAVE; __SAVE; __SAVE;
+ __SAVE; __SAVE; __SAVE; __SAVE;
+ __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+ __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+
+ {
+ struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
+
+ /* Stop the back trace when we hit userland or we
+ * find some badly aligned kernel stack. Set an upper
+ * bound in case our stack is trashed and we loop.
+ */
+ while(rw &&
+ count++ < 30 &&
+ (((unsigned long) rw) >= PAGE_OFFSET) &&
+ !(((unsigned long) rw) & 0x7)) {
+ printk("Caller[%08lx]\n", rw->ins[7]);
+ rw = (struct reg_window *)rw->ins[6];
+ }
+ }
printk("Instruction DUMP:");
instruction_dump ((unsigned long *) regs->pc);
if(regs->psr & PSR_PS)
diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c
index 1fb434b49..a683efb3e 100644
--- a/arch/sparc/kernel/unaligned.c
+++ b/arch/sparc/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.17 1997/04/11 00:42:08 davem Exp $
+/* $Id: unaligned.c,v 1.18 1999/04/03 11:36:17 anton Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -332,7 +332,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
enum direction dir = decode_direction(insn);
int size = decode_access_size(insn);
- lock_kernel();
if(!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n",
regs->pc);
@@ -380,7 +379,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
}
advance(regs);
}
- unlock_kernel();
}
static inline int ok_for_user(struct pt_regs *regs, unsigned int insn,