summaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
commit78c388aed2b7184182c08428db1de6c872d815f5 (patch)
tree4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /arch/sparc/kernel
parenteb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff)
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/Makefile8
-rw-r--r--arch/sparc/kernel/auxio.c7
-rw-r--r--arch/sparc/kernel/devices.c43
-rw-r--r--arch/sparc/kernel/ebus.c331
-rw-r--r--arch/sparc/kernel/entry.S5
-rw-r--r--arch/sparc/kernel/init_task.c2
-rw-r--r--arch/sparc/kernel/irq.c233
-rw-r--r--arch/sparc/kernel/pcic.c762
-rw-r--r--arch/sparc/kernel/process.c63
-rw-r--r--arch/sparc/kernel/setup.c13
-rw-r--r--arch/sparc/kernel/signal.c298
-rw-r--r--arch/sparc/kernel/smp.c28
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c58
-rw-r--r--arch/sparc/kernel/sun4c_irq.c7
-rw-r--r--arch/sparc/kernel/sun4d_irq.c12
-rw-r--r--arch/sparc/kernel/sun4d_smp.c56
-rw-r--r--arch/sparc/kernel/sun4m_irq.c4
-rw-r--r--arch/sparc/kernel/sun4m_smp.c46
-rw-r--r--arch/sparc/kernel/sunos_ioctl.c4
-rw-r--r--arch/sparc/kernel/sys_sparc.c10
-rw-r--r--arch/sparc/kernel/sys_sunos.c34
-rw-r--r--arch/sparc/kernel/systbls.S346
-rw-r--r--arch/sparc/kernel/time.c45
-rw-r--r--arch/sparc/kernel/traps.c6
24 files changed, 1838 insertions, 583 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 9606064b3..18e487d86 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.45 1998/07/28 16:52:42 jj Exp $
+# $Id: Makefile,v 1.48 1998/09/21 05:04:46 jj Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -22,7 +22,7 @@ O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \
sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \
sunos_ioctl.o time.o windows.o cpu.o devices.o \
sclow.o solaris.o tadpole.o tick14.o ptrace.o sys_solaris.o \
- unaligned.o muldiv.o
+ unaligned.o muldiv.o pcic.o
OX_OBJS := sparc_ksyms.o
@@ -38,6 +38,10 @@ ifdef CONFIG_SUN_AUXIO
O_OBJS += auxio.o
endif
+ifdef CONFIG_PCI
+O_OBJS += ebus.o
+endif
+
head.o: head.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
index 13d34310f..a5e24ac52 100644
--- a/arch/sparc/kernel/auxio.c
+++ b/arch/sparc/kernel/auxio.c
@@ -5,6 +5,7 @@
#include <linux/stddef.h>
#include <linux/init.h>
+#include <linux/config.h>
#include <asm/oplib.h>
#include <asm/io.h>
#include <asm/auxio.h>
@@ -32,6 +33,11 @@ __initfunc(void auxio_probe(void))
node = prom_getchild(node);
auxio_nd = prom_searchsiblings(node, "auxio");
if(!auxio_nd) {
+#ifdef CONFIG_PCI
+ /* There may be auxio on Ebus */
+ auxio_register = 0;
+ return;
+#else
if(prom_searchsiblings(node, "leds")) {
/* VME chassis sun4m machine, no auxio exists. */
auxio_register = 0;
@@ -39,6 +45,7 @@ __initfunc(void auxio_probe(void))
}
prom_printf("Cannot find auxio node, cannot continue...\n");
prom_halt();
+#endif
}
}
prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs));
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index dd4dbb3c6..69f3070e5 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -1,5 +1,5 @@
/* devices.c: Initial scan of the prom device tree for important
- * Sparc device nodes which we need to find.
+ * Sparc device nodes which we need to find.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
@@ -14,8 +14,8 @@
#include <asm/smp.h>
#include <asm/system.h>
-struct prom_cpuinfo linux_cpus[NR_CPUS];
-int linux_num_cpus;
+struct prom_cpuinfo linux_cpus[32];
+int linux_num_cpus = 0;
extern void cpu_probe(void);
extern void clock_stop_probe(void); /* tadpole.c */
@@ -25,64 +25,55 @@ __initfunc(unsigned long
device_scan(unsigned long mem_start))
{
char node_str[128];
- int nd, prom_node_cpu, thismid;
- int cpu_nds[NR_CPUS]; /* One node for each cpu */
- int cpu_ctr = 0;
+ int thismid;
prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
if(strcmp(node_str, "cpu") == 0) {
- cpu_nds[0] = prom_root_node;
- cpu_ctr++;
+ linux_num_cpus++;
} else {
int scan;
scan = prom_getchild(prom_root_node);
prom_printf("root child is %08lx\n", (unsigned long) scan);
- nd = 0;
while((scan = prom_getsibling(scan)) != 0) {
prom_getstring(scan, "device_type", node_str, sizeof(node_str));
if(strcmp(node_str, "cpu") == 0) {
- cpu_nds[cpu_ctr] = scan;
- linux_cpus[cpu_ctr].prom_node = scan;
+ linux_cpus[linux_num_cpus].prom_node = scan;
prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
- linux_cpus[cpu_ctr].mid = thismid;
+ linux_cpus[linux_num_cpus].mid = thismid;
prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
- cpu_ctr, (unsigned long) scan,
+ linux_num_cpus, (unsigned long) scan,
thismid);
- cpu_ctr++;
+ linux_num_cpus++;
}
};
- if(cpu_ctr == 0) {
+ if(linux_num_cpus == 0) {
if (sparc_cpu_model == sun4d) {
scan = prom_getchild(prom_root_node);
for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
int node = prom_getchild(scan);
-
+
prom_getstring(node, "device_type", node_str, sizeof(node_str));
if (strcmp(node_str, "cpu") == 0) {
prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
- cpu_nds[cpu_ctr] = node;
- linux_cpus[cpu_ctr].prom_node = node;
- linux_cpus[cpu_ctr].mid = 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",
- cpu_ctr, (unsigned long) node,
+ linux_num_cpus, (unsigned long) node,
thismid);
- cpu_ctr++;
+ linux_num_cpus++;
}
}
}
}
- if(cpu_ctr == 0) {
+ if(linux_num_cpus == 0) {
printk("No CPU nodes found, cannot continue.\n");
/* Probably a sun4e, Sun is trying to trick us ;-) */
halt();
}
- printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
+ printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
};
- prom_node_cpu = cpu_nds[0];
-
- linux_num_cpus = cpu_ctr;
cpu_probe();
#ifdef CONFIG_SUN_AUXIO
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
new file mode 100644
index 000000000..7c3eda88e
--- /dev/null
+++ b/arch/sparc/kernel/ebus.c
@@ -0,0 +1,331 @@
+/* $Id: ebus.c,v 1.2 1998/10/07 11:35:16 jj Exp $
+ * ebus.c: PCI to EBus bridge device.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Adopted for sparc by V. Roganov and G. Raiko.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#include <asm/io.h>
+#include <asm/oplib.h>
+#include <asm/bpp.h>
+
+#undef PROM_DEBUG
+#undef DEBUG_FILL_EBUS_DEV
+
+#ifdef PROM_DEBUG
+#define dprintf prom_printf
+#else
+#define dprintf printk
+#endif
+
+struct linux_ebus *ebus_chain = 0;
+
+#ifdef CONFIG_SUN_OPENPROMIO
+extern int openprom_init(void);
+#endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
+#ifdef CONFIG_SUN_AUXIO
+extern void auxio_probe(void);
+#endif
+#ifdef CONFIG_OBP_FLASH
+extern int flash_init(void);
+#endif
+#ifdef CONFIG_ENVCTRL
+extern int envctrl_init(void);
+#endif
+
+static inline unsigned long ebus_alloc(size_t size)
+{
+ return (unsigned long)kmalloc(size, GFP_ATOMIC);
+}
+
+__initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
+ struct linux_ebus_child *dev))
+{
+ int regs[PROMREG_MAX];
+ int irqs[PROMREG_MAX];
+ char lbuf[128];
+ int i, len;
+
+ dev->prom_node = node;
+ prom_getstring(node, "name", lbuf, sizeof(lbuf));
+ strcpy(dev->prom_name, lbuf);
+
+ len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+ dev->num_addrs = len / sizeof(regs[0]);
+
+ for (i = 0; i < dev->num_addrs; i++) {
+ if (regs[i] >= dev->parent->num_addrs) {
+ prom_printf("UGH: property for %s was %d, need < %d\n",
+ dev->prom_name, len, dev->parent->num_addrs);
+ panic(__FUNCTION__);
+ }
+ dev->base_address[i] = dev->parent->base_address[regs[i]];
+ }
+
+ len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+ if ((len == -1) || (len == 0)) {
+ dev->num_irqs = 0;
+ /*
+ * Oh, well, some PROMs don't export interrupts
+ * property to children of EBus devices...
+ *
+ * Be smart about PS/2 keyboard and mouse.
+ */
+ if (!strcmp(dev->parent->prom_name, "8042")) {
+ dev->num_irqs = 1;
+ dev->irqs[0] = dev->parent->irqs[0];
+ }
+ } else {
+ dev->num_irqs = len / sizeof(irqs[0]);
+ printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]);
+ }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+ dprintk("child '%s': address%s\n", dev->prom_name,
+ dev->num_addrs > 1 ? "es" : "");
+ for (i = 0; i < dev->num_addrs; i++)
+ dprintk(" %016lx\n", dev->base_address[i]);
+ if (dev->num_irqs) {
+ dprintk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ for (i = 0; i < dev->num_irqs; i++)
+ dprintk(" %08x", dev->irqs[i]);
+ dprintk("\n");
+ }
+#endif
+}
+
+__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
+{
+ struct linux_prom_registers regs[PROMREG_MAX];
+ struct linux_ebus_child *child;
+ int irqs[PROMINTR_MAX];
+ char lbuf[128];
+ int i, n, len;
+
+ dev->prom_node = node;
+ prom_getstring(node, "name", lbuf, sizeof(lbuf));
+ strcpy(dev->prom_name, lbuf);
+
+ len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+ if (len % sizeof(struct linux_prom_registers)) {
+ prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
+ dev->prom_name, len,
+ (int)sizeof(struct linux_prom_registers));
+ panic(__FUNCTION__);
+ }
+ dev->num_addrs = len / sizeof(struct linux_prom_registers);
+
+ for (i = 0; i < dev->num_addrs; i++) {
+ n = (regs[i].which_io - 0x10) >> 2;
+
+ dev->base_address[i] = dev->bus->self->base_address[n];
+ dev->base_address[i] += regs[i].phys_addr;
+
+ if (dev->base_address[i]) {
+ dev->base_address[i] =
+ (unsigned long)sparc_alloc_io (dev->base_address[i], 0,
+ regs[i].reg_size,
+ dev->prom_name, 0, 0);
+ /* Some drivers call 'check_region', so we release it */
+ release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE);
+
+ if (dev->base_address[i] == 0 ) {
+ panic("ebus: unable sparc_alloc_io for dev %s",
+ dev->prom_name);
+ }
+ }
+ }
+
+ len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+ if ((len == -1) || (len == 0)) {
+ dev->num_irqs = 0;
+ } else {
+ dev->num_irqs = len / sizeof(irqs[0]);
+
+#define IRQ_8042 7
+ if (irqs[0] == 4) dev->irqs[0] = IRQ_8042;
+ printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]);
+ }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+ dprintk("'%s': address%s\n", dev->prom_name,
+ dev->num_addrs > 1 ? "es" : "");
+ for (i = 0; i < dev->num_addrs; i++)
+ dprintk(" %016lx\n", dev->base_address[i]);
+ if (dev->num_irqs) {
+ dprintk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ for (i = 0; i < dev->num_irqs; i++)
+ dprintk(" %08x", dev->irqs[i]);
+ dprintk("\n");
+ }
+#endif
+ if ((node = prom_getchild(node))) {
+ dev->children = (struct linux_ebus_child *)
+ ebus_alloc(sizeof(struct linux_ebus_child));
+
+ child = dev->children;
+ child->next = 0;
+ child->parent = dev;
+ child->bus = dev->bus;
+ fill_ebus_child(node, &regs[0], child);
+
+ while ((node = prom_getsibling(node))) {
+ child->next = (struct linux_ebus_child *)
+ ebus_alloc(sizeof(struct linux_ebus_child));
+
+ child = child->next;
+ child->next = 0;
+ child->parent = dev;
+ child->bus = dev->bus;
+ fill_ebus_child(node, &regs[0], child);
+ }
+ }
+}
+
+__initfunc(void ebus_init(void))
+{
+ struct linux_prom_pci_registers regs[PROMREG_MAX];
+ struct linux_pbm_info *pbm;
+ struct linux_ebus_device *dev;
+ struct linux_ebus *ebus;
+ struct pci_dev *pdev;
+ struct pcidev_cookie *cookie;
+ char lbuf[128];
+ unsigned long addr, *base;
+ unsigned short pci_command;
+ int nd, len, ebusnd;
+ int reg, nreg;
+ int num_ebus = 0;
+
+ if (!pci_present())
+ return;
+
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
+ if (!pdev) {
+#ifdef PROM_DEBUG
+ dprintk("ebus: No EBus's found.\n");
+#endif
+ return;
+ }
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus_chain = ebus = (struct linux_ebus *)
+ ebus_alloc(sizeof(struct linux_ebus));
+ ebus->next = 0;
+
+ while (ebusnd) {
+#ifdef PROM_DEBUG
+ dprintk("ebus%d:", num_ebus);
+#endif
+
+ prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
+ ebus->prom_node = ebusnd;
+ strcpy(ebus->prom_name, lbuf);
+ ebus->self = pdev;
+ ebus->parent = pbm = cookie->pbm;
+
+ /* Enable BUS Master. */
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+ pci_command |= PCI_COMMAND_MASTER;
+ pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+
+ len = prom_getproperty(ebusnd, "reg", (void *)regs,
+ sizeof(regs));
+ if (len == 0 || len == -1) {
+ prom_printf("%s: can't find reg property\n",
+ __FUNCTION__);
+ prom_halt();
+ }
+ nreg = len / sizeof(struct linux_prom_pci_registers);
+
+ base = &ebus->self->base_address[0];
+ for (reg = 0; reg < nreg; reg++) {
+ if (!(regs[reg].which_io & 0x03000000))
+ continue;
+
+ addr = regs[reg].phys_lo;
+ *base++ = addr;
+#ifdef PROM_DEBUG
+ dprintk(" %lx[%x]", addr, regs[reg].size_lo);
+#endif
+ }
+#ifdef PROM_DEBUG
+ dprintk("\n");
+#endif
+
+ nd = prom_getchild(ebusnd);
+ if (!nd)
+ goto next_ebus;
+
+ ebus->devices = (struct linux_ebus_device *)
+ ebus_alloc(sizeof(struct linux_ebus_device));
+
+ dev = ebus->devices;
+ dev->next = 0;
+ dev->children = 0;
+ dev->bus = ebus;
+ fill_ebus_device(nd, dev);
+
+ while ((nd = prom_getsibling(nd))) {
+ dev->next = (struct linux_ebus_device *)
+ ebus_alloc(sizeof(struct linux_ebus_device));
+
+ dev = dev->next;
+ dev->next = 0;
+ dev->children = 0;
+ dev->bus = ebus;
+ fill_ebus_device(nd, dev);
+ }
+
+ next_ebus:
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_EBUS, pdev);
+ if (!pdev)
+ break;
+
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus->next = (struct linux_ebus *)
+ ebus_alloc(sizeof(struct linux_ebus));
+ ebus = ebus->next;
+ ebus->next = 0;
+ ++num_ebus;
+ }
+
+#ifdef CONFIG_SUN_OPENPROMIO
+ openprom_init();
+#endif
+
+#ifdef CONFIG_SPARCAUDIO
+ sparcaudio_init();
+#endif
+#ifdef CONFIG_SUN_BPP
+ bpp_init();
+#endif
+#ifdef CONFIG_SUN_AUXIO
+ auxio_probe();
+#endif
+#ifdef CONFIG_ENVCTRL
+ envctrl_init();
+#endif
+#ifdef CONFIG_OBP_FLASH
+ flash_init();
+#endif
+}
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 66ae02054..d628c0c8d 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.152 1998/07/29 16:32:24 jj Exp $
+/* $Id: entry.S,v 1.153 1998/11/11 15:12:33 jj Exp $
* arch/sparc/kernel/entry.S: Sparc trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -313,7 +313,8 @@ real_irq_continue:
patch_handler_irq:
call C_LABEL(handler_irq)
add %sp, REGWIN_SZ, %o1 ! pt_regs ptr
- wr %l0, PSR_ET, %psr
+ or %l0, PSR_PIL, %g2 ! restore PIL after handler_irq
+ wr %g2, PSR_ET, %psr ! keep ET up
WRITE_PAUSE
RESTORE_ALL
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
index 506a98622..156ed4337 100644
--- a/arch/sparc/kernel/init_task.c
+++ b/arch/sparc/kernel/init_task.c
@@ -6,7 +6,7 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct files * init_fd_array[NR_OPEN] = { NULL, };
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index d2d27d90a..4c8f78c8a 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.86 1998/06/04 09:54:49 jj Exp $
+/* $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj 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
@@ -6,8 +6,9 @@
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@ipmce.su)
+ * 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)
*/
#include <linux/config.h>
@@ -40,6 +41,7 @@
#include <asm/spinlock.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
+#include <asm/pcic.h>
/*
* Dave Redman (djhr@tadpole.co.uk)
@@ -190,13 +192,9 @@ void free_irq(unsigned int irq, void *dev_id)
restore_flags(flags);
}
-/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
+/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */
+unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
-#ifdef __SMP__
-atomic_t __sparc_bh_counter = ATOMIC_INIT(0);
-#else
-int __sparc_bh_counter = 0;
-#endif
#ifdef __SMP__
/* SMP interrupt locking on Sparc. */
@@ -207,14 +205,33 @@ 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);
+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
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#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)
+{
+ int stuck = INIT_STUCK;
+ do {
+ STUCK;
+ /* nothing .. wait for the other bh's to go away */
+ } while (atomic_read(&global_bh_count) != 0);
+}
+
static unsigned long previous_irqholder;
#undef INIT_STUCK
@@ -224,36 +241,83 @@ static unsigned long previous_irqholder;
#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; }
+/*
+ * We have to allow irqs to arrive between __sti and __cli
+ */
+#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+
static inline void wait_on_irq(int cpu, unsigned long where)
{
int stuck = INIT_STUCK;
int local_count = local_irq_count[cpu];
- /* Are we the only one in an interrupt context? */
- while (local_count != atomic_read(&global_irq_count)) {
+ for (;;) {
+
/*
- * No such luck. Now we need to release the lock,
- * _and_ release our interrupt context, because
- * otherwise we'd have dead-locks and live-locks
- * and other fun things.
+ * Wait until all interrupts are gone. Wait
+ * for bottom half handlers unless we're
+ * already executing in one..
*/
- atomic_sub(local_count, &global_irq_count);
+ if (!atomic_read(&global_irq_count)) {
+ if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+ break;
+ }
+
+ /* Duh, we have to loop. Release the lock to avoid deadlocks */
spin_unlock(&global_irq_lock);
- /*
- * Wait for everybody else to go away and release
- * their things before trying to get the lock again.
- */
for (;;) {
STUCK;
+
+ __sti();
+ SYNC_OTHER_CORES(cpu);
+ __cli();
+
if (atomic_read(&global_irq_count))
continue;
if (*((unsigned char *)&global_irq_lock))
continue;
+ if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+ continue;
if (spin_trylock(&global_irq_lock))
break;
}
- atomic_add(local_count, &global_irq_count);
+ }
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler.
+ */
+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);
+ }
+}
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+void synchronize_irq(void)
+{
+ if (atomic_read(&global_irq_count)) {
+ /* Stupid approach */
+ cli();
+ sti();
}
}
@@ -280,54 +344,106 @@ static inline void get_irqlock(int cpu, unsigned long where)
} while (*((volatile unsigned char *)&global_irq_lock));
} while (!spin_trylock(&global_irq_lock));
}
- /*
- * Ok, we got the lock bit.
- * But that's actually just the easy part.. Now
- * we need to make sure that nobody else is running
+ /*
+ * We also to make sure that nobody else is running
* in an interrupt context.
*/
wait_on_irq(cpu, where);
/*
- * Finally.
+ * Ok, finally..
*/
global_irq_holder = cpu;
previous_irqholder = where;
}
+/*
+ * 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)
{
- int cpu = smp_processor_id();
+ unsigned int flags;
unsigned long where;
__asm__("mov %%i7, %0" : "=r" (where));
- __cli();
- get_irqlock(cpu, where);
+
+ __save_flags(flags);
+
+ if ((flags & PSR_PIL) != PSR_PIL) {
+ int cpu = smp_processor_id();
+ __cli();
+ if (!local_irq_count[cpu])
+ get_irqlock(cpu, where);
+ }
}
void __global_sti(void)
{
- release_irqlock(smp_processor_id());
+ 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)
{
- return global_irq_holder == (unsigned char) smp_processor_id();
+ int retval;
+ int local_enabled = 0;
+ unsigned long flags;
+
+ __save_flags(flags);
+
+ if ((flags & PSR_PIL) != PSR_PIL)
+ local_enabled = 1;
+
+ /* default to local */
+ retval = 2 + local_enabled;
+
+ /* check for global flags if we're not in an interrupt */
+ if (!local_irq_count[smp_processor_id()]) {
+ if (local_enabled)
+ retval = 1;
+ if (global_irq_holder == (unsigned char) smp_processor_id())
+ retval = 0;
+ }
+ return retval;
}
void __global_restore_flags(unsigned long flags)
{
- if(flags & 1) {
+ switch (flags) {
+ case 0:
__global_cli();
- } else {
- /* release_irqlock() */
- if(global_irq_holder == smp_processor_id()) {
- global_irq_holder = NO_PROC_ID;
- spin_unlock(&global_irq_lock);
- }
- if(!(flags & 2))
- __sti();
+ break;
+ case 1:
+ __global_sti();
+ break;
+ case 2:
+ __cli();
+ break;
+ case 3:
+ __sti();
+ break;
+ default:
+ printk("global_restore_flags: %08lx (%08lx)\n",
+ flags, (&flags)[-1]);
}
}
@@ -352,7 +468,7 @@ void irq_enter(int cpu, int irq, void *_opaque)
while (*((volatile unsigned char *)&global_irq_lock)) {
if ((unsigned char) cpu == global_irq_holder) {
struct pt_regs *regs = _opaque;
- int sbh_cnt = atomic_read(&__sparc_bh_counter);
+ 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];
@@ -385,24 +501,6 @@ void irq_exit(int cpu, int irq)
}
#endif /* DEBUG_IRQLOCK */
-
-/* There has to be a better way. */
-void synchronize_irq(void)
-{
- int cpu = smp_processor_id();
- int local_count = local_irq_count[cpu];
-
- if(local_count != atomic_read(&global_irq_count)) {
- unsigned long flags;
-
- /* See comment below at __global_save_flags to understand
- * why we must do it this way on Sparc.
- */
- save_and_cli(flags);
- restore_flags(flags);
- }
-}
-
#endif /* __SMP__ */
void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
@@ -510,12 +608,13 @@ int request_fast_irq(unsigned int irq,
/* If this is flagged as statically allocated then we use our
* private struct which is never freed.
*/
- if (irqflags & SA_STATIC_ALLOC)
+ if (irqflags & SA_STATIC_ALLOC) {
if (static_irq_count < MAX_STATIC_ALLOC)
action = &static_irqaction[static_irq_count++];
else
printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
irq, devname);
+ }
if (action == NULL)
action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
@@ -603,11 +702,12 @@ int request_irq(unsigned int irq,
/* If this is flagged as statically allocated then we use our
* private struct which is never freed.
*/
- if (irqflags & SA_STATIC_ALLOC)
+ if (irqflags & SA_STATIC_ALLOC) {
if (static_irq_count < MAX_STATIC_ALLOC)
action = &static_irqaction[static_irq_count++];
else
printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname);
+ }
if (action == NULL)
action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
@@ -669,6 +769,13 @@ __initfunc(void init_IRQ(void))
break;
case sun4m:
+#ifdef CONFIG_PCI
+ pcic_probe();
+ if (pci_present()) {
+ sun4m_pci_init_IRQ();
+ break;
+ }
+#endif
sun4m_init_IRQ();
break;
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
new file mode 100644
index 000000000..aae13c515
--- /dev/null
+++ b/arch/sparc/kernel/pcic.c
@@ -0,0 +1,762 @@
+/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $
+ * pcic.c: Sparc/PCI controller support
+ *
+ * Copyright (C) 1998 V. Roganov and G. Raiko
+ *
+ * Code is derived from Ultra/PCI PSYCHO controller support, see that
+ * for author info.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+
+#include <asm/ebus.h>
+#include <asm/sbus.h> /* for sanity check... */
+
+#include <asm/io.h>
+
+#undef PROM_DEBUG
+#undef FIXUP_REGS_DEBUG
+#undef FIXUP_IRQ_DEBUG
+#undef FIXUP_VMA_DEBUG
+
+#ifdef PROM_DEBUG
+#define dprintf prom_printf
+#else
+#define dprintf printk
+#endif
+
+#include <linux/ctype.h>
+#include <linux/pci.h>
+#include <linux/timex.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+#include <asm/pcic.h>
+#include <asm/timer.h>
+#include <asm/uaccess.h>
+
+#ifndef CONFIG_PCI
+
+int pcibios_present(void)
+{
+ return 0;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ return 0;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ return 0;
+}
+
+#else
+
+static struct linux_pcic PCIC;
+static struct linux_pcic *pcic = NULL;
+
+static void pci_do_gettimeofday(struct timeval *tv);
+static void pci_do_settimeofday(struct timeval *tv);
+
+__initfunc(void pcic_probe(void))
+{
+ struct linux_prom_registers regs[PROMREG_MAX];
+ struct linux_pbm_info* pbm;
+ char namebuf[64];
+ int node;
+ int err;
+
+ if (pcibios_present()) {
+ prom_printf("PCIC: called twice!\n");
+ prom_halt();
+ }
+
+ node = prom_getchild (prom_root_node);
+ node = prom_searchsiblings (node, "pci");
+ if (node == 0)
+ return;
+ /*
+ * Map in PCIC register set, config space, and IO base
+ */
+ err = prom_getproperty(node, "reg", (char*)regs, sizeof(regs));
+ if (err == 0 || err == -1) {
+ prom_printf("PCIC: Error, cannot get PCIC registers "
+ "from PROM.\n");
+ prom_halt();
+ }
+
+ pcic = &PCIC;
+
+ pcic->pcic_regs = (unsigned long)sparc_alloc_io(regs[0].phys_addr, NULL,
+ regs[0].reg_size,
+ "PCIC Registers", 0, 0);
+ if (!pcic->pcic_regs) {
+ prom_printf("PCIC: Error, cannot map PCIC registers.\n");
+ prom_halt();
+ }
+
+ pcic->pcic_io_phys = regs[1].phys_addr;
+ pcic->pcic_io = (unsigned long)sparc_alloc_io(regs[1].phys_addr, NULL,
+ regs[1].reg_size,
+ "PCIC IO Base", 0, 0);
+ if (pcic->pcic_io == 0UL) {
+ prom_printf("PCIC: Error, cannot map PCIC IO Base.\n");
+ prom_halt();
+ }
+
+ pcic->pcic_config_space_addr =
+ (unsigned long)sparc_alloc_io (regs[2].phys_addr, NULL,
+ regs[2].reg_size * 2,
+ "PCI Config Space Address", 0, 0);
+ if (pcic->pcic_config_space_addr == 0UL) {
+ prom_printf("PCIC: Error, cannot map"
+ "PCI Configuration Space Address.\n");
+ prom_halt();
+ }
+
+ /*
+ * Docs say three least significant bits in address and data
+ * must be the same. Thus, we need adjust size of data.
+ */
+ pcic->pcic_config_space_data =
+ (unsigned long)sparc_alloc_io (regs[3].phys_addr, NULL,
+ regs[3].reg_size * 2,
+ "PCI Config Space Data", 0, 0);
+ if (pcic->pcic_config_space_data == 0UL) {
+ prom_printf("PCIC: Error, cannot map"
+ "PCI Configuration Space Data.\n");
+ prom_halt();
+ }
+
+ pbm = &pcic->pbm;
+ pbm->prom_node = node;
+ prom_getstring(node, "name", namebuf, sizeof(namebuf));
+ strcpy(pbm->prom_name, namebuf);
+}
+
+__initfunc(void pcibios_init(void))
+{
+ /*
+ * PCIC should be initialized at start of the timer.
+ * So, here we report the presence of PCIC and do some magic passes.
+ */
+ if(!pcic)
+ return;
+
+ printk("PCIC MAP: config addr=0x%lx; config data=0x%lx, "
+ "regs=0x%lx io=0x%lx\n",
+ pcic->pcic_config_space_addr, pcic->pcic_config_space_data,
+ pcic->pcic_regs, pcic->pcic_io);
+
+ /*
+ * FIXME:
+ * Switch off IOTLB translation.
+ * It'll be great to use IOMMU to handle HME's rings
+ * but we couldn't. Thus, we have to flush CPU cache
+ * in HME.
+ */
+ writeb(PCI_DVMA_CONTROL_IOTLB_DISABLE,
+ pcic->pcic_regs+PCI_DVMA_CONTROL);
+
+ /*
+ * FIXME:
+ * Increase mapped size for PCI memory space (DMA access).
+ * Should be done in that order (size first, address second).
+ * Why we couldn't set up 4GB and forget about it ?
+ */
+ writel(0xF0000000UL, pcic->pcic_regs+PCI_SIZE_0);
+ writel(0+PCI_BASE_ADDRESS_SPACE_MEMORY,
+ pcic->pcic_regs+PCI_BASE_ADDRESS_0);
+}
+
+int pcibios_present(void)
+{
+ return pcic != NULL;
+}
+
+__initfunc(static int pdev_to_pnode(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev))
+{
+ struct linux_prom_pci_registers regs[PROMREG_MAX];
+ int err;
+ int node = prom_getchild(pbm->prom_node);
+
+ while(node) {
+ err = prom_getproperty(node, "reg",
+ (char *)&regs[0], sizeof(regs));
+ if(err != 0 && err != -1) {
+ unsigned long devfn = (regs[0].which_io >> 8) & 0xff;
+ if(devfn == pdev->devfn)
+ return node; /* Match */
+ }
+ node = prom_getsibling(node);
+ }
+ return 0;
+}
+
+static inline struct pcidev_cookie *pci_devcookie_alloc(void)
+{
+ return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC);
+}
+
+
+static void pcic_map_pci_device (struct pci_dev *dev) {
+ int node, pcinode;
+ int i, j;
+
+ /* Is any valid address present ? */
+ i = 0;
+ for(j = 0; j < 6; j++)
+ if (dev->base_address[j]) i++;
+ if (!i) return; /* nothing to do */
+
+ /*
+ * find related address and get it's window length
+ */
+ pcinode = prom_getchild(prom_root_node);
+ pcinode = prom_searchsiblings(pcinode, "pci");
+ if (!pcinode)
+ panic("PCIC: failed to locate 'pci' node");
+
+
+ for (node = prom_getchild(pcinode); node;
+ node = prom_getsibling(node)) {
+ struct linux_prom_pci_assigned_addresses addrs[6];
+ int addrlen = prom_getproperty(node,"assigned-addresses",
+ (char*)addrs, sizeof(addrs));
+ if (addrlen == -1)
+ continue;
+
+ addrlen /= sizeof(struct linux_prom_pci_assigned_addresses);
+ for (i = 0; i < addrlen; i++ )
+ for (j = 0; j < 6; j++) {
+ if (!dev->base_address[j] || !addrs[i].phys_lo)
+ continue;
+ if (addrs[i].phys_lo == dev->base_address[j]) {
+ unsigned long address = dev->base_address[j];
+ int length = addrs[i].size_lo;
+ char namebuf[128] = { 0, };
+ unsigned long mapaddr, addrflags;
+
+ prom_getstring(node, "name",
+ namebuf, sizeof(namebuf));
+
+ /* FIXME:
+ * failure in allocation too large space
+ */
+ if (length > 0x200000) {
+ length = 0x200000;
+ prom_printf("PCIC: map window for device '%s' "
+ "reduced to 2MB !\n", namebuf);
+ }
+
+ /*
+ * Be careful with MEM/IO address flags
+ */
+ if ((address & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_IO) {
+ mapaddr = address & PCI_BASE_ADDRESS_IO_MASK;
+ } else {
+ mapaddr = address & PCI_BASE_ADDRESS_MEM_MASK;
+ }
+ addrflags = address ^ mapaddr;
+
+ dev->base_address[j] =
+ (unsigned long)sparc_alloc_io(address, 0,
+ length,
+ namebuf, 0, 0);
+ if ( dev->base_address[j] == 0 )
+ panic("PCIC: failed make mapping for "
+ "pci device '%s' with address %lx\n",
+ namebuf, address);
+
+ dev->base_address[j] ^= addrflags;
+ return;
+ }
+ }
+ }
+
+ panic("PCIC: unable to locate prom node for pci device (%x,%x) \n",
+ dev->device, dev->vendor);
+}
+
+/*
+ * Assign IO space for a device.
+ * This is a chance for devices which have the same IO and Mem Space to
+ * fork access to IO and Mem.
+ *
+ * Now, we assume there is one such device only (IGA 1682) but code below
+ * should work in cases when space of all such devices is less then 16MB.
+ */
+unsigned long pcic_alloc_io( unsigned long* addr )
+{
+ unsigned long paddr = *addr;
+ unsigned long offset;
+
+ if(pcic->pcic_mapped_io == 0) {
+ pcic->pcic_mapped_io = paddr & ~(PCI_SPACE_SIZE-1) ;
+ writeb((pcic->pcic_mapped_io>>24) & 0xff,
+ pcic->pcic_regs+PCI_PIBAR);
+ writeb((pcic->pcic_io_phys>>24) & PCI_SIBAR_ADDRESS_MASK,
+ pcic->pcic_regs+PCI_SIBAR);
+ writeb(PCI_ISIZE_16M, pcic->pcic_regs+PCI_ISIZE);
+ }
+ if(paddr < pcic->pcic_mapped_io ||
+ paddr > pcic->pcic_mapped_io + PCI_SPACE_SIZE)
+ return 0;
+ offset = paddr - pcic->pcic_mapped_io;
+ *addr = pcic->pcic_io_phys + offset;
+ return pcic->pcic_io + offset;
+}
+
+/*
+ * Stolen from both i386 and sparc64 branch
+ */
+__initfunc(void pcibios_fixup(void))
+{
+ struct pci_dev *dev;
+ int i, has_io, has_mem;
+ unsigned short cmd;
+
+ if(pcic == NULL) {
+ prom_printf("PCI: Error, PCIC not found.\n");
+ prom_halt();
+ }
+
+ for (dev = pci_devices; dev; dev=dev->next) {
+ /*
+ * Comment from i386 branch:
+ * There are buggy BIOSes that forget to enable I/O and memory
+ * access to PCI devices. We try to fix this, but we need to
+ * be sure that the BIOS didn't forget to assign an address
+ * to the device. [mj]
+ * OBP is a case of such BIOS :-)
+ */
+ has_io = has_mem = 0;
+ for(i=0; i<6; i++) {
+ unsigned long a = dev->base_address[i];
+ if (a & PCI_BASE_ADDRESS_SPACE_IO) {
+ has_io = 1;
+ } else if (a & PCI_BASE_ADDRESS_MEM_MASK)
+ has_mem = 1;
+ }
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (has_io && !(cmd & PCI_COMMAND_IO)) {
+ printk("PCI: Enabling I/O for device %02x:%02x\n",
+ dev->bus->number, dev->devfn);
+ cmd |= PCI_COMMAND_IO;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) {
+ printk("PCI: Enabling memory for device %02x:%02x\n",
+ dev->bus->number, dev->devfn);
+ cmd |= PCI_COMMAND_MEMORY;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+
+ /* cookies */
+ {
+ struct pcidev_cookie *pcp;
+ struct linux_pbm_info* pbm = &pcic->pbm;
+ int node = pdev_to_pnode(pbm, dev);
+
+ if(node == 0)
+ node = -1;
+ pcp = pci_devcookie_alloc();
+ pcp->pbm = pbm;
+ pcp->prom_node = node;
+ dev->sysdata = pcp;
+ }
+
+ /* memory mapping */
+ if (!(dev->vendor == PCI_VENDOR_ID_SUN &&
+ dev->device == PCI_DEVICE_ID_SUN_EBUS)) {
+ pcic_map_pci_device(dev);
+ }
+
+ /* irq */
+#define SETIRQ(vend,devid,irqn) \
+ if (dev->vendor==vend && dev->device==devid) dev->irq = irqn;
+
+ SETIRQ(PCI_VENDOR_ID_SUN,PCI_DEVICE_ID_SUN_HAPPYMEAL,3);
+ }
+ ebus_init();
+}
+
+/* Makes compiler happy */
+static volatile int pcic_timer_dummy;
+
+static void pcic_clear_clock_irq(void)
+{
+ pcic_timer_dummy = readl(pcic->pcic_regs+PCI_SYS_LIMIT);
+}
+
+static void pcic_timer_handler (int irq, void *h, struct pt_regs *regs)
+{
+ pcic_clear_clock_irq();
+ do_timer(regs);
+}
+
+#define USECS_PER_JIFFY 10000 /* We have 100HZ "standard" timer for sparc */
+#define TICK_TIMER_LIMIT ((100*1000000/4)/100)
+
+__initfunc(void pci_time_init(void))
+{
+ unsigned long v;
+ int timer_irq, irq;
+
+ do_get_fast_time = pci_do_gettimeofday;
+ /* A hack until do_gettimeofday prototype is moved to arch specific headers
+ and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
+ ((unsigned int *)do_gettimeofday)[0] =
+ 0x10800000 | ((((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) >> 2) & 0x003fffff);
+ ((unsigned int *)do_gettimeofday)[1] =
+ 0x01000000;
+ BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM);
+ btfixup();
+
+ writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT);
+ /* PROM should set appropriate irq */
+ v = readb(pcic->pcic_regs+PCI_COUNTER_IRQ);
+ timer_irq = PCI_COUNTER_IRQ_SYS(v);
+ writel (PCI_COUNTER_IRQ_SET(timer_irq, 0),
+ pcic->pcic_regs+PCI_COUNTER_IRQ);
+ irq = request_irq(timer_irq, pcic_timer_handler,
+ (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
+ if (irq) {
+ prom_printf("time_init: unable to attach IRQ%d\n", timer_irq);
+ prom_halt();
+ }
+ __sti();
+}
+
+static __inline__ unsigned long do_gettimeoffset(void)
+{
+ unsigned long offset = 0;
+
+ /*
+ * We devide all to 100
+ * to have microsecond resolution and to avoid overflow
+ */
+ unsigned long count =
+ readl(pcic->pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
+ count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);
+
+ if(test_bit(TIMER_BH, &bh_active))
+ offset = 1000000;
+ return offset + count;
+}
+
+extern volatile unsigned long lost_ticks;
+
+static void pci_do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ *tv = xtime;
+ tv->tv_usec += do_gettimeoffset();
+
+ /*
+ * xtime is atomically updated in timer_bh. lost_ticks is
+ * nonzero if the timer bottom half hasnt executed yet.
+ */
+ if (lost_ticks)
+ tv->tv_usec += USECS_PER_JIFFY;
+
+ restore_flags(flags);
+
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+}
+
+static void pci_do_settimeofday(struct timeval *tv)
+{
+ cli();
+ tv->tv_usec -= do_gettimeoffset();
+ if(tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+ xtime = *tv;
+ time_state = TIME_BAD;
+ time_maxerror = 0x70000000;
+ time_esterror = 0x70000000;
+ sti();
+}
+
+#if 0
+static void watchdog_reset() {
+ writeb(0, pcic->pcic_regs+PCI_SYS_STATUS);
+}
+#endif
+
+#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3))
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char *value)
+{
+ unsigned int v;
+
+ pcibios_read_config_dword (bus, device_fn, where&~3, &v);
+ *value = 0xff & (v >> (8*(where & 3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word (unsigned char bus,
+ unsigned char device_fn,
+ unsigned char where, unsigned short *value)
+{
+ unsigned int v;
+ if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ pcibios_read_config_dword (bus, device_fn, where&~3, &v);
+ *value = 0xffff & (v >> (8*(where & 3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int *value)
+{
+ unsigned long flags;
+ if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 ||
+ (device_fn != 0 && device_fn != 1 && device_fn != 0x80)) {
+ *value = 0xffffffff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ /* FIXME: IGA haven't got high config memory addresses !!! */
+ if (device_fn == 0x80 && where > PCI_INTERRUPT_LINE) {
+ *value = 0xffffffff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ save_and_cli(flags);
+ writel(CONFIG_CMD(bus,device_fn,where), pcic->pcic_config_space_addr);
+ *value = readl(pcic->pcic_config_space_data + (where&4));
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned char value)
+{
+ unsigned int v;
+
+ pcibios_read_config_dword (bus, devfn, where&~3, &v);
+ v = (v & ~(0xff << (8*(where&3)))) |
+ ((0xff&(unsigned)value) << (8*(where&3)));
+ return pcibios_write_config_dword (bus, devfn, where&~3, v);
+}
+
+int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned short value)
+{
+ unsigned int v;
+ if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ pcibios_read_config_dword (bus, devfn, where&~3, &v);
+ v = (v & ~(0xffff << (8*(where&3)))) |
+ ((0xffff&(unsigned)value) << (8*(where&3)));
+ return pcibios_write_config_dword (bus, devfn, where&~3, v);
+}
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned int value)
+{
+ unsigned long flags;
+ if ((where&3) || bus != 0 || (devfn != 0 && devfn != 1 && devfn != 0x80))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ save_and_cli(flags);
+ writel(CONFIG_CMD(bus,devfn,where),pcic->pcic_config_space_addr);
+ writel(value, pcic->pcic_config_space_data + (where&4));
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__initfunc(char *pcibios_setup(char *str))
+{
+ return str;
+}
+
+/*
+ * Following code added to handle extra PCI-related system calls
+ */
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ int err = 0;
+
+ if(!suser())
+ return -EPERM;
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ pcibios_read_config_byte(bus, dfn, off, &ubyte);
+ put_user(ubyte, (unsigned char *)buf);
+ break;
+ case 2:
+ pcibios_read_config_word(bus, dfn, off, &ushort);
+ put_user(ushort, (unsigned short *)buf);
+ break;
+ case 4:
+ pcibios_read_config_dword(bus, dfn, off, &uint);
+ put_user(uint, (unsigned int *)buf);
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+ };
+ unlock_kernel();
+
+ return err;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ int err = 0;
+
+ if(!suser())
+ return -EPERM;
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ err = get_user(ubyte, (unsigned char *)buf);
+ if(err)
+ break;
+ pcibios_write_config_byte(bus, dfn, off, ubyte);
+ break;
+
+ case 2:
+ err = get_user(ushort, (unsigned short *)buf);
+ if(err)
+ break;
+ pcibios_write_config_byte(bus, dfn, off, ushort);
+ break;
+
+ case 4:
+ err = get_user(uint, (unsigned int *)buf);
+ if(err)
+ break;
+ pcibios_write_config_byte(bus, dfn, off, uint);
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+
+ };
+ unlock_kernel();
+
+ return err;
+}
+
+static inline unsigned long get_irqmask(int irq_nr)
+{
+ return 1 << irq_nr;
+}
+
+static inline char *pcic_irq_itoa(unsigned int irq)
+{
+ static char buff[16];
+ sprintf(buff, "%d", irq);
+ return buff;
+}
+
+static void pcic_disable_irq(unsigned int irq_nr)
+{
+ unsigned long mask, flags;
+
+ mask = get_irqmask(irq_nr);
+ save_and_cli(flags);
+ writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
+ restore_flags(flags);
+}
+
+static void pcic_enable_irq(unsigned int irq_nr)
+{
+ unsigned long mask, flags;
+
+ mask = get_irqmask(irq_nr);
+ save_and_cli(flags);
+ writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
+ restore_flags(flags);
+}
+
+static void pcic_clear_profile_irq(int cpu)
+{
+ printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
+}
+
+static void pcic_load_profile_irq(int cpu, unsigned int limit)
+{
+ printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
+}
+
+/* We assume the caller is local cli()'d when these are called, or else
+ * very bizarre behavior will result.
+ */
+static void pcic_disable_pil_irq(unsigned int pil)
+{
+ writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
+}
+
+static void pcic_enable_pil_irq(unsigned int pil)
+{
+ writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
+}
+
+__initfunc(void sun4m_pci_init_IRQ(void))
+{
+ BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM);
+}
+
+__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+{
+}
+
+#endif
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index c52674431..3aeee6f6b 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.118 1998/08/04 20:48:47 davem Exp $
+/* $Id: process.c,v 1.126 1998/09/21 05:05:18 jj Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -61,8 +61,8 @@ asmlinkage int sys_idle(void)
goto out;
/* endless idle loop with no priority at all */
- current->priority = -100;
- current->counter = -100;
+ current->priority = 0;
+ current->counter = 0;
for (;;) {
if (ARCH_SUN4C_SUN4) {
static int count = HZ;
@@ -108,16 +108,13 @@ out:
/* This is being executed in task 0 'user space'. */
int cpu_idle(void *unused)
{
- extern volatile int smp_commenced;
-
- current->priority = -100;
+ current->priority = 0;
while(1) {
- srmmu_check_pgt_cache();
- run_task_queue(&tq_scheduler);
- /* endless idle loop with no priority at all */
- current->counter = -100;
- if(!smp_commenced || current->need_resched)
- schedule();
+ check_pgt_cache();
+ run_task_queue(&tq_scheduler);
+ /* endless idle loop with no priority at all */
+ current->counter = 0;
+ schedule();
}
}
@@ -176,8 +173,10 @@ void machine_restart(char * cmd)
void machine_power_off(void)
{
+#ifdef CONFIG_SUN_AUXIO
if (auxio_power_register)
*auxio_power_register |= AUXIO_POWER_OFF;
+#endif
machine_halt();
}
@@ -594,8 +593,44 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
*/
int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
{
- /* Currently we report that we couldn't dump the fpu structure */
- return 0;
+ if (current->used_math == 0) {
+ memset(fpregs, 0, sizeof(*fpregs));
+ fpregs->pr_q_entrysize = 8;
+ return 1;
+ }
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+ &current->tss.fpqueue[0], &current->tss.fpqdepth);
+ regs->psr &= ~(PSR_EF);
+ current->flags &= ~(PF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+ &current->tss.fpqueue[0], &current->tss.fpqdepth);
+ last_task_used_math = 0;
+ regs->psr &= ~(PSR_EF);
+ }
+#endif
+ memcpy(&fpregs->pr_fr.pr_regs[0],
+ &current->tss.float_regs[0],
+ (sizeof(unsigned long) * 32));
+ fpregs->pr_fsr = current->tss.fsr;
+ fpregs->pr_qcnt = current->tss.fpqdepth;
+ fpregs->pr_q_entrysize = 8;
+ fpregs->pr_en = 1;
+ if(fpregs->pr_qcnt != 0) {
+ memcpy(&fpregs->pr_q[0],
+ &current->tss.fpqueue[0],
+ sizeof(struct fpq) * fpregs->pr_qcnt);
+ }
+ /* Zero out the rest. */
+ memset(&fpregs->pr_q[fpregs->pr_qcnt], 0,
+ sizeof(struct fpq) * (32 - fpregs->pr_qcnt));
+ return 1;
}
/*
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 257b1c086..84190cf5a 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.99 1998/07/28 16:52:45 jj Exp $
+/* $Id: setup.c,v 1.103 1998/09/21 05:05:23 jj Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -332,9 +332,6 @@ __initfunc(void setup_arch(char **cmdline_p,
switch(sparc_cpu_model) {
case sun4:
printk("SUN4\n");
-#ifdef CONFIG_SUN4_FORCECONSOLE
- register_console(&prom_console);
-#endif
packed = 0;
break;
case sun4c:
@@ -443,8 +440,14 @@ __initfunc(void setup_arch(char **cmdline_p,
serial_console = 1;
} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
serial_console = 2;
+ } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
+ prom_printf("MrCoffee ttya\n");
+ serial_console = 1;
+ } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
+ serial_console = 0;
+ prom_printf("MrCoffee keyboard\n");
} else {
- prom_printf("Inconsistent console\n");
+ prom_printf("Inconsistent or unknown console\n");
prom_halt();
}
}
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 357d30af5..287ed6cdc 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.82 1998/07/31 05:18:51 jj Exp $
+/* $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -75,6 +75,7 @@ struct new_signal_frame {
__siginfo_fpu_t *fpu_save;
unsigned long insns [2] __attribute__ ((aligned (8)));
unsigned int extramask[_NSIG_WORDS - 1];
+ unsigned int extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
@@ -86,6 +87,7 @@ struct rt_signal_frame {
__siginfo_fpu_t *fpu_save;
unsigned int insns [2];
stack_t stack;
+ unsigned int extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
@@ -203,16 +205,19 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
#endif
current->used_math = 1;
current->flags &= ~PF_USEDFPU;
+
+ if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
+ return -EFAULT;
- err = copy_from_user(&current->tss.float_regs[0], &fpu->si_float_regs[0],
- (sizeof(unsigned long) * 32));
+ err = __copy_from_user(&current->tss.float_regs[0], &fpu->si_float_regs[0],
+ (sizeof(unsigned long) * 32));
err |= __get_user(current->tss.fsr, &fpu->si_fsr);
err |= __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
if (current->tss.fpqdepth != 0)
- err |= copy_from_user(&current->tss.fpqueue[0],
- &fpu->si_fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
+ err |= __copy_from_user(&current->tss.fpqueue[0],
+ &fpu->si_fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
return err;
}
@@ -241,7 +246,7 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
/* 2. Restore the state */
up_psr = regs->psr;
- err |= copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
+ err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
/* User can only change condition codes and FPU enabling in %psr. */
regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
@@ -250,14 +255,14 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
- err |= restore_fpu_state(regs, sf->fpu_save);
+ err |= restore_fpu_state(regs, fpu_save);
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
err |= __get_user(set.sig[0], &sf->info.si_mask);
- err |= copy_from_user(&set.sig[1], &sf->extramask,
- (_NSIG_WORDS-1) * sizeof(unsigned int));
+ err |= __copy_from_user(&set.sig[1], &sf->extramask,
+ (_NSIG_WORDS-1) * sizeof(unsigned int));
if (err)
goto segv_and_exit;
@@ -270,8 +275,6 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
return;
segv_and_exit:
- /* Ugh, we need to grab master lock in these rare cases ;-( */
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -305,8 +308,8 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
*/
err |= __get_user(set.sig[0], &scptr->sigc_mask);
/* Note that scptr + 1 points to extramask */
- err |= copy_from_user(&set.sig[1], scptr + 1,
- (_NSIG_WORDS - 1) * sizeof(unsigned int));
+ err |= __copy_from_user(&set.sig[1], scptr + 1,
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
if (err)
goto segv_and_exit;
@@ -352,7 +355,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
(((unsigned long) sf) & 0x03))
goto segv;
- err = get_user(pc, &sf->regs.pc);
+ err = __get_user(pc, &sf->regs.pc);
err |= __get_user(npc, &sf->regs.npc);
err |= ((pc | npc) & 0x03);
@@ -366,8 +369,8 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
err |= __get_user(fpu_save, &sf->fpu_save);
if(fpu_save)
- err |= restore_fpu_state(regs, &sf->fpu_state);
- err |= copy_from_user(&set, &sf->mask, sizeof(sigset_t));
+ err |= restore_fpu_state(regs, fpu_save);
+ err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
@@ -423,7 +426,7 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
{
struct signal_sframe *sframep;
struct sigcontext *sc;
- int window = 0;
+ int window = 0, err;
synchronize_user_stack();
sframep = (struct signal_sframe *)get_sigframe(sa, regs, SF_ALIGNEDSZ);
@@ -443,58 +446,63 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
sc = &sframep->sig_context;
/* We've already made sure frame pointer isn't in kernel space... */
- __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), &sc->sigc_onstack);
- __put_user(oldset->sig[0], &sc->sigc_mask);
- __copy_to_user(sframep->extramask, &oldset->sig[1],
- (_NSIG_WORDS - 1) * sizeof(unsigned int));
- __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
- __put_user(pc, &sc->sigc_pc);
- __put_user(npc, &sc->sigc_npc);
- __put_user(regs->psr, &sc->sigc_psr);
- __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
- __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
- __put_user(current->tss.w_saved, &sc->sigc_oswins);
+ err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK),
+ &sc->sigc_onstack);
+ err |= __put_user(oldset->sig[0], &sc->sigc_mask);
+ err |= __copy_to_user(sframep->extramask, &oldset->sig[1],
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
+ err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
+ err |= __put_user(pc, &sc->sigc_pc);
+ err |= __put_user(npc, &sc->sigc_npc);
+ err |= __put_user(regs->psr, &sc->sigc_psr);
+ err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
+ err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
+ err |= __put_user(current->tss.w_saved, &sc->sigc_oswins);
if(current->tss.w_saved)
for(window = 0; window < current->tss.w_saved; window++) {
sc->sigc_spbuf[window] =
(char *)current->tss.rwbuf_stkptrs[window];
- copy_to_user(&sc->sigc_wbuf[window],
- &current->tss.reg_window[window],
- sizeof(struct reg_window));
+ err |= __copy_to_user(&sc->sigc_wbuf[window],
+ &current->tss.reg_window[window],
+ sizeof(struct reg_window));
}
else
- copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
- sizeof(struct reg_window));
+ err |= __copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
+ sizeof(struct reg_window));
current->tss.w_saved = 0; /* So process is allowed to execute. */
- __put_user(signr, &sframep->sig_num);
+ err |= __put_user(signr, &sframep->sig_num);
if(signr == SIGSEGV ||
signr == SIGILL ||
signr == SIGFPE ||
signr == SIGBUS ||
signr == SIGEMT) {
- __put_user(current->tss.sig_desc, &sframep->sig_code);
- __put_user(current->tss.sig_address, &sframep->sig_address);
+ err |= __put_user(current->tss.sig_desc, &sframep->sig_code);
+ err |= __put_user(current->tss.sig_address, &sframep->sig_address);
} else {
- __put_user(0, &sframep->sig_code);
- __put_user(0, &sframep->sig_address);
+ err |= __put_user(0, &sframep->sig_code);
+ err |= __put_user(0, &sframep->sig_address);
}
- __put_user(sc, &sframep->sig_scptr);
+ err |= __put_user(sc, &sframep->sig_scptr);
+ if (err)
+ goto sigsegv;
+
regs->u_regs[UREG_FP] = (unsigned long) sframep;
regs->pc = (unsigned long) sa->sa_handler;
regs->npc = (regs->pc + 4);
return;
sigill_and_return:
- /* Ugh, we need to grab master lock in these rare cases ;-( */
- lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ do_exit(SIGSEGV);
}
-static inline void
+static inline int
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
+ int err = 0;
#ifdef __SMP__
if (current->flags & PF_USEDFPU) {
put_psr(get_psr() | PSR_EF);
@@ -512,15 +520,16 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
regs->psr &= ~(PSR_EF);
}
#endif
- copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
- (sizeof(unsigned long) * 32));
- __put_user(current->tss.fsr, &fpu->si_fsr);
- __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
+ err |= __copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+ (sizeof(unsigned long) * 32));
+ err |= __put_user(current->tss.fsr, &fpu->si_fsr);
+ err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
if (current->tss.fpqdepth != 0)
- copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
+ err |= __copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
current->used_math = 0;
+ return err;
}
static inline void
@@ -528,7 +537,7 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset)
{
struct new_signal_frame *sf;
- int sigframe_size;
+ int sigframe_size, err;
/* 1. Make sure everything is clean */
synchronize_user_stack();
@@ -551,20 +560,24 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
}
/* 2. Save the current process state */
- copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+ err = __copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+
+ err |= __put_user(0, &sf->extra_size);
if (current->used_math) {
- save_fpu_state(regs, &sf->fpu_state);
- __put_user(&sf->fpu_state, &sf->fpu_save);
+ err |= save_fpu_state(regs, &sf->fpu_state);
+ err |= __put_user(&sf->fpu_state, &sf->fpu_save);
} else {
- __put_user(0, &sf->fpu_save);
+ err |= __put_user(0, &sf->fpu_save);
}
- __put_user(oldset->sig[0], &sf->info.si_mask);
- __copy_to_user(sf->extramask, &oldset->sig[1],
- (_NSIG_WORDS - 1) * sizeof(unsigned int));
- copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
- sizeof (struct reg_window));
+ err |= __put_user(oldset->sig[0], &sf->info.si_mask);
+ err |= __copy_to_user(sf->extramask, &oldset->sig[1],
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
+ err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+ sizeof (struct reg_window));
+ if (err)
+ goto sigsegv;
/* 3. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = (unsigned long) sf;
@@ -581,8 +594,13 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
else {
regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
- __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
- __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+ /* mov __NR_sigreturn, %g1 */
+ err |= __put_user(0x821020d8, &sf->insns[0]);
+
+ /* t 0x10 */
+ err |= __put_user(0x91d02010, &sf->insns[1]);
+ if (err)
+ goto sigsegv;
/* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
@@ -590,8 +608,9 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
return;
sigill_and_return:
- lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ do_exit(SIGSEGV);
}
static inline void
@@ -601,7 +620,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
struct rt_signal_frame *sf;
int sigframe_size;
unsigned int psr;
- int i;
+ int err;
synchronize_user_stack();
sigframe_size = RT_ALIGNEDSZ;
@@ -613,30 +632,33 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
if(current->tss.w_saved != 0)
goto sigill;
- put_user(regs->pc, &sf->regs.pc);
- __put_user(regs->npc, &sf->regs.npc);
- __put_user(regs->y, &sf->regs.y);
+ err = __put_user(regs->pc, &sf->regs.pc);
+ err |= __put_user(regs->npc, &sf->regs.npc);
+ err |= __put_user(regs->y, &sf->regs.y);
psr = regs->psr;
if(current->used_math)
psr |= PSR_EF;
- __put_user(psr, &sf->regs.psr);
- for(i = 0; i < 16; i++)
- __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+ err |= __put_user(psr, &sf->regs.psr);
+ err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
+ err |= __put_user(0, &sf->extra_size);
+
if(psr & PSR_EF) {
- save_fpu_state(regs, &sf->fpu_state);
- __put_user(&sf->fpu_state, &sf->fpu_save);
+ err |= save_fpu_state(regs, &sf->fpu_state);
+ err |= __put_user(&sf->fpu_state, &sf->fpu_save);
} else {
- __put_user(0, &sf->fpu_save);
+ err |= __put_user(0, &sf->fpu_save);
}
- __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
+ err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
/* Setup sigaltstack */
- __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
- __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
- __put_user(current->sas_ss_size, &sf->stack.ss_size);
+ err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
- copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
- sizeof (struct reg_window));
+ err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+ sizeof (struct reg_window));
+ if (err)
+ goto sigsegv;
regs->u_regs[UREG_FP] = (unsigned long) sf;
regs->u_regs[UREG_I0] = signo;
@@ -650,8 +672,13 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
else {
regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
- __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
- __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+ /* mov __NR_sigreturn, %g1 */
+ err |= __put_user(0x821020d8, &sf->insns[0]);
+
+ /* t 0x10 */
+ err |= __put_user(0x91d02010, &sf->insns[1]);
+ if (err)
+ goto sigsegv;
/* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
@@ -659,8 +686,9 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
return;
sigill:
- lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ do_exit(SIGSEGV);
}
/* Setup a Solaris stack frame */
@@ -675,7 +703,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
svr4_gwindows_t *gw;
svr4_ucontext_t *uc;
svr4_sigset_t setv;
- int window = 0;
+ int window = 0, err;
synchronize_user_stack();
sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, SVR4_SF_ALIGNED + REGWIN_SZ);
@@ -688,7 +716,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
}
/* Start with a clean frame pointer and fill it */
- clear_user(sfp, sizeof (*sfp));
+ err = __clear_user(sfp, sizeof (*sfp));
/* Setup convenience variables */
si = &sfp->si;
@@ -706,32 +734,32 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
if (_NSIG_WORDS >= 4) {
setv.sigbits[2] = oldset->sig[2];
setv.sigbits[3] = oldset->sig[3];
- __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
} else
- __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
+ err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
/* Store registers */
- __put_user(regs->pc, &((*gr) [SVR4_PC]));
- __put_user(regs->npc, &((*gr) [SVR4_NPC]));
- __put_user(regs->psr, &((*gr) [SVR4_PSR]));
- __put_user(regs->y, &((*gr) [SVR4_Y]));
+ err |= __put_user(regs->pc, &((*gr) [SVR4_PC]));
+ err |= __put_user(regs->npc, &((*gr) [SVR4_NPC]));
+ err |= __put_user(regs->psr, &((*gr) [SVR4_PSR]));
+ err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
/* Copy g [1..7] and o [0..7] registers */
- copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
- copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
+ err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
+ err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
/* Setup sigaltstack */
- __put_user(current->sas_ss_sp, &uc->stack.sp);
- __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
- __put_user(current->sas_ss_size, &uc->stack.size);
+ err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
+ err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+ err |= __put_user(current->sas_ss_size, &uc->stack.size);
/* Save the currently window file: */
/* 1. Link sfp->uc->gwins to our windows */
- __put_user(gw, &mc->gwin);
+ err |= __put_user(gw, &mc->gwin);
/* 2. Number of windows to restore at setcontext (): */
- __put_user(current->tss.w_saved, &gw->count);
+ err |= __put_user(current->tss.w_saved, &gw->count);
/* 3. Save each valid window
* Currently, it makes a copy of the windows from the kernel copy.
@@ -745,9 +773,11 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
* to flush the user windows.
*/
for(window = 0; window < current->tss.w_saved; window++) {
- __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
- copy_to_user(&gw->win [window], &current->tss.reg_window [window], sizeof (svr4_rwindow_t));
- __put_user(0, gw->winptr [window]);
+ err |= __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
+ err |= __copy_to_user(&gw->win [window],
+ &current->tss.reg_window [window],
+ sizeof (svr4_rwindow_t));
+ err |= __put_user(0, gw->winptr [window]);
}
/* 4. We just pay attention to the gw->count field on setcontext */
@@ -758,8 +788,10 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
* that much currently, should use those that David already
* is providing with tss.sig_desc
*/
- __put_user(signr, &si->siginfo.signo);
- __put_user(SVR4_SINOINFO, &si->siginfo.code);
+ err |= __put_user(signr, &si->siginfo.signo);
+ err |= __put_user(SVR4_SINOINFO, &si->siginfo.code);
+ if (err)
+ goto sigsegv;
regs->u_regs[UREG_FP] = (unsigned long) sfp;
regs->pc = (unsigned long) sa->sa_handler;
@@ -772,10 +804,13 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
if (regs->u_regs [14]){
struct reg_window *rw = (struct reg_window *) regs->u_regs [14];
- __put_user(signr, &rw->ins [0]);
- __put_user(si, &rw->ins [1]);
- __put_user(uc, &rw->ins [2]);
- __put_user(sfp, &rw->ins [6]); /* frame pointer */
+ err |= __put_user(signr, &rw->ins [0]);
+ err |= __put_user(si, &rw->ins [1]);
+ err |= __put_user(uc, &rw->ins [2]);
+ err |= __put_user(sfp, &rw->ins [6]); /* frame pointer */
+ if (err)
+ goto sigsegv;
+
regs->u_regs[UREG_I0] = signr;
regs->u_regs[UREG_I1] = (uint) si;
regs->u_regs[UREG_I2] = (uint) uc;
@@ -783,8 +818,9 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
return;
sigill_and_return:
- lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ do_exit(SIGSEGV);
}
asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
@@ -792,13 +828,15 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
svr4_gregset_t *gr;
svr4_mcontext_t *mc;
svr4_sigset_t setv;
+ int err = 0;
synchronize_user_stack();
if (current->tss.w_saved)
goto sigsegv_and_return;
- if(clear_user(uc, sizeof (*uc)))
+ err = clear_user(uc, sizeof (*uc));
+ if (err)
return -EFAULT;
/* Setup convenience variables */
@@ -810,32 +848,31 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
if (_NSIG_WORDS >= 4) {
setv.sigbits[2] = current->blocked.sig[2];
setv.sigbits[3] = current->blocked.sig[3];
- __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
} else
- __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
+ err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
/* Store registers */
- __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
- __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]);
- __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]);
- __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
+ err |= __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
+ err |= __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]);
+ err |= __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]);
+ err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
/* Copy g [1..7] and o [0..7] registers */
- copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
- copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
+ err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
+ err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
/* Setup sigaltstack */
- __put_user(current->sas_ss_sp, &uc->stack.sp);
- __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
- __put_user(current->sas_ss_size, &uc->stack.size);
+ err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
+ err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+ err |= __put_user(current->sas_ss_size, &uc->stack.size);
/* The register file is not saved
* we have already stuffed all of it with sync_user_stack
*/
- return 0;
+ return (err ? -EFAULT : 0);
sigsegv_and_return:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -905,18 +942,19 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
spin_unlock_irq(&current->sigmask_lock);
regs->pc = pc;
regs->npc = npc | 1;
- __get_user(regs->y, &((*gr) [SVR4_Y]));
- __get_user(psr, &((*gr) [SVR4_PSR]));
+ err |= __get_user(regs->y, &((*gr) [SVR4_Y]));
+ err |= __get_user(psr, &((*gr) [SVR4_PSR]));
regs->psr &= ~(PSR_ICC);
regs->psr |= (psr & PSR_ICC);
/* Restore g[1..7] and o[0..7] registers */
- copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7);
- copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8);
- return 0;
+ err |= __copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1],
+ sizeof (long) * 7);
+ err |= __copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0],
+ sizeof (long) * 8);
+ return (err ? -EFAULT : 0);
sigsegv_and_return:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -1069,7 +1107,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
if(current->binfmt && current->binfmt->core_dump) {
lock_kernel();
- if(current->binfmt->core_dump(signr, regs))
+ if(current->binfmt &&
+ current->binfmt->core_dump &&
+ current->binfmt->core_dump(signr, regs))
exit_code |= 0x80;
unlock_kernel();
}
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 0d9c43e9d..f77d823aa 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -64,6 +64,9 @@ volatile int __cpu_logical_map[NR_CPUS];
/* Kernel spinlock */
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+/* Used to make bitops atomic */
+unsigned char bitops_spinlock = 0;
+
volatile unsigned long ipi_count;
volatile int smp_process_available=0;
@@ -159,7 +162,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
local_flush_tlb_mm(mm);
} else {
xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
- if(mm->count == 1 && current->mm == mm)
+ if(atomic_read(&mm->count) == 1 && current->mm == mm)
mm->cpu_vm_mask = (1 << smp_processor_id());
}
}
@@ -275,3 +278,26 @@ int setup_profiling_timer(unsigned int multiplier)
return 0;
}
+
+int smp_bogo_info(char *buf)
+{
+ int len = 0, i;
+
+ for (i = 0; i < NR_CPUS; i++)
+ if (cpu_present_map & (1 << i))
+ len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n",
+ i,
+ cpu_data[i].udelay_val/500000,
+ (cpu_data[i].udelay_val/5000)%100);
+ return len;
+}
+
+int smp_info(char *buf)
+{
+ int len = 0, i;
+
+ for (i = 0; i < NR_CPUS; i++)
+ if (cpu_present_map & (1 << i))
+ len += sprintf(buf + len, "CPU%d\t\t: online\n", i);
+ return len;
+}
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index e6aad243d..43f963217 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.65 1998/06/04 09:54:50 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.73 1998/11/06 13:49:54 jj Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -41,6 +41,7 @@
#endif
#include <asm/a.out.h>
#include <asm/spinlock.h>
+#include <asm/io-unit.h>
struct poll {
int fd;
@@ -68,6 +69,10 @@ extern int __ashrdi3(int, int);
extern void dump_thread(struct pt_regs *, struct user *);
+#ifdef __SMP__
+extern spinlock_t kernel_flag;
+#endif
+
/* One thing to note is that the way the symbols of the mul/div
* support routines are named is a mess, they all start with
* a '.' which makes it a bitch to export, here is the trick:
@@ -85,48 +90,27 @@ __attribute__((section("__ksymtab"))) = \
/* used by various drivers */
EXPORT_SYMBOL(sparc_cpu_model);
-#ifdef __SMP__
-EXPORT_SYMBOL(klock_info);
-#endif
-EXPORT_SYMBOL_PRIVATE(_lock_kernel);
-EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
#ifdef SPIN_LOCK_DEBUG
-EXPORT_SYMBOL(_spin_lock);
-EXPORT_SYMBOL(_spin_unlock);
+EXPORT_SYMBOL(_do_spin_lock);
+EXPORT_SYMBOL(_do_spin_unlock);
EXPORT_SYMBOL(_spin_trylock);
-EXPORT_SYMBOL(_spin_lock_irq);
-EXPORT_SYMBOL(_spin_unlock_irq);
-EXPORT_SYMBOL(_spin_lock_irqsave);
-EXPORT_SYMBOL(_spin_unlock_irqrestore);
-EXPORT_SYMBOL(_read_lock);
-EXPORT_SYMBOL(_read_unlock);
-EXPORT_SYMBOL(_read_lock_irq);
-EXPORT_SYMBOL(_read_unlock_irq);
-EXPORT_SYMBOL(_read_lock_irqsave);
-EXPORT_SYMBOL(_read_unlock_irqrestore);
-EXPORT_SYMBOL(_write_lock);
-EXPORT_SYMBOL(_write_unlock);
-EXPORT_SYMBOL(_write_lock_irq);
-EXPORT_SYMBOL(_write_unlock_irq);
-EXPORT_SYMBOL(_write_lock_irqsave);
-EXPORT_SYMBOL(_write_unlock_irqrestore);
+EXPORT_SYMBOL(_do_read_lock);
+EXPORT_SYMBOL(_do_read_unlock);
+EXPORT_SYMBOL(_do_write_lock);
+EXPORT_SYMBOL(_do_write_unlock);
#else
EXPORT_SYMBOL_PRIVATE(_rw_read_enter);
EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
#endif
-EXPORT_SYMBOL(__sparc_bh_counter);
#ifdef __SMP__
#ifdef DEBUG_IRQLOCK
-EXPORT_SYMBOL(irq_enter);
-EXPORT_SYMBOL(irq_exit);
+EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_cli);
#else
-EXPORT_SYMBOL_PRIVATE(_irq_enter);
-EXPORT_SYMBOL_PRIVATE(_irq_exit);
EXPORT_SYMBOL_PRIVATE(_global_restore_flags);
EXPORT_SYMBOL_PRIVATE(_global_sti);
EXPORT_SYMBOL_PRIVATE(_global_cli);
@@ -134,7 +118,10 @@ EXPORT_SYMBOL_PRIVATE(_global_cli);
#endif
EXPORT_SYMBOL(page_offset);
+
+#ifndef CONFIG_SUN4
EXPORT_SYMBOL(stack_top);
+#endif
/* Atomic operations. */
EXPORT_SYMBOL_PRIVATE(_atomic_add);
@@ -148,14 +135,19 @@ EXPORT_SYMBOL_PRIVATE(_set_le_bit);
EXPORT_SYMBOL_PRIVATE(_clear_le_bit);
/* IRQ implementation. */
-EXPORT_SYMBOL(local_irq_count);
#ifdef __SMP__
+EXPORT_SYMBOL(kernel_flag);
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(global_irq_lock);
EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_bh_count);
+EXPORT_SYMBOL(sparc_bh_lock);
EXPORT_SYMBOL(global_irq_count);
EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(synchronize_bh);
#endif
+EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(udelay);
EXPORT_SYMBOL(mstk48t02_regs);
@@ -166,6 +158,8 @@ EXPORT_SYMBOL(request_fast_irq);
EXPORT_SYMBOL(sparc_alloc_io);
EXPORT_SYMBOL(sparc_free_io);
EXPORT_SYMBOL(io_remap_page_range);
+EXPORT_SYMBOL(iounit_map_dma_init);
+EXPORT_SYMBOL(iounit_map_dma_page);
/* Btfixup stuff cannot have versions, it would be complicated too much */
#ifndef __SMP__
@@ -227,7 +221,7 @@ EXPORT_SYMBOL(__prom_getsibling);
/* sparc library symbols */
EXPORT_SYMBOL(bcopy);
-EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL_NOVERS(memscan);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strcpy);
@@ -235,7 +229,7 @@ EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL_NOVERS(strncmp);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strpbrk);
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index cda7564dc..cafd61955 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -121,7 +121,7 @@ static void sun4c_clear_clock_irq(void)
{
volatile unsigned int clear_intr;
#ifdef CONFIG_SUN4
- if( idprom->id_machtype == SM_SUN4 | SM_4_260 )
+ if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
clear_intr = sun4_timer.timer_limit10;
else
#endif
@@ -146,7 +146,7 @@ __initfunc(static void sun4c_init_timers(void (*counter_fn)(int, void *, struct
* the cache chip on the sun4c.
*/
#ifdef CONFIG_SUN4
- if (idprom->id_machtype == SM_SUN4 | SM_4_260)
+ if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
sun4c_timers = &sun4_timer;
else
#endif
@@ -171,7 +171,10 @@ __initfunc(static void sun4c_init_timers(void (*counter_fn)(int, void *, struct
prom_halt();
}
+#if 0
+ /* This does not work on 4/330 */
sun4c_enable_irq(10);
+#endif
claim_ticker14(NULL, PROFILE_IRQ, 0);
}
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 3a37df0c9..93474714a 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.14 1998/06/04 09:54:47 jj Exp $
+/* $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $
* arch/sparc/kernel/sun4d_irq.c:
* SS1000/SC2000 interrupt handling.
*
@@ -284,11 +284,12 @@ int sun4d_request_irq(unsigned int irq,
/* If this is flagged as statically allocated then we use our
* private struct which is never freed.
*/
- if (irqflags & SA_STATIC_ALLOC)
+ if (irqflags & SA_STATIC_ALLOC) {
if (static_irq_count < MAX_STATIC_ALLOC)
action = &static_irqaction[static_irq_count++];
else
printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname);
+ }
if (action == NULL)
action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
@@ -437,8 +438,13 @@ __initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct
int cpu;
/* Map the User Timer registers. */
- sun4d_timers = sparc_alloc_io(BW_LOCAL_BASE+BW_TIMER_LIMIT, 0,
+#ifdef __SMP__
+ sun4d_timers = sparc_alloc_io(CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT, 0,
PAGE_SIZE, "user timer", 0xf, 0x0);
+#else
+ sun4d_timers = sparc_alloc_io(CSR_BASE(0)+BW_TIMER_LIMIT, 0,
+ PAGE_SIZE, "user timer", 0xf, 0x0);
+#endif
sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
master_l10_counter = &sun4d_timers->l10_cur_count;
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 5563a0cc6..af0aaf58d 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -8,6 +8,7 @@
#include <asm/head.h>
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/tasks.h>
@@ -57,7 +58,6 @@ extern unsigned char boot_cpu_id;
extern int smp_activated;
extern volatile int cpu_number_map[NR_CPUS];
extern volatile int __cpu_logical_map[NR_CPUS];
-extern struct klock_info klock_info;
extern volatile unsigned long ipi_count;
extern volatile int smp_process_available;
extern volatile int smp_commenced;
@@ -71,31 +71,6 @@ extern int __smp4d_processor_id(void);
#define SMP_PRINTK(x)
#endif
-int smp4d_bogo_info(char *buf)
-{
- int len = 0, i;
-
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_present_map & (1 << i))
- len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n",
- i,
- cpu_data[i].udelay_val/500000,
- (cpu_data[i].udelay_val/5000)%100);
- return len;
-}
-
-int smp4d_info(char *buf)
-{
- int len = 0, i;
-
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_present_map & (1 << i))
- len += sprintf(buf + len, "CPU%d\t\t: %s\n",
- i,
- (klock_info.akp == i) ? "akp" : "online");
- return len;
-}
-
static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
{
__asm__ __volatile__("swap [%1], %0\n\t" :
@@ -193,10 +168,6 @@ __initfunc(void smp4d_boot_cpus(void))
printk("Entering SMP Mode...\n");
- smp_penguin_ctable.which_io = 0;
- smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
- smp_penguin_ctable.reg_size = 0;
-
for (i = 0; i < NR_CPUS; i++)
cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
@@ -216,7 +187,6 @@ __initfunc(void smp4d_boot_cpus(void))
mid_xlate[i] = i;
cpu_number_map[boot_cpu_id] = 0;
__cpu_logical_map[0] = boot_cpu_id;
- klock_info.akp = boot_cpu_id;
current->processor = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
smp_setup_percpu_timer();
@@ -246,7 +216,16 @@ __initfunc(void smp4d_boot_cpus(void))
for (no = 0; no < linux_num_cpus; no++)
if (linux_cpus[no].mid == i)
break;
-
+
+ /*
+ * Initialize the contexts table
+ * Since the call to prom_startcpu() trashes the structure,
+ * we need to re-initialize it for each cpu
+ */
+ smp_penguin_ctable.which_io = 0;
+ smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
+ smp_penguin_ctable.reg_size = 0;
+
/* whirrr, whirrr, whirrrrrrrrr... */
SMP_PRINTK(("Starting CPU %d at %p task %d node %08x\n", i, entry, cpucount, linux_cpus[no].prom_node));
local_flush_cache_all();
@@ -256,10 +235,10 @@ __initfunc(void smp4d_boot_cpus(void))
SMP_PRINTK(("prom_startcpu returned :)\n"));
/* wheee... it's going... */
- for(timeout = 0; timeout < 5000000; timeout++) {
+ for(timeout = 0; timeout < 10000; timeout++) {
if(cpu_callin_map[i])
break;
- udelay(100);
+ udelay(200);
}
if(cpu_callin_map[i]) {
@@ -436,6 +415,8 @@ void smp4d_message_pass(int target, int msg, unsigned long data, int wait)
/* Protects counters touched during level14 ticker */
static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_PROFILE
+
/* 32-bit Sparc specific profiling function. */
static inline void sparc_do_profile(unsigned long pc)
{
@@ -454,6 +435,8 @@ static inline void sparc_do_profile(unsigned long pc)
}
}
+#endif
+
extern unsigned int prof_multiplier[NR_CPUS];
extern unsigned int prof_counter[NR_CPUS];
@@ -479,9 +462,10 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
show_leds(cpu);
}
+#ifdef CONFIG_PROFILE
if(!user_mode(regs))
sparc_do_profile(regs->pc);
-
+#endif
if(!--prof_counter[cpu]) {
int user = user_mode(regs);
if(current->pid) {
@@ -559,8 +543,6 @@ __initfunc(void sun4d_init_smp(void))
BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(smp_message_pass, smp4d_message_pass, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(smp_bogo_info, smp4d_bogo_info, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(smp_info, smp4d_info, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
for (i = 0; i < NR_CPUS; i++) {
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 68c04014f..bd6fc8e20 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -47,10 +47,12 @@ unsigned long *irq_rcvreg = &dummy;
*
* take an encoded intr value and lookup if it's valid
* then get the mask bits that match from irq_mask
+ *
+ * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
*/
static unsigned char irq_xlate[32] = {
/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */
- 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 0, 0, 7,
+ 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7,
0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0
};
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 597ee7665..183ea7323 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -53,7 +53,6 @@ extern unsigned char boot_cpu_id;
extern int smp_activated;
extern volatile int cpu_number_map[NR_CPUS];
extern volatile int __cpu_logical_map[NR_CPUS];
-extern struct klock_info klock_info;
extern volatile unsigned long ipi_count;
extern volatile int smp_process_available;
extern volatile int smp_commenced;
@@ -67,30 +66,6 @@ extern int __smp4m_processor_id(void);
#define SMP_PRINTK(x)
#endif
-int smp4m_bogo_info(char *buf)
-{
- return sprintf(buf,
- "Cpu0Bogo\t: %lu.%02lu\n"
- "Cpu1Bogo\t: %lu.%02lu\n"
- "Cpu2Bogo\t: %lu.%02lu\n"
- "Cpu3Bogo\t: %lu.%02lu\n",
- cpu_data[0].udelay_val/500000, (cpu_data[0].udelay_val/5000)%100,
- cpu_data[1].udelay_val/500000, (cpu_data[1].udelay_val/5000)%100,
- cpu_data[2].udelay_val/500000, (cpu_data[2].udelay_val/5000)%100,
- cpu_data[3].udelay_val/500000, (cpu_data[3].udelay_val/5000)%100);
-}
-
-int smp4m_info(char *buf)
-{
- return sprintf(buf,
-" CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
-"State: %s\t\t%s\t\t%s\t\t%s\n",
-(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline",
-(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline",
-(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline",
-(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline");
-}
-
static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
{
__asm__ __volatile__("swap [%1], %0\n\t" :
@@ -168,10 +143,6 @@ __initfunc(void smp4m_boot_cpus(void))
printk("Entering SMP Mode...\n");
- smp_penguin_ctable.which_io = 0;
- smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
- smp_penguin_ctable.reg_size = 0;
-
for (i = 0; i < NR_CPUS; i++)
cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
@@ -186,7 +157,6 @@ __initfunc(void smp4m_boot_cpus(void))
mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8);
cpu_number_map[boot_cpu_id] = 0;
__cpu_logical_map[0] = boot_cpu_id;
- klock_info.akp = boot_cpu_id;
current->processor = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
set_irq_udt(mid_xlate[boot_cpu_id]);
@@ -215,6 +185,15 @@ __initfunc(void smp4m_boot_cpus(void))
/* See trampoline.S for details... */
entry += ((i-1) * 3);
+ /*
+ * Initialize the contexts table
+ * Since the call to prom_startcpu() trashes the structure,
+ * we need to re-initialize it for each cpu
+ */
+ smp_penguin_ctable.which_io = 0;
+ smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
+ smp_penguin_ctable.reg_size = 0;
+
/* whirrr, whirrr, whirrrrrrrrr... */
printk("Starting CPU %d at %p\n", i, entry);
mid_xlate[i] = (linux_cpus[i].mid & ~8);
@@ -223,10 +202,10 @@ __initfunc(void smp4m_boot_cpus(void))
&smp_penguin_ctable, 0, (char *)entry);
/* wheee... it's going... */
- for(timeout = 0; timeout < 5000000; timeout++) {
+ for(timeout = 0; timeout < 10000; timeout++) {
if(cpu_callin_map[i])
break;
- udelay(100);
+ udelay(200);
}
if(cpu_callin_map[i]) {
/* Another "Red Snapper". */
@@ -468,6 +447,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
if(!--prof_counter[cpu]) {
int user = user_mode(regs);
+
if(current->pid) {
update_one_process(current, 1, user, !user, cpu);
@@ -534,7 +514,5 @@ __initfunc(void sun4m_init_smp(void))
BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current);
BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(smp_message_pass, smp4m_message_pass, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(smp_bogo_info, smp4m_bogo_info, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(smp_info, smp4m_info, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM);
}
diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c
index deb1aa79e..2f0fe9ed7 100644
--- a/arch/sparc/kernel/sunos_ioctl.c
+++ b/arch/sparc/kernel/sunos_ioctl.c
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.30 1998/01/21 06:17:32 ecd Exp $
+/* $Id: sunos_ioctl.c,v 1.31 1998/10/25 19:31:04 davem Exp $
* sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
*
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -218,7 +218,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
}
#if 0
- if (cmd & 0xff00 == ('k' << 8)){
+ if ((cmd & 0xff00) == ('k' << 8)) {
printk ("[[KBIO: %8.8x\n", (unsigned int) cmd);
}
#endif
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index 7529c679a..e5ea2e9b3 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.46 1998/08/03 23:58:01 davem Exp $
+/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $
* linux/arch/sparc/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -181,6 +181,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
struct file * file = NULL;
unsigned long retval = -EBADF;
+ down(&current->mm->mmap_sem);
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
@@ -206,6 +207,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
}
}
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
retval = do_mmap(file, addr, len, prot, flags, off);
out_putf:
@@ -213,6 +215,7 @@ out_putf:
fput(file);
out:
unlock_kernel();
+ up(&current->mm->mmap_sem);
return retval;
}
@@ -298,6 +301,11 @@ sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
if (sigsetsize != sizeof(sigset_t))
return -EINVAL;
+ /* All tasks which use RT signals (effectively) use
+ * new style signals.
+ */
+ current->tss.new_signal = 1;
+
if (act) {
new_ka.ka_restorer = restorer;
if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index d54c9352d..086a473e3 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.91 1998/06/16 04:37:04 davem Exp $
+/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6 +68,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
struct file * file = NULL;
unsigned long retval, ret_type;
+ down(&current->mm->mmap_sem);
lock_kernel();
current->personality |= PER_BSD;
if(flags & MAP_NORESERVE) {
@@ -118,6 +119,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
}
}
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
retval = do_mmap(file, addr, len, prot, flags, off);
if(!ret_type)
retval = ((retval < PAGE_OFFSET) ? 0 : retval);
@@ -127,6 +129,7 @@ out_putf:
fput(file);
out:
unlock_kernel();
+ up(&current->mm->mmap_sem);
return retval;
}
@@ -146,6 +149,7 @@ asmlinkage int sunos_brk(unsigned long brk)
unsigned long rlim;
unsigned long newbrk, oldbrk;
+ down(&current->mm->mmap_sem);
lock_kernel();
if(ARCH_SUN4C_SUN4) {
if(brk >= 0x20000000 && brk < 0xe0000000) {
@@ -212,6 +216,7 @@ asmlinkage int sunos_brk(unsigned long brk)
retval = 0;
out:
unlock_kernel();
+ up(&current->mm->mmap_sem);
return retval;
}
@@ -578,20 +583,16 @@ struct sunos_utsname {
asmlinkage int sunos_uname(struct sunos_utsname *name)
{
- int ret = -EFAULT;
-
+ int ret;
down(&uts_sem);
- if(!name)
- goto out;
- if(copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1))
- goto out;
- copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
- put_user('\0', &name->nname[8]);
- copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
- copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
- copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
- ret = 0;
-out:
+ ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
+ if (!ret) {
+ ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
+ ret |= __put_user('\0', &name->nname[8]);
+ ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
+ ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
+ ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
+ }
up(&uts_sem);
return ret;
}
@@ -842,7 +843,7 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
strncpy (linux_nfs_mount.hostname, the_name, 254);
linux_nfs_mount.hostname [255] = 0;
putname (the_name);
-
+
dev = get_unnamed_dev ();
ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
@@ -859,6 +860,9 @@ sunos_mount(char *type, char *dir, int flags, void *data)
int ret = -EINVAL;
char *dev_fname = 0;
+ if (!capable (CAP_SYS_ADMIN))
+ return -EPERM;
+
lock_kernel();
/* We don't handle the integer fs type */
if ((flags & SMNT_NEWTYPE) == 0)
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 08aae84c9..5508f850a 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.75 1998/07/28 13:07:48 jj Exp $
+/* $Id: systbls.S,v 1.80 1998/09/21 05:04:59 jj Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -9,212 +9,156 @@
* Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
*/
-#include <asm/cprefix.h>
-
.data
.align 4
/* First, the Linux native syscall table. */
- .globl C_LABEL(sys_call_table)
-C_LABEL(sys_call_table):
-/*0*/ .long C_LABEL(sys_setup), C_LABEL(sys_exit), C_LABEL(sys_fork)
- .long C_LABEL(sys_read), C_LABEL(sys_write)
-/*5*/ .long C_LABEL(sys_open), C_LABEL(sys_close), C_LABEL(sys_wait4)
- .long C_LABEL(sys_creat), C_LABEL(sys_link)
-/*10*/ .long C_LABEL(sys_unlink), C_LABEL(sunos_execv), C_LABEL(sys_chdir)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_mknod)
-/*15*/ .long C_LABEL(sys_chmod), C_LABEL(sys_lchown), C_LABEL(sparc_brk)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_lseek)
-/*20*/ .long C_LABEL(sys_getpid), C_LABEL(sys_capget), C_LABEL(sys_capset)
- .long C_LABEL(sys_setuid), C_LABEL(sys_getuid)
-/*25*/ .long C_LABEL(sys_time), C_LABEL(sys_ptrace), C_LABEL(sys_alarm)
- .long C_LABEL(sys_sigaltstack), C_LABEL(sys_pause)
-/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
- .long C_LABEL(sys_sendfile), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
- .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid)
- .long C_LABEL(sys_signal), C_LABEL(sys_geteuid)
-/*50*/ .long C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_ioctl), C_LABEL(sys_reboot)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
- .long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
- .long C_LABEL(sys_newfstat), C_LABEL(sys_nis_syscall), C_LABEL(sys_getpagesize)
- .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_pread)
- .long C_LABEL(sys_pwrite), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_mmap), C_LABEL(sys_nis_syscall), C_LABEL(sys_munmap)
- .long C_LABEL(sys_mprotect), C_LABEL(sys_nis_syscall), C_LABEL(sys_vhangup)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getgroups)
- .long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_setitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_swapon)
- .long C_LABEL(sys_getitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_sethostname)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_dup2), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sys_rt_sigreturn)
- .long C_LABEL(sys_rt_sigaction), C_LABEL(sys_rt_sigprocmask)
- .long C_LABEL(sys_rt_sigpending), C_LABEL(sys_rt_sigtimedwait)
- .long C_LABEL(sys_rt_sigqueueinfo), C_LABEL(sys_rt_sigsuspend)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_getcwd), C_LABEL(sys_readv)
- .long C_LABEL(sys_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
- .long C_LABEL(sys_fchmod), C_LABEL(sys_nis_syscall), C_LABEL(sys_setreuid)
- .long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
- .long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_utimes)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getrlimit)
- .long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_prctl)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*150*/ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_poll), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
- .long C_LABEL(sys_umount), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_getdomainname), C_LABEL(sys_setdomainname)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_getdents), C_LABEL(sys_setsid)
- .long C_LABEL(sys_fchdir), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_sigpending), C_LABEL(sys_query_module)
- .long C_LABEL(sys_setpgid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module)
- .long C_LABEL(sys_personality), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_getppid), C_LABEL(sparc_sigaction), C_LABEL(sys_sgetmask)
-/*200*/ .long C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat)
- .long C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_idle), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo)
- .long C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_adjtimex), C_LABEL(sys_sigprocmask)
- .long C_LABEL(sys_create_module), C_LABEL(sys_delete_module)
- .long C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush)
- .long C_LABEL(sys_sysfs), C_LABEL(sys_nis_syscall), C_LABEL(sys_setfsuid)
- .long C_LABEL(sys_setfsgid), C_LABEL(sys_select), C_LABEL(sys_time)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek)
- /* "We are the Knights of the Forest of Ni!!" */
- .long C_LABEL(sys_mlock)
- .long C_LABEL(sys_munlock)
- .long C_LABEL(sys_mlockall)
-/*240*/ .long C_LABEL(sys_munlockall)
- .long C_LABEL(sys_sched_setparam)
- .long C_LABEL(sys_sched_getparam)
- .long C_LABEL(sys_sched_setscheduler)
- .long C_LABEL(sys_sched_getscheduler)
-/*245*/ .long C_LABEL(sys_sched_yield)
- .long C_LABEL(sys_sched_get_priority_max)
- .long C_LABEL(sys_sched_get_priority_min)
- .long C_LABEL(sys_sched_rr_get_interval)
- .long C_LABEL(sys_nanosleep)
-/*250*/ .long C_LABEL(sys_mremap)
- .long C_LABEL(sys_sysctl)
- .long C_LABEL(sys_getsid)
- .long C_LABEL(sys_fdatasync)
- .long C_LABEL(sys_nfsservctl)
-/*255*/ .long C_LABEL(sys_aplib)
- .long C_LABEL(sys_nis_syscall)
+ .globl sys_call_table
+sys_call_table:
+/*0*/ .long sys_nis_syscall, sys_exit, sys_fork, sys_read, sys_write
+/*5*/ .long sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/ .long sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod
+/*15*/ .long sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
+/*25*/ .long sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause
+/*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
+/*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
+/*65*/ .long sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall
+/*70*/ .long sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+/*75*/ .long sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/ .long sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+/*85*/ .long sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/ .long sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+/*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/ .long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
+/*105*/ .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
+/*110*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*115*/ .long sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
+/*120*/ .long sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+/*125*/ .long sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/ .long sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall
+/*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
+/*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
+/*175*/ .long sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
+/*185*/ .long sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/ .long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*195*/ .long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/ .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
+/*205*/ .long sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*210*/ .long sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+/*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/ .long sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+/*225*/ .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/ .long sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ /* "We are the Knights of the Forest of Ni!!" */
+/*235*/ .long sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
+/*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+/*255*/ .long sys_aplib, sys_nis_syscall
/* Now the SunOS syscall table. */
.align 4
- .globl C_LABEL(sunos_sys_table)
-C_LABEL(sunos_sys_table):
-/*0*/ .long C_LABEL(sunos_indir), C_LABEL(sys_exit), C_LABEL(sys_fork)
- .long C_LABEL(sunos_read), C_LABEL(sunos_write), C_LABEL(sunos_open)
- .long C_LABEL(sys_close), C_LABEL(sunos_wait4), C_LABEL(sys_creat)
- .long C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv)
- .long C_LABEL(sys_chdir), C_LABEL(sunos_nosys), C_LABEL(sys_mknod)
- .long C_LABEL(sys_chmod), C_LABEL(sys_lchown), C_LABEL(sunos_brk)
- .long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), C_LABEL(sunos_getpid)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sys_ptrace)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
- .long C_LABEL(sunos_nosys), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
- .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_getgid)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-/*50*/ .long C_LABEL(sunos_nosys), C_LABEL(sys_acct), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_mctl), C_LABEL(sunos_ioctl), C_LABEL(sys_reboot)
- .long C_LABEL(sunos_nosys), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
- .long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
- .long C_LABEL(sys_newfstat), C_LABEL(sunos_nosys), C_LABEL(sys_getpagesize)
- .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_sbrk), C_LABEL(sunos_sstk)
- .long C_LABEL(sunos_mmap), C_LABEL(sunos_vadvise), C_LABEL(sys_munmap)
- .long C_LABEL(sys_mprotect), C_LABEL(sunos_madvise), C_LABEL(sys_vhangup)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_mincore), C_LABEL(sys_getgroups)
- .long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sunos_setpgrp)
- .long C_LABEL(sys_setitimer), C_LABEL(sunos_nosys), C_LABEL(sys_swapon)
- .long C_LABEL(sys_getitimer), C_LABEL(sys_gethostname), C_LABEL(sys_sethostname)
- .long C_LABEL(sunos_getdtablesize), C_LABEL(sys_dup2), C_LABEL(sunos_nop)
- .long C_LABEL(sys_fcntl), C_LABEL(sunos_select), C_LABEL(sunos_nop)
- .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sunos_socket)
- .long C_LABEL(sys_connect), C_LABEL(sunos_accept)
-/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sunos_send), C_LABEL(sunos_recv)
- .long C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sunos_setsockopt)
- .long C_LABEL(sys_listen), C_LABEL(sunos_nosys), C_LABEL(sunos_sigaction)
- .long C_LABEL(sunos_sigblock), C_LABEL(sunos_sigsetmask), C_LABEL(sys_sigpause)
- .long C_LABEL(sys_sigstack), C_LABEL(sys_recvmsg), C_LABEL(sys_sendmsg)
- .long C_LABEL(sunos_nosys), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
- .long C_LABEL(sunos_getsockopt), C_LABEL(sunos_nosys), C_LABEL(sunos_readv)
- .long C_LABEL(sunos_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
- .long C_LABEL(sys_fchmod), C_LABEL(sys_recvfrom), C_LABEL(sys_setreuid)
- .long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
- .long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sunos_nosys)
- .long C_LABEL(sys_sendto), C_LABEL(sys_shutdown), C_LABEL(sys_socketpair)
- .long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_utimes)
- .long C_LABEL(sys_sigreturn), C_LABEL(sunos_nosys), C_LABEL(sys_getpeername)
- .long C_LABEL(sunos_gethostid), C_LABEL(sunos_nosys), C_LABEL(sys_getrlimit)
- .long C_LABEL(sys_setrlimit), C_LABEL(sunos_killpg), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-/*150*/ .long C_LABEL(sys_getsockname), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sys_poll), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_getdirentries), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
- .long C_LABEL(sys_umount), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sys_getdomainname), C_LABEL(sys_setdomainname)
- .long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_semsys)
- .long C_LABEL(sunos_msgsys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
- .long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sys_sigpending), C_LABEL(sunos_nosys)
- .long C_LABEL(sys_setpgid), C_LABEL(sunos_pathconf), C_LABEL(sunos_fpathconf)
- .long C_LABEL(sunos_sysconf), C_LABEL(sunos_uname), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-/*200*/ .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-/*250*/ .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sys_aplib)
+ .globl sunos_sys_table
+sunos_sys_table:
+/*0*/ .long sunos_indir, sys_exit, sys_fork
+ .long sunos_read, sunos_write, sunos_open
+ .long sys_close, sunos_wait4, sys_creat
+ .long sys_link, sys_unlink, sunos_execv
+ .long sys_chdir, sunos_nosys, sys_mknod
+ .long sys_chmod, sys_lchown, sunos_brk
+ .long sunos_nosys, sys_lseek, sunos_getpid
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_getuid, sunos_nosys, sys_ptrace
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sys_access, sunos_nosys, sunos_nosys
+ .long sys_sync, sys_kill, sys_newstat
+ .long sunos_nosys, sys_newlstat, sys_dup
+ .long sys_pipe, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_getgid
+ .long sunos_nosys, sunos_nosys
+/*50*/ .long sunos_nosys, sys_acct, sunos_nosys
+ .long sunos_mctl, sunos_ioctl, sys_reboot
+ .long sunos_nosys, sys_symlink, sys_readlink
+ .long sys_execve, sys_umask, sys_chroot
+ .long sys_newfstat, sunos_nosys, sys_getpagesize
+ .long sys_msync, sys_vfork, sunos_nosys
+ .long sunos_nosys, sunos_sbrk, sunos_sstk
+ .long sunos_mmap, sunos_vadvise, sys_munmap
+ .long sys_mprotect, sunos_madvise, sys_vhangup
+ .long sunos_nosys, sunos_mincore, sys_getgroups
+ .long sys_setgroups, sys_getpgrp, sunos_setpgrp
+ .long sys_setitimer, sunos_nosys, sys_swapon
+ .long sys_getitimer, sys_gethostname, sys_sethostname
+ .long sunos_getdtablesize, sys_dup2, sunos_nop
+ .long sys_fcntl, sunos_select, sunos_nop
+ .long sys_fsync, sys_setpriority, sunos_socket
+ .long sys_connect, sunos_accept
+/*100*/ .long sys_getpriority, sunos_send, sunos_recv
+ .long sunos_nosys, sys_bind, sunos_setsockopt
+ .long sys_listen, sunos_nosys, sunos_sigaction
+ .long sunos_sigblock, sunos_sigsetmask, sys_sigpause
+ .long sys_sigstack, sys_recvmsg, sys_sendmsg
+ .long sunos_nosys, sys_gettimeofday, sys_getrusage
+ .long sunos_getsockopt, sunos_nosys, sunos_readv
+ .long sunos_writev, sys_settimeofday, sys_fchown
+ .long sys_fchmod, sys_recvfrom, sys_setreuid
+ .long sys_setregid, sys_rename, sys_truncate
+ .long sys_ftruncate, sys_flock, sunos_nosys
+ .long sys_sendto, sys_shutdown, sys_socketpair
+ .long sys_mkdir, sys_rmdir, sys_utimes
+ .long sys_sigreturn, sunos_nosys, sys_getpeername
+ .long sunos_gethostid, sunos_nosys, sys_getrlimit
+ .long sys_setrlimit, sunos_killpg, sunos_nosys
+ .long sunos_nosys, sunos_nosys
+/*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_getdomainname, sys_setdomainname
+ .long sunos_nosys, sys_quotactl, sunos_nosys
+ .long sunos_mount, sys_ustat, sunos_semsys
+ .long sunos_msgsys, sunos_shmsys, sunos_audit
+ .long sunos_nosys, sunos_getdents, sys_setsid
+ .long sys_fchdir, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sys_sigpending, sunos_nosys
+ .long sys_setpgid, sunos_pathconf, sunos_fpathconf
+ .long sunos_sysconf, sunos_uname, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+/*200*/ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys
+/*250*/ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sys_aplib
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index dba16891c..eac95ec98 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.33 1998/07/28 16:52:48 jj Exp $
+/* $Id: time.c,v 1.39 1998/09/29 09:46:15 davem Exp $
* linux/arch/sparc/kernel/time.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,9 @@
* Chris Davis (cdavis@cois.on.ca) 03/27/1998
* Added support for the intersil on the sun4/4200
*
+ * Gleb Raiko (rajko@mech.math.msu.su) 08/18/1998
+ * Support for MicroSPARC-IIep, PCI CPU.
+ *
* This file handles the Sparc specific time handling details.
*/
#include <linux/config.h>
@@ -19,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/init.h>
+#include <linux/pci.h>
#include <asm/oplib.h>
#include <asm/segment.h>
@@ -36,6 +40,7 @@ enum sparc_clock_type sp_clock_typ;
struct mostek48t02 *mstk48t02_regs = 0;
struct mostek48t08 *mstk48t08_regs = 0;
static int set_rtc_mmss(unsigned long);
+static void sbus_do_settimeofday(struct timeval *tv);
#ifdef CONFIG_SUN4
struct intersil *intersil_clock;
@@ -71,10 +76,13 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
static long last_rtc_update=0;
#ifdef CONFIG_SUN4
- int temp;
- intersil_read_intr(intersil_clock, temp);
- /* re-enable the irq */
- enable_pil_irq(10);
+ if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
+ (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
+ int temp;
+ intersil_read_intr(intersil_clock, temp);
+ /* re-enable the irq */
+ enable_pil_irq(10);
+ }
#endif
clear_clock_irq();
@@ -83,11 +91,12 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* Determine when to update the Mostek clock. */
if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1))
+ xtime.tv_usec < 500000 + (tick >> 1)) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
}
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -316,7 +325,7 @@ static __inline__ void clock_probe(void)
kick_start_clock();
}
-__initfunc(void time_init(void))
+__initfunc(void sbus_time_init(void))
{
unsigned int year, mon, day, hour, min, sec;
struct mostek48t02 *mregs;
@@ -327,6 +336,8 @@ __initfunc(void time_init(void))
#endif
do_get_fast_time = do_gettimeofday;
+ BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
+ btfixup();
#if CONFIG_AP1000
init_timers(timer_interrupt);
@@ -344,7 +355,6 @@ __initfunc(void time_init(void))
#ifdef CONFIG_SUN4
if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
#endif
-
mregs = mstk48t02_regs;
if(!mregs) {
prom_printf("Something wrong, clock regs not mapped yet.\n");
@@ -397,7 +407,19 @@ __initfunc(void time_init(void))
__sti();
}
-static __inline__ unsigned long do_gettimeoffset(void)
+__initfunc(void time_init(void))
+{
+#ifdef CONFIG_PCI
+ extern void pci_time_init(void);
+ if (pci_present()) {
+ pci_time_init();
+ return;
+ }
+#endif
+ sbus_time_init();
+}
+
+extern __inline__ unsigned long do_gettimeoffset(void)
{
unsigned long offset = 0;
unsigned int count;
@@ -459,6 +481,11 @@ void do_gettimeofday(struct timeval *tv)
void do_settimeofday(struct timeval *tv)
{
+ bus_do_settimeofday(tv);
+}
+
+static void sbus_do_settimeofday(struct timeval *tv)
+{
cli();
#if !CONFIG_AP1000
tv->tv_usec -= do_gettimeoffset();
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 015d05357..86d632409 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.56 1998/04/06 16:08:32 jj Exp $
+/* $Id: traps.c,v 1.57 1998/09/17 11:04:51 jj Exp $
* arch/sparc/kernel/traps.c
*
* Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -242,8 +242,8 @@ extern int do_mathemu(struct pt_regs *, struct task_struct *);
void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long psr)
{
- static calls = 0;
- int ret;
+ static int calls = 0;
+ int ret = 0;
#ifndef __SMP__
struct task_struct *fpt = last_task_used_math;
#else