summaryrefslogtreecommitdiffstats
path: root/arch/sparc
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
parenteb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff)
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/Makefile47
-rw-r--r--arch/sparc/boot/Makefile31
-rw-r--r--arch/sparc/boot/btfixupprep.c85
-rw-r--r--arch/sparc/config.in9
-rw-r--r--arch/sparc/defconfig73
-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
-rw-r--r--arch/sparc/lib/bitops.S90
-rw-r--r--arch/sparc/lib/copy_user.S146
-rw-r--r--arch/sparc/lib/debuglocks.c388
-rw-r--r--arch/sparc/lib/locks.S44
-rw-r--r--arch/sparc/mm/Makefile7
-rw-r--r--arch/sparc/mm/asyncd.c2
-rw-r--r--arch/sparc/mm/fault.c39
-rw-r--r--arch/sparc/mm/generic.c11
-rw-r--r--arch/sparc/mm/init.c2
-rw-r--r--arch/sparc/mm/io-unit.c50
-rw-r--r--arch/sparc/mm/srmmu.c125
-rw-r--r--arch/sparc/mm/sun4c.c23
-rw-r--r--arch/sparc/mm/turbosparc.S48
-rw-r--r--arch/sparc/prom/console.c26
-rw-r--r--arch/sparc/prom/tree.c65
-rw-r--r--arch/sparc/vmlinux.lds2
45 files changed, 2485 insertions, 1249 deletions
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index fa171a7f7..45bec8353 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.36 1998/06/02 00:36:40 davem Exp $
+# $Id: Makefile,v 1.39 1998/09/16 12:31:31 jj Exp $
# sparc/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -15,26 +15,35 @@ SHELL =/bin/bash
# Uncomment the first CFLAGS if you are doing kgdb source level
# debugging of the kernel to get the proper debugging information.
+IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
+NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
+
+ifeq ($(NEW_GAS),y)
+AS := $(AS) -32
+LD := $(LD) -m elf32_sparc
+endif
+
#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7
+ifneq ($(IS_EGCS),y)
CFLAGS := $(CFLAGS) -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
+else
+CFLAGS := $(CFLAGS) -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
+endif
#LINKFLAGS = -N -Ttext 0xf0004000
LINKFLAGS = -T arch/sparc/vmlinux.lds
HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
-# Note arch/sparc/mm has to be the last subdir
SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/prom \
- arch/sparc/mm
+ arch/sparc/mm arch/sparc/math-emu
-CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES)
+CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES) \
+ arch/sparc/math-emu/math-emu.o
LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \
$(TOPDIR)/arch/sparc/lib/lib.a
-SUBDIRS += arch/sparc/math-emu
-CORE_FILES += arch/sparc/math-emu/math-emu.o
-
ifdef CONFIG_AP1000
SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp
CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o \
@@ -43,8 +52,14 @@ DRIVERS := $(DRIVERS) drivers/ap1000/ap1000.a
CFLAGS := $(CFLAGS) -D__MPP__=1
endif
+# This one has to come last
+SUBDIRS += arch/sparc/boot
+CORE_FILES_NO_BTFIX := $(CORE_FILES)
+CORE_FILES += arch/sparc/boot/btfix.o
+
archclean:
- -$(MAKE) -C arch/sparc/boot archclean
+ rm -f $(TOPDIR)/vmlinux.aout
+ -$(MAKE) -C arch/sparc/boot clean
archmrproper:
-$(MAKE) -C arch/sparc/math-emu cleansymlinks
@@ -57,19 +72,3 @@ check_asm:
tftpboot.img:
$(MAKE) -C arch/sparc/boot tftpboot.img
-
-vmlinux.o: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
- $(LD) -r $(VMLINUX.OBJS) -o vmlinux.o
-
-arch/sparc/boot/btfix.s: arch/sparc/boot/btfixupprep vmlinux.o
- $(OBJDUMP) -x vmlinux.o | arch/sparc/boot/btfixupprep > arch/sparc/boot/btfix.s
-
-arch/sparc/boot/btfix.o: arch/sparc/boot/btfix.s
- $(CC) -c -o arch/sparc/boot/btfix.o arch/sparc/boot/btfix.s
-
-arch/sparc/boot/btfixupprep: arch/sparc/boot/btfixupprep.c
- $(MAKE) -C arch/sparc/boot btfixupprep
-
-vmlinux: arch/sparc/boot/btfix.o
- $(LD) $(LINKFLAGS) vmlinux.o arch/sparc/boot/btfix.o -o vmlinux
- $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
index c9301a79e..b0f7f63ea 100644
--- a/arch/sparc/boot/Makefile
+++ b/arch/sparc/boot/Makefile
@@ -1,16 +1,13 @@
-# $Id: Makefile,v 1.6 1998/02/23 01:44:39 rth Exp $
+# $Id: Makefile,v 1.9 1998/10/26 20:01:03 davem Exp $
# Makefile for the Sparc boot stuff.
#
# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
-# Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+# Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
ROOT_IMG =/usr/src/root.img
ELFTOAOUT =elftoaout
-all: boot
-
-boot:
- @echo "Nothing special to be done for 'boot' on Linux/SPARC."
+all: btfix.o
tftpboot.img: piggyback
$(ELFTOAOUT) $(TOPDIR)/vmlinux -o tftpboot.img
@@ -22,8 +19,24 @@ piggyback: piggyback.c
btfixupprep: btfixupprep.c
$(HOSTCC) $(HOSTCFLAGS) -o btfixupprep btfixupprep.c
-archclean:
- rm -f btfixupprep piggyback tftpboot.img
+clean:
+ rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s
+
+BTOBJS := $(HEAD) init/main.o init/version.o \
+ $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
+ $(NETWORKS) $(DRIVERS)
+
+# I wanted to make this depend upon BTOBJS so that a parallel
+# build would work, but this fails because $(HEAD) cannot work
+# properly as it will cause head.o to be built with the implicit
+# rules not the ones in kernel/Makefile. Someone please fix. --DaveM
+vmlinux.o: dummy
+ $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o
+
+btfix.s: btfixupprep vmlinux.o
+ $(OBJDUMP) -x vmlinux.o | ./btfixupprep > btfix.s
-dep:
+btfix.o: btfix.s
+ $(CC) -c -o btfix.o btfix.s
+include $(TOPDIR)/Rules.make
diff --git a/arch/sparc/boot/btfixupprep.c b/arch/sparc/boot/btfixupprep.c
index 1bef965af..af0a1dc4e 100644
--- a/arch/sparc/boot/btfixupprep.c
+++ b/arch/sparc/boot/btfixupprep.c
@@ -1,4 +1,4 @@
-/* $Id: btfixupprep.c,v 1.3 1998/03/09 14:03:10 jj Exp $
+/* $Id: btfixupprep.c,v 1.5 1998/09/16 12:24:55 jj Exp $
Simple utility to prepare vmlinux image for sparc.
Resolves all BTFIXUP uses and settings and creates
a special .s object to link to the image.
@@ -29,8 +29,11 @@
#define MAXSYMS 1024
+static char *symtab = "SYMBOL TABLE:";
static char *relrec = "RELOCATION RECORDS FOR [";
static int rellen;
+static int symlen;
+int mode;
struct _btfixup;
@@ -97,6 +100,20 @@ int main(int argc,char **argv)
unsigned long offset;
char *initvalstr;
+ symlen = strlen(symtab);
+ while (fgets (buffer, 1024, stdin) != NULL)
+ if (!strncmp (buffer, symtab, symlen))
+ goto main0;
+ fatal();
+main0:
+ if (fgets (buffer, 1024, stdin) == NULL || buffer[0] < '0' || buffer[0] > '9')
+ fatal();
+ for (mode = 0;; mode++)
+ if (buffer[mode] < '0' || buffer[mode] > '9')
+ break;
+ if (mode != 8 && mode != 16)
+ fatal();
+
rellen = strlen(relrec);
while (fgets (buffer, 1024, stdin) != NULL)
if (!strncmp (buffer, relrec, rellen))
@@ -112,17 +129,19 @@ main1:
if (fgets (buffer, 1024, stdin) == NULL)
fatal();
while (fgets (buffer, 1024, stdin) != NULL) {
+ int nbase;
if (!strncmp (buffer, relrec, rellen))
goto main1;
p = strchr (buffer, '\n');
if (p) *p = 0;
- if (strlen (buffer) < 30)
+ if (strlen (buffer) < 22+mode)
continue;
- if (strncmp (buffer + 8, " R_SPARC_", 9))
+ if (strncmp (buffer + mode, " R_SPARC_", 9))
continue;
- if (buffer[27] != '_' || buffer[28] != '_' || buffer[29] != '_')
+ nbase = 27 - 8 + mode;
+ if (buffer[nbase] != '_' || buffer[nbase+1] != '_' || buffer[nbase+2] != '_')
continue;
- switch (buffer[30]) {
+ switch (buffer[nbase+3]) {
case 'f': /* CALL */
case 'b': /* BLACKBOX */
case 's': /* SIMM13 */
@@ -133,26 +152,26 @@ main1:
default:
continue;
}
- p = strchr (buffer + 32, '+');
+ p = strchr (buffer + nbase+5, '+');
if (p) *p = 0;
- shift = 32;
- if (buffer[31] == 's' && buffer[32] == '_') {
- shift = 33;
+ shift = nbase + 5;
+ if (buffer[nbase+4] == 's' && buffer[nbase+5] == '_') {
+ shift = nbase + 6;
if (strcmp (sect, ".text.init")) {
fprintf(stderr, "Wrong use of '%s' BTFIXUPSET.\nBTFIXUPSET_CALL can be used only in __init sections\n", buffer+shift);
exit(1);
}
- } else if (buffer[31] != '_')
+ } else if (buffer[nbase+4] != '_')
continue;
- if (strcmp (sect, ".text") && strcmp (sect, ".text.init") && (strcmp (sect, "__ksymtab") || buffer[30] != 'f')) {
- if (buffer[30] == 'f')
- fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .text.init and __ksymtab\n", buffer + shift, sect);
+ if (strcmp (sect, ".text") && strcmp (sect, ".text.init") && strcmp (sect, ".fixup") && (strcmp (sect, "__ksymtab") || buffer[nbase+3] != 'f')) {
+ if (buffer[nbase+3] == 'f')
+ fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .text.init, .fixup and __ksymtab\n", buffer + shift, sect);
else
- fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text and .text.init\n", buffer + shift, sect);
+ fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .fixup and .text.init\n", buffer + shift, sect);
exit(1);
}
p = strstr (buffer + shift, "__btset_");
- if (p && buffer[31] == 's') {
+ if (p && buffer[nbase+4] == 's') {
fprintf(stderr, "__btset_ in BTFIXUP name can only be used when defining the variable, not for setting\n%s\n", buffer);
exit(1);
}
@@ -171,23 +190,23 @@ main1:
initvalstr = p + 10;
*p = 0;
}
- f = find(buffer[30], buffer + shift);
- if (buffer[31] == 's')
+ f = find(buffer[nbase+3], buffer + shift);
+ if (buffer[nbase+4] == 's')
continue;
- switch (buffer[30]) {
+ switch (buffer[nbase+3]) {
case 'f':
if (initval) {
fprintf(stderr, "Cannot use pre-initalized fixups for calls\n%s\n", buffer);
exit(1);
}
if (!strcmp (sect, "__ksymtab")) {
- if (strncmp (buffer + 17, "32 ", 10)) {
+ if (strncmp (buffer + mode+9, "32 ", 10)) {
fprintf(stderr, "BTFIXUP_CALL in EXPORT_SYMBOL results in relocation other than R_SPARC_32\n\%s\n", buffer);
exit(1);
}
- } else if (strncmp (buffer + 17, "WDISP30 ", 10) &&
- strncmp (buffer + 17, "HI22 ", 10) &&
- strncmp (buffer + 17, "LO10 ", 10)) {
+ } else if (strncmp (buffer + mode+9, "WDISP30 ", 10) &&
+ strncmp (buffer + mode+9, "HI22 ", 10) &&
+ strncmp (buffer + mode+9, "LO10 ", 10)) {
fprintf(stderr, "BTFIXUP_CALL results in relocation other than R_SPARC_WDISP30, R_SPARC_HI22 or R_SPARC_LO10\n%s\n", buffer);
exit(1);
}
@@ -197,7 +216,7 @@ main1:
fprintf(stderr, "Cannot use pre-initialized fixups for blackboxes\n%s\n", buffer);
exit(1);
}
- if (strncmp (buffer + 17, "HI22 ", 10)) {
+ if (strncmp (buffer + mode+9, "HI22 ", 10)) {
fprintf(stderr, "BTFIXUP_BLACKBOX results in relocation other than R_SPARC_HI22\n%s\n", buffer);
exit(1);
}
@@ -207,7 +226,7 @@ main1:
fprintf(stderr, "Wrong initializer for SIMM13. Has to be from $fffff000 to $00000fff\n%s\n", buffer);
exit(1);
}
- if (strncmp (buffer + 17, "13 ", 10)) {
+ if (strncmp (buffer + mode+9, "13 ", 10)) {
fprintf(stderr, "BTFIXUP_SIMM13 results in relocation other than R_SPARC_13\n%s\n", buffer);
exit(1);
}
@@ -217,7 +236,7 @@ main1:
fprintf(stderr, "Wrong initializer for HALF.\n%s\n", buffer);
exit(1);
}
- if (strncmp (buffer + 17, "13 ", 10)) {
+ if (strncmp (buffer + mode+9, "13 ", 10)) {
fprintf(stderr, "BTFIXUP_HALF results in relocation other than R_SPARC_13\n%s\n", buffer);
exit(1);
}
@@ -227,7 +246,7 @@ main1:
fprintf(stderr, "Wrong initializer for SETHI. Cannot have set low 10 bits\n%s\n", buffer);
exit(1);
}
- if (strncmp (buffer + 17, "HI22 ", 10)) {
+ if (strncmp (buffer + mode+9, "HI22 ", 10)) {
fprintf(stderr, "BTFIXUP_SETHI results in relocation other than R_SPARC_HI22\n%s\n", buffer);
exit(1);
}
@@ -237,7 +256,7 @@ main1:
fprintf(stderr, "Cannot use pre-initalized fixups for INT\n%s\n", buffer);
exit(1);
}
- if (strncmp (buffer + 17, "HI22 ", 10) && strncmp (buffer + 17, "LO10 ", 10)) {
+ if (strncmp (buffer + mode+9, "HI22 ", 10) && strncmp (buffer + mode+9, "LO10 ", 10)) {
fprintf(stderr, "BTFIXUP_INT results in relocation other than R_SPARC_HI22 and R_SPARC_LO10\n%s\n", buffer);
exit(1);
}
@@ -261,7 +280,7 @@ main1:
exit(1);
}
offset = strtoul(buffer, &q, 16);
- if (q != buffer + 8 || (!offset && strncmp (buffer, "00000000 ", 9))) {
+ if (q != buffer + mode || (!offset && (mode == 8 ? strncmp (buffer, "00000000 ", 9) : strncmp (buffer, "0000000000000000 ", 17)))) {
fprintf(stderr, "Malformed relocation address in\n%s\n", buffer);
exit(1);
}
@@ -274,7 +293,7 @@ main1:
if (!*rr) fatal();
(*rr)->offset = offset;
(*rr)->f = NULL;
- if (buffer[30] == 'f') {
+ if (buffer[nbase+3] == 'f') {
lastf = f;
lastfoffset = offset;
lastfrelno = k;
@@ -302,11 +321,13 @@ main1:
printf("0\n");
for (r = f->rel, j--; r != NULL; j--, r = r->next) {
if (!strcmp (r->sect, ".text"))
- printf ("_stext+0x%08x", r->offset);
+ printf ("_stext+0x%08lx", r->offset);
else if (!strcmp (r->sect, ".text.init"))
- printf ("__init_begin+0x%08x", r->offset);
+ printf ("__init_begin+0x%08lx", r->offset);
else if (!strcmp (r->sect, "__ksymtab"))
- printf ("__start___ksymtab+0x%08x", r->offset);
+ printf ("__start___ksymtab+0x%08lx", r->offset);
+ else if (!strcmp (r->sect, ".fixup"))
+ printf ("__start___fixup+0x%08lx", r->offset);
else
fatal();
if (f->type == 'f' || !r->f)
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index e3aaea31c..97c970481 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.58 1998/07/29 05:06:41 davem Exp $
+# $Id: config.in,v 1.63 1998/09/21 05:05:56 jj Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -35,6 +35,9 @@ if [ "$CONFIG_AP1000" = "y" ]; then
tristate 'OPIU DDV Driver' CONFIG_DDV
else
bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
+ if [ "$CONFIG_SUN4" != "y" ]; then
+ bool 'Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI
+ fi
mainmenu_option next_comment
comment 'Console drivers'
@@ -54,9 +57,7 @@ else
define_bool CONFIG_SUN_CONSOLE y
define_bool CONFIG_SUN_AUXIO y
define_bool CONFIG_SUN_IO y
- if [ "$CONFIG_SUN4" = "y" ]; then
- bool 'Force early PROM Console' CONFIG_SUN4_FORCECONSOLE
- else
+ if [ "$CONFIG_SUN4" != "y" ]; then
source drivers/sbus/char/Config.in
source drivers/sbus/audio/Config.in
fi
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 52801ae68..7ea12a128 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -21,6 +21,7 @@ CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_AP1000 is not set
# CONFIG_SUN4 is not set
+# CONFIG_PCI is not set
#
# Console drivers
@@ -67,6 +68,8 @@ CONFIG_SUN_MOSTEK_RTC=y
# CONFIG_SPARCAUDIO is not set
# CONFIG_SPARCAUDIO_AMD7930 is not set
# CONFIG_SPARCAUDIO_CS4231 is not set
+# CONFIG_SPARCAUDIO_DBRI is not set
+# CONFIG_SPARCAUDIO_DUMMY is not set
CONFIG_SUN_OPENPROMFS=m
CONFIG_NET=y
CONFIG_SYSVIPC=y
@@ -74,7 +77,7 @@ CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
+CONFIG_BINFMT_MISC=m
CONFIG_BINFMT_JAVA=m
#
@@ -82,52 +85,32 @@ CONFIG_BINFMT_JAVA=m
#
CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_STRIPED=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
CONFIG_MD_MIRRORING=m
CONFIG_MD_RAID5=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_NBD=m
#
# Networking options
#
CONFIG_PACKET=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-# CONFIG_NETLINK_DEV is not set
-CONFIG_FIREWALL=y
-CONFIG_NET_ALIAS=y
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
+# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-CONFIG_IP_FIREWALL=y
-# CONFIG_IP_FIREWALL_NETLINK is not set
-# CONFIG_IP_TRANSPARENT_PROXY is not set
-# CONFIG_IP_ALWAYS_DEFRAG is not set
-CONFIG_IP_MASQUERADE=y
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_ICMP is not set
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_IPAUTOFW is not set
-# CONFIG_IP_MASQUERADE_IPPORTFW is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
-# CONFIG_ARPD is not set
+# CONFIG_IP_ALIAS is not set
# CONFIG_SYN_COOKIES is not set
#
@@ -146,7 +129,7 @@ CONFIG_IPX=m
# CONFIG_IPX_INTERN is not set
# CONFIG_SPX is not set
CONFIG_ATALK=m
-CONFIG_X25=m
+# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
@@ -155,18 +138,7 @@ CONFIG_X25=m
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
-CONFIG_NET_SCHED=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_CSZ=m
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-# CONFIG_NET_SCH_TEQL is not set
-CONFIG_NET_SCH_TBF=y
-# CONFIG_NET_QOS is not set
-# CONFIG_NET_CLS is not set
+# CONFIG_NET_SCHED is not set
#
# ISDN subsystem
@@ -185,7 +157,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SG=m
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -236,21 +208,22 @@ CONFIG_MYRI_SBUS=m
#
# Filesystems
#
-CONFIG_QUOTA=y
+# CONFIG_QUOTA is not set
CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
# CONFIG_JOLIET is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
+CONFIG_CODA_FS=m
CONFIG_SMB_FS=m
CONFIG_SMB_WIN95=y
CONFIG_NCP_FS=m
@@ -268,12 +241,12 @@ CONFIG_AFFS_FS=m
CONFIG_ROMFS_FS=m
CONFIG_AUTOFS_FS=m
CONFIG_AMIGA_PARTITION=y
-CONFIG_UFS_FS=y
+CONFIG_UFS_FS=m
CONFIG_BSD_DISKLABEL=y
CONFIG_SMD_DISKLABEL=y
-# CONFIG_SOLARIS_X86_PARTITION is not set
+CONFIG_SOLARIS_X86_PARTITION=y
# CONFIG_ADFS_FS is not set
-CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_NLS=y
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
diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S
index 526bf86bd..253c358fe 100644
--- a/arch/sparc/lib/bitops.S
+++ b/arch/sparc/lib/bitops.S
@@ -26,12 +26,26 @@ ___set_bit:
wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ld [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ld [%g1], %g7
or %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ st %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
st %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
@@ -48,12 +62,26 @@ ___clear_bit:
wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ld [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ld [%g1], %g7
andn %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ st %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
st %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
@@ -70,12 +98,26 @@ ___change_bit:
wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ld [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ld [%g1], %g7
xor %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ st %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
st %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
@@ -92,12 +134,26 @@ ___set_le_bit:
wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ldub [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ldub [%g1], %g7
or %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ stb %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
stb %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
@@ -113,12 +169,26 @@ ___clear_le_bit:
wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ldub [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ldub [%g1], %g7
andn %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ stb %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
stb %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
diff --git a/arch/sparc/lib/copy_user.S b/arch/sparc/lib/copy_user.S
index fceaf7a4b..728cbf9bd 100644
--- a/arch/sparc/lib/copy_user.S
+++ b/arch/sparc/lib/copy_user.S
@@ -3,7 +3,7 @@
* Copyright(C) 1995 Linus Torvalds
* Copyright(C) 1996 David S. Miller
* Copyright(C) 1996 Eddie C. Dost
- * Copyright(C) 1996 Jakub Jelinek
+ * Copyright(C) 1996,1998 Jakub Jelinek
*
* derived from:
* e-mail between David and Eddie.
@@ -13,13 +13,14 @@
#include <asm/cprefix.h>
#include <asm/ptrace.h>
+#include <asm/asmmacro.h>
#define EX(x,y,a,b,z) \
98: x,y; \
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
-99: retl; \
- a, b, %o0; \
+99: ba fixupretl; \
+ a, b, %g3; \
.section __ex_table,z##alloc; \
.align 4; \
.word 98b, 99b; \
@@ -31,8 +32,8 @@
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
99: c, d, e; \
- retl; \
- a, b, %o0; \
+ ba fixupretl; \
+ a, b, %g3; \
.section __ex_table,z##alloc; \
.align 4; \
.word 98b, 99b; \
@@ -340,7 +341,7 @@ short_aligned_end:
andcc %o2, 4, %g0
EXO2(ld [%o1 + 0x00], %g2,#)
- EX(ld [%o1 + 0x04], %g3, sub %o2, 4,#)
+ EXO2(ld [%o1 + 0x04], %g3,#)
add %o1, 8, %o1
EXO2(st %g2, [%o0 + 0x00],#)
EX(st %g3, [%o0 + 0x04], sub %o2, 4,#)
@@ -352,16 +353,32 @@ short_aligned_end:
.section .fixup,#alloc,#execinstr
.align 4
97:
- retl
- mov %o2, %o0
+ mov %o2, %g3
+fixupretl:
+ GET_PAGE_OFFSET(g1)
+ cmp %o0, %g1
+ blu 1f
+ cmp %o1, %g1
+ bgeu 1f
+ nop
+ save %sp, -64, %sp
+ mov %i0, %o0
+ call __bzero
+ mov %g3, %o1
+ restore
+1: retl
+ mov %g3, %o0
+
/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
50:
/* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK
* happens. This is derived from the amount ldd reads, st stores, etc.
* x = g2 % 12;
- * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4)
+ * g3 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? 0 : (x - 4) * 4);
+ * o0 += (g2 / 12) * 32;
*/
cmp %g2, 12
+ add %o0, %g7, %o0
bcs 1f
cmp %g2, 24
bcs 2f
@@ -370,84 +387,97 @@ short_aligned_end:
nop
sub %g2, 12, %g2
sub %g7, 32, %g7
-3:
- sub %g2, 12, %g2
+3: sub %g2, 12, %g2
sub %g7, 32, %g7
-2:
- sub %g2, 12, %g2
+2: sub %g2, 12, %g2
sub %g7, 32, %g7
-1:
- cmp %g2, 4
- bcs,a 1f
- sll %g2, 3, %g2
+1: cmp %g2, 4
+ bcs,a 60f
+ clr %g2
sub %g2, 4, %g2
sll %g2, 2, %g2
-1:
- and %g1, 0x7f, %o0
- add %o0, %g7, %o0
- retl
- sub %o0, %g2, %o0
+60: and %g1, 0x7f, %g3
+ sub %o0, %g7, %o0
+ add %g3, %g7, %g3
+ ba fixupretl
+ sub %g3, %g2, %g3
51:
/* i = 41 - g2; j = i % 6;
- * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8;
+ * g3 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : 16;
+ * o0 -= (i / 6) * 16 + 16;
*/
neg %g2
and %g1, 0xf, %g1
add %g2, 41, %g2
-1:
- cmp %g2, 6
+ add %o0, %g1, %o0
+1: cmp %g2, 6
bcs,a 2f
cmp %g2, 4
add %g1, 16, %g1
b 1b
sub %g2, 6, %g2
-2:
- bcs,a 3f
- inc %g2
- sub %g2, 3, %g2
- b 2f
- sll %g2, 3, %g2
-3:
+2: bcc,a 2f
+ mov 16, %g2
+ inc %g2
sll %g2, 2, %g2
-2:
- retl
- add %g1, %g2, %o0
+2: add %g1, %g2, %g3
+ ba fixupretl
+ sub %o0, %g3, %o0
52:
-/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */
- and %g2, 0xfffffff8, %g4
+/* g3 = g1 + g7 - (g2 / 8) * 32 + (g2 & 4) ? (g2 & 3) * 8 : 0;
+ o0 += (g2 / 8) * 32 */
+ andn %g2, 7, %g4
+ add %o0, %g7, %o0
+ andcc %g2, 4, %g0
and %g2, 3, %g2
sll %g4, 2, %g4
sll %g2, 3, %g2
- add %g2, %g4, %g2
- b,a 1b
+ bne 60b
+ sub %g7, %g4, %g7
+ ba 60b
+ clr %g2
53:
-/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */
+/* g3 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 4) ? (g2 & 3) * 2 : 0;
+ o0 += (g2 & 8) */
and %g2, 3, %g4
- and %g2, 0xfffffff8, %g2
+ andcc %g2, 4, %g0
+ and %g2, 8, %g2
sll %g4, 1, %g4
+ be 1f
+ add %o0, %g2, %o0
add %g2, %g4, %g2
- and %o2, 0xf, %o0
- add %o0, %o3, %o0
- retl
- sub %o0, %g2, %o0
+1: and %o2, 0xf, %g3
+ add %g3, %o3, %g3
+ ba fixupretl
+ sub %g3, %g2, %g3
54:
-/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */
+/* g3 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 2) ? (g2 & 1) : 0;
+ o0 += (g2 / 4) * 2 */
srl %g2, 2, %o4
- and %g2, 1, %o1
- sll %o4, 1, %o4
+ and %g2, 1, %o5
+ srl %g2, 1, %g2
+ add %o4, %o4, %o4
+ and %o5, %g2, %o5
and %o2, 0xf, %o2
- sub %o3, %o1, %o3
+ add %o0, %o4, %o0
+ sub %o3, %o5, %o3
sub %o2, %o4, %o2
- retl
- add %o2, %o3, %o0
+ ba fixupretl
+ add %o2, %o3, %g3
55:
-/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */
+/* i = 27 - g2;
+ g3 = (o2 & 1) + i / 4 * 2 + !(i & 3);
+ o0 -= i / 4 * 2 + 1 */
neg %g2
and %o2, 1, %o2
add %g2, 27, %g2
- srl %g2, 2, %o1
- and %g2, 1, %g2
- sll %o1, 1, %o1
- add %o2, %g2, %o0
- retl
- add %o0, %o1, %o0
+ srl %g2, 2, %o5
+ andcc %g2, 3, %g0
+ mov 1, %g2
+ add %o5, %o5, %o5
+ be,a 1f
+ clr %g2
+1: add %g2, %o5, %g3
+ sub %o0, %g3, %o0
+ ba fixupretl
+ add %g3, %o2, %g3
diff --git a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c
index 006cba5a8..8f0941ebf 100644
--- a/arch/sparc/lib/debuglocks.c
+++ b/arch/sparc/lib/debuglocks.c
@@ -1,7 +1,8 @@
-/* $Id: debuglocks.c,v 1.1 1997/05/08 18:13:34 davem Exp $
+/* $Id: debuglocks.c,v 1.5 1998/10/14 09:19:04 jj Exp $
* debuglocks.c: Debugging versions of SMP locking primitives.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
*/
#include <linux/kernel.h>
@@ -22,75 +23,56 @@
* number of the owner in the lowest two bits.
*/
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("spin_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
+#define STORE_CALLER(A) __asm__ __volatile__("mov %%i7, %0" : "=r" (A));
-void _spin_lock(spinlock_t *lock)
+static inline void show(char *str, spinlock_t *lock, unsigned long caller)
{
- unsigned long caller;
- unsigned long val;
int cpu = smp_processor_id();
- int stuck = INIT_STUCK;
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-again:
- __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
- if(val) {
- while(lock->lock) {
- STUCK;
- barrier();
- }
- goto again;
- }
- lock->owner_pc = (cpu & 3) | (caller & ~3);
+ printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str,
+ lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
}
-int _spin_trylock(spinlock_t *lock)
+static inline void show_read(char *str, rwlock_t *lock, unsigned long caller)
{
- unsigned long val;
- unsigned long caller;
int cpu = smp_processor_id();
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
- __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
- if(!val) {
- /* We got it, record our identity for debugging. */
- lock->owner_pc = (cpu & 3) | (caller & ~3);
- }
- return val == 0;
+ printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str,
+ lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
}
-void _spin_unlock(spinlock_t *lock)
+static inline void show_write(char *str, rwlock_t *lock, unsigned long caller)
{
- lock->owner_pc = 0;
- __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+ int cpu = smp_processor_id();
+
+ printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx) reader[0]=%08lx reader[1]=%08lx reader[2]=%08lx reader[3]=%08lx\n",
+ str, lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3,
+ lock->reader_pc[0],
+ lock->reader_pc[1],
+ lock->reader_pc[2],
+ lock->reader_pc[3]);
}
#undef INIT_STUCK
#define INIT_STUCK 100000000
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _spin_lock_irq(spinlock_t *lock)
+void _do_spin_lock(spinlock_t *lock, char *str)
{
unsigned long caller;
unsigned long val;
int cpu = smp_processor_id();
int stuck = INIT_STUCK;
- __cli();
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ STORE_CALLER(caller);
+
again:
__asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
if(val) {
while(lock->lock) {
- STUCK;
+ if (!--stuck) {
+ show(str, lock, caller);
+ stuck = INIT_STUCK;
+ }
barrier();
}
goto again;
@@ -98,362 +80,126 @@ again:
lock->owner_pc = (cpu & 3) | (caller & ~3);
}
-void _spin_unlock_irq(spinlock_t *lock)
-{
- lock->owner_pc = 0;
- __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
- __sti();
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
-
-/* Caller macro does __save_and_cli(flags) for us. */
-void _spin_lock_irqsave(spinlock_t *lock)
+int _spin_trylock(spinlock_t *lock)
{
- unsigned long caller;
unsigned long val;
+ unsigned long caller;
int cpu = smp_processor_id();
- int stuck = INIT_STUCK;
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-again:
+ STORE_CALLER(caller);
+
__asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
- if(val) {
- while(lock->lock) {
- STUCK;
- barrier();
- }
- goto again;
+ if(!val) {
+ /* We got it, record our identity for debugging. */
+ lock->owner_pc = (cpu & 3) | (caller & ~3);
}
- lock->owner_pc = (cpu & 3) | (caller & ~3);
+ return val == 0;
}
-void _spin_unlock_irqrestore(spinlock_t *lock)
+void _do_spin_unlock(spinlock_t *lock)
{
lock->owner_pc = 0;
- __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+ barrier();
+ lock->lock = 0;
}
#undef INIT_STUCK
#define INIT_STUCK 100000000
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _read_lock(rwlock_t *rw)
+void _do_read_lock(rwlock_t *rw, char *str)
{
- unsigned long flags;
unsigned long caller;
unsigned long val;
int cpu = smp_processor_id();
int stuck = INIT_STUCK;
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
- __save_and_cli(flags);
-wlock_again:
- __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff) {
- STUCK;
- barrier();
- }
- goto wlock_again;
- }
-clock_again:
- __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff00) {
- STUCK;
- barrier();
- }
- goto clock_again;
- }
- (*((unsigned short *)&rw->lock))++;
- barrier();
- (*(((unsigned short *)&rw->lock)+1)) = 0;
- __restore_flags(flags);
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_unlock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _read_unlock(rwlock_t *rw)
-{
- unsigned long flags, val, caller;
- int cpu = smp_processor_id();
- int stuck = INIT_STUCK;
-
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
- __save_and_cli(flags);
-clock_again:
- __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff00) {
- STUCK;
- barrier();
- }
- goto clock_again;
- }
- (*((unsigned short *)&rw->lock))--;
- barrier();
- (*(((unsigned char *)&rw->lock)+2))=0;
- __restore_flags(flags);
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("write_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+ STORE_CALLER(caller);
-void _write_lock(rwlock_t *rw)
-{
- unsigned long flags, val, caller;
- int cpu = smp_processor_id();
- int stuck = INIT_STUCK;
-
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
- __save_and_cli(flags);
wlock_again:
__asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
if(val) {
while(rw->lock & 0xff) {
- STUCK;
+ if (!--stuck) {
+ show_read(str, rw, caller);
+ stuck = INIT_STUCK;
+ }
barrier();
}
goto wlock_again;
}
- rw->owner_pc = (cpu & 3) | (caller & ~3);
- while(rw->lock & ~0xff) {
- STUCK;
- barrier();
- }
-}
-void _write_unlock(rwlock_t *rw)
-{
- rw->owner_pc = 0;
+ rw->reader_pc[cpu] = caller;
barrier();
- rw->lock = 0;
+ rw->lock++;
}
#undef INIT_STUCK
#define INIT_STUCK 100000000
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _read_lock_irq(rwlock_t *rw)
+void _do_read_unlock(rwlock_t *rw, char *str)
{
unsigned long caller;
unsigned long val;
int cpu = smp_processor_id();
int stuck = INIT_STUCK;
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
- __cli();
-wlock_again:
- __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff) {
- STUCK;
- barrier();
- }
- goto wlock_again;
- }
-clock_again:
- __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff00) {
- STUCK;
- barrier();
- }
- goto clock_again;
- }
- (*((unsigned short *)&rw->lock))++;
- barrier();
- (*(((unsigned short *)&rw->lock)+1)) = 0;
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+ STORE_CALLER(caller);
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_unlock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _read_unlock_irq(rwlock_t *rw)
-{
- unsigned long val, caller;
- int stuck = INIT_STUCK;
- int cpu = smp_processor_id();
-
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-clock_again:
- __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff00) {
- STUCK;
- barrier();
- }
- goto clock_again;
- }
- (*((unsigned short *)&rw->lock))--;
- barrier();
- (*(((unsigned char *)&rw->lock)+2))=0;
- __sti();
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("write_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _write_lock_irq(rwlock_t *rw)
-{
- unsigned long val, caller;
- int cpu = smp_processor_id();
- int stuck = INIT_STUCK;
-
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
- __cli();
wlock_again:
__asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
if(val) {
while(rw->lock & 0xff) {
- STUCK;
+ if (!--stuck) {
+ show_read(str, rw, caller);
+ stuck = INIT_STUCK;
+ }
barrier();
}
goto wlock_again;
}
- rw->owner_pc = (cpu & 3) | (caller & ~3);
- while(rw->lock & ~0xff) {
- STUCK;
- barrier();
- }
-}
-void _write_unlock_irq(rwlock_t *rw)
-{
- rw->owner_pc = 0;
+ rw->reader_pc[cpu] = 0;
barrier();
- rw->lock = 0;
- __sti();
+ rw->lock -= 0x1ff;
}
#undef INIT_STUCK
#define INIT_STUCK 100000000
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-/* Caller does __save_and_cli(flags) for us. */
-void _read_lock_irqsave(rwlock_t *rw)
+void _do_write_lock(rwlock_t *rw, char *str)
{
unsigned long caller;
unsigned long val;
int cpu = smp_processor_id();
int stuck = INIT_STUCK;
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ STORE_CALLER(caller);
+
wlock_again:
__asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
if(val) {
- while(rw->lock & 0xff) {
- STUCK;
+wlock_wait:
+ while(rw->lock) {
+ if (!--stuck) {
+ show_write(str, rw, caller);
+ stuck = INIT_STUCK;
+ }
barrier();
}
goto wlock_again;
}
-clock_again:
- __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff00) {
- STUCK;
- barrier();
- }
- goto clock_again;
- }
- (*((unsigned short *)&rw->lock))++;
- barrier();
- (*(((unsigned short *)&rw->lock)+1)) = 0;
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_unlock_irqrestore(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-void _read_unlock_irqrestore(rwlock_t *rw)
-{
- unsigned long val, caller;
- int cpu = smp_processor_id();
- int stuck = INIT_STUCK;
-
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-clock_again:
- __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff00) {
- STUCK;
- barrier();
- }
- goto clock_again;
+ if (rw->lock & ~0xff) {
+ *(((unsigned char *)&rw->lock)+3) = 0;
+ barrier();
+ goto wlock_wait;
}
- (*((unsigned short *)&rw->lock))--;
- barrier();
- (*(((unsigned char *)&rw->lock)+2))=0;
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("write_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-/* Caller does __save_and_cli(flags) for us. */
-void _write_lock_irqsave(rwlock_t *rw)
-{
- unsigned long val, caller;
- int cpu = smp_processor_id();
- int stuck = INIT_STUCK;
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-wlock_again:
- __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff) {
- STUCK;
- barrier();
- }
- goto wlock_again;
- }
+ barrier();
rw->owner_pc = (cpu & 3) | (caller & ~3);
- while(rw->lock & ~0xff) {
- STUCK;
- barrier();
- }
}
-void _write_unlock_irqrestore(rwlock_t *rw)
+void _do_write_unlock(rwlock_t *rw)
{
rw->owner_pc = 0;
barrier();
diff --git a/arch/sparc/lib/locks.S b/arch/sparc/lib/locks.S
index 8d634704f..102541b18 100644
--- a/arch/sparc/lib/locks.S
+++ b/arch/sparc/lib/locks.S
@@ -1,7 +1,9 @@
-/* $Id: locks.S,v 1.13 1998/07/30 11:29:28 davem Exp $
+/* $Id: locks.S,v 1.15 1998/10/14 09:18:55 jj Exp $
* locks.S: SMP low-level lock primitives on Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#include <asm/cprefix.h>
@@ -43,52 +45,48 @@ ___rw_read_enter_spin_on_wlock:
ldstub [%g1 + 3], %g2
b ___rw_read_enter_spin_on_wlock
ldub [%g1 + 3], %g2
+___rw_read_exit_spin_on_wlock:
+ orcc %g2, 0x0, %g0
+ be,a ___rw_read_exit
+ ldstub [%g1 + 3], %g2
+ b ___rw_read_exit_spin_on_wlock
+ ldub [%g1 + 3], %g2
___rw_write_enter_spin_on_wlock:
orcc %g2, 0x0, %g0
be,a ___rw_write_enter
ldstub [%g1 + 3], %g2
b ___rw_write_enter_spin_on_wlock
- ldub [%g1 + 3], %g2
+ ld [%g1], %g2
.globl ___rw_read_enter
___rw_read_enter:
orcc %g2, 0x0, %g0
bne,a ___rw_read_enter_spin_on_wlock
ldub [%g1 + 3], %g2
-1:
- ldstub [%g1 + 2], %g7
- orcc %g7, 0x0, %g0
- bne 1b
- ldsh [%g1], %g2
+ ld [%g1], %g2
add %g2, 1, %g2
- sth %g2, [%g1]
- sth %g0, [%g1 + 2]
+ st %g2, [%g1]
retl
mov %g4, %o7
- /* We must be careful here to not blow away wlock. */
.globl ___rw_read_exit
-___rw_read_exit_spin:
- ldstub [%g1 + 2], %g2
___rw_read_exit:
orcc %g2, 0x0, %g0
- bne ___rw_read_exit_spin
- ldsh [%g1], %g7
- sub %g7, 1, %g7
- sth %g7, [%g1]
- stb %g0, [%g1 + 2]
+ bne,a ___rw_read_exit_spin_on_wlock
+ ldub [%g1 + 3], %g2
+ ld [%g1], %g2
+ sub %g2, 0x1ff, %g2
+ st %g2, [%g1]
retl
mov %g4, %o7
.globl ___rw_write_enter
___rw_write_enter:
orcc %g2, 0x0, %g0
- bne,a ___rw_write_enter_spin_on_wlock
- ldub [%g1 + 3], %g2
- ld [%g1], %g2
-1:
- andncc %g2, 0xff, %g0
- bne,a 1b
+ bne ___rw_write_enter_spin_on_wlock
ld [%g1], %g2
+ andncc %g2, 0xff, %g0
+ bne,a ___rw_write_enter_spin_on_wlock
+ stb %g0, [%g1 + 3]
retl
mov %g4, %o7
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 929b2a6f0..a9e51c67f 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.31 1998/07/26 03:02:45 davem Exp $
+# $Id: Makefile,v 1.32 1998/08/16 16:02:25 ecd Exp $
# Makefile for the linux Sparc-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -12,7 +12,7 @@ O_OBJS := fault.o init.o loadmmu.o generic.o asyncd.o extable.o btfixup.o
ifeq ($(CONFIG_SUN4),y)
O_OBJS += nosrmmu.o
else
-O_OBJS += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o turbosparc.o
+O_OBJS += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o
endif
ifdef SMP
O_OBJS += nosun4c.o
@@ -25,9 +25,6 @@ include $(TOPDIR)/Rules.make
hypersparc.o: hypersparc.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S
-turbosparc.o: turbosparc.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o turbosparc.o turbosparc.S
-
viking.o: viking.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o viking.o viking.S
diff --git a/arch/sparc/mm/asyncd.c b/arch/sparc/mm/asyncd.c
index 908501dc9..666bf8429 100644
--- a/arch/sparc/mm/asyncd.c
+++ b/arch/sparc/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.11 1997/12/14 23:24:34 ecd Exp $
+/* $Id: asyncd.c,v 1.12 1998/09/13 04:30:30 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 88d85004c..3c8ffbfae 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.94 1998/05/01 16:00:27 jj Exp $
+/* $Id: fault.c,v 1.96 1998/11/08 11:13:56 davem Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -149,7 +149,9 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk,
(unsigned long) tsk->mm->context);
printk(KERN_ALERT "tsk->mm->pgd = %08lx\n",
(unsigned long) tsk->mm->pgd);
+ lock_kernel();
die_if_kernel("Oops", regs);
+ unlock_kernel();
}
asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
@@ -196,11 +198,11 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
unsigned int fixup;
unsigned long g2;
int from_user = !(regs->psr & PSR_PS);
- lock_kernel();
- down(&mm->mmap_sem);
+
if(text_fault)
address = regs->pc;
+ down(&mm->mmap_sem);
/* The kernel referencing a bad kernel pointer can lock up
* a sun4c machine completely, so we must attempt recovery.
*/
@@ -229,9 +231,10 @@ good_area:
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(current, vma, address, write);
+ if (!handle_mm_fault(current, vma, address, write))
+ goto do_sigbus;
up(&mm->mmap_sem);
- goto out;
+ return;
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
@@ -239,7 +242,7 @@ good_area:
bad_area:
up(&mm->mmap_sem);
/* Is this in ex_table? */
-
+do_kernel_fault:
g2 = regs->u_regs[UREG_G2];
if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) {
if (fixup > 10) { /* Values below are reserved for other things */
@@ -263,7 +266,7 @@ bad_area:
regs->u_regs[UREG_G2] = g2;
regs->pc = fixup;
regs->npc = regs->pc + 4;
- goto out;
+ return;
}
}
if(from_user) {
@@ -274,11 +277,18 @@ bad_area:
tsk->tss.sig_address = address;
tsk->tss.sig_desc = SUBSIG_NOMAPPING;
force_sig(SIGSEGV, tsk);
- goto out;
+ return;
}
unhandled_fault (address, tsk, regs);
-out:
- unlock_kernel();
+ return;
+
+do_sigbus:
+ up(&mm->mmap_sem);
+ tsk->tss.sig_address = address;
+ tsk->tss.sig_desc = SUBSIG_MISCERROR;
+ force_sig(SIGBUS, tsk);
+ if (! from_user)
+ goto do_kernel_fault;
}
asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
@@ -372,7 +382,8 @@ good_area:
else
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
- handle_mm_fault(current, vma, address, write);
+ if (!handle_mm_fault(current, vma, address, write))
+ goto do_sigbus;
up(&mm->mmap_sem);
return;
bad_area:
@@ -385,6 +396,12 @@ bad_area:
tsk->tss.sig_desc = SUBSIG_NOMAPPING;
send_sig(SIGSEGV, tsk, 1);
return;
+
+do_sigbus:
+ up(&mm->mmap_sem);
+ tsk->tss.sig_address = address;
+ tsk->tss.sig_desc = SUBSIG_MISCERROR;
+ force_sig(SIGBUS, tsk);
}
void window_overflow_fault(void)
diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c
index 4ad1810e3..ea94a8f60 100644
--- a/arch/sparc/mm/generic.c
+++ b/arch/sparc/mm/generic.c
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.5 1996/12/18 06:43:23 tridge Exp $
+/* $Id: generic.c,v 1.6 1998/10/27 23:28:00 davem Exp $
* generic.c: Generic Sparc mm routines that are not dependent upon
* MMU type but are Sparc specific.
*
@@ -41,10 +41,11 @@ static inline void forget_pte(pte_t page)
unsigned long addr = pte_page(page);
if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
return;
- free_page(addr);
- if (current->mm->rss <= 0)
- return;
- current->mm->rss--;
+ /*
+ * free_page() used to be able to clear swap cache
+ * entries. We may now have to do it manually.
+ */
+ free_page_and_swap_cache(addr);
return;
}
swap_free(pte_val(page));
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index eef01666d..391a4dedb 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.59 1998/03/27 06:59:57 davem Exp $
+/* $Id: init.c,v 1.60 1998/09/13 04:30:31 davem Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index 41bd72671..6cd8c9b7c 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -1,4 +1,4 @@
-/* $Id: io-unit.c,v 1.11 1998/04/13 07:26:37 davem Exp $
+/* $Id: io-unit.c,v 1.13 1998/11/08 11:13:57 davem Exp $
* io-unit.c: IO-UNIT specific routines for memory management.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -231,3 +231,51 @@ __initfunc(void ld_mmu_iounit(void))
BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
#endif
}
+
+__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size)
+{
+ int i, j, k, npages;
+ unsigned long rotor, scan, limit;
+ unsigned long flags;
+ __u32 ret;
+ struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
+
+ npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
+ i = 0x0213;
+ spin_lock_irqsave(&iounit->lock, flags);
+next: j = (i & 15);
+ rotor = iounit->rotor[j - 1];
+ limit = iounit->limit[j];
+ scan = rotor;
+nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
+ if (scan + npages > limit) {
+ if (limit != rotor) {
+ limit = rotor;
+ scan = iounit->limit[j - 1];
+ goto nexti;
+ }
+ i >>= 4;
+ if (!(i & 15))
+ panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size);
+ goto next;
+ }
+ for (k = 1, scan++; k < npages; k++)
+ if (test_bit(scan++, iounit->bmap))
+ goto nexti;
+ iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
+ scan -= npages;
+ ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
+ for (k = 0; k < npages; k++, scan++)
+ set_bit(scan, iounit->bmap);
+ spin_unlock_irqrestore(&iounit->lock, flags);
+ return ret;
+}
+
+__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus)
+{
+ int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
+ struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
+
+ iounit->page_table[scan] = MKIOPTE(mmu_v2p(((unsigned long)addr) & PAGE_MASK));
+ return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
+}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 97bd5be37..69d40fa09 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.173 1998/08/04 20:48:57 davem Exp $
+/* $Id: srmmu.c,v 1.175 1998/08/28 18:57:31 zaitcev Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1997,7 +1997,7 @@ static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long ad
static void srmmu_destroy_context(struct mm_struct *mm)
{
- if(mm->context != NO_CONTEXT && mm->count == 1) {
+ if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
flush_cache_mm(mm);
ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir);
flush_tlb_mm(mm);
@@ -2071,7 +2071,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
static void hypersparc_destroy_context(struct mm_struct *mm)
{
- if(mm->context != NO_CONTEXT && mm->count == 1) {
+ if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
ctxd_t *ctxp;
/* HyperSparc is copy-back, any data for this
@@ -2399,10 +2399,93 @@ __initfunc(static void init_swift(void))
poke_srmmu = poke_swift;
}
-/* turbosparc.S */
-extern void turbosparc_flush_cache_all(void);
-extern void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
-extern void turbosparc_flush_page_for_dma(unsigned long page);
+static void turbosparc_flush_cache_all(void)
+{
+ flush_user_windows();
+ turbosparc_idflash_clear();
+}
+
+static void turbosparc_flush_cache_mm(struct mm_struct *mm)
+{
+ FLUSH_BEGIN(mm)
+ flush_user_windows();
+ turbosparc_idflash_clear();
+ FLUSH_END
+}
+
+static void turbosparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+ FLUSH_BEGIN(mm)
+ flush_user_windows();
+ turbosparc_idflash_clear();
+ FLUSH_END
+}
+
+static void turbosparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+{
+ FLUSH_BEGIN(vma->vm_mm)
+ flush_user_windows();
+ if (vma->vm_flags & VM_EXEC)
+ turbosparc_flush_icache();
+ turbosparc_flush_dcache();
+ FLUSH_END
+}
+
+/* TurboSparc is copy-back, if we turn it on, but this does not work. */
+static void turbosparc_flush_page_to_ram(unsigned long page)
+{
+#ifdef TURBOSPARC_WRITEBACK
+ volatile unsigned long clear;
+
+ if (srmmu_hwprobe(page))
+ turbosparc_flush_page_cache(page);
+ clear = srmmu_get_fstatus();
+#endif
+}
+
+static void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{
+}
+
+static void turbosparc_flush_page_for_dma(unsigned long page)
+{
+ turbosparc_flush_dcache();
+}
+
+static void turbosparc_flush_chunk(unsigned long chunk)
+{
+}
+
+static void turbosparc_flush_tlb_all(void)
+{
+ srmmu_flush_whole_tlb();
+ module_stats.invall++;
+}
+
+static void turbosparc_flush_tlb_mm(struct mm_struct *mm)
+{
+ FLUSH_BEGIN(mm)
+ srmmu_flush_whole_tlb();
+ module_stats.invmm++;
+ FLUSH_END
+}
+
+static void turbosparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+ FLUSH_BEGIN(mm)
+ srmmu_flush_whole_tlb();
+ module_stats.invrnge++;
+ FLUSH_END
+}
+
+static void turbosparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+ FLUSH_BEGIN(vma->vm_mm)
+ srmmu_flush_whole_tlb();
+ module_stats.invpg++;
+ FLUSH_END
+}
+
__initfunc(static void poke_turbosparc(void))
{
@@ -2420,7 +2503,7 @@ __initfunc(static void poke_turbosparc(void))
#ifdef TURBOSPARC_WRITEBACK
ccreg |= (TURBOSPARC_SNENABLE); /* Do DVMA snooping in Dcache */
ccreg &= ~(TURBOSPARC_uS2 | TURBOSPARC_WTENABLE);
- /* Write-back D-cache, emulate VLSI
+ /* Write-back D-cache, emulate VLSI
* abortion number three, not number one */
#else
/* For now let's play safe, optimize later */
@@ -2428,7 +2511,8 @@ __initfunc(static void poke_turbosparc(void))
/* Do DVMA snooping in Dcache, Write-thru D-cache */
ccreg &= ~(TURBOSPARC_uS2);
/* Emulate VLSI abortion number three, not number one */
-#endif
+#endif
+
switch (ccreg & 7) {
case 0: /* No SE cache */
case 7: /* Test mode */
@@ -2449,22 +2533,17 @@ __initfunc(static void init_turbosparc(void))
srmmu_modtype = TurboSparc;
BTFIXUPSET_CALL(flush_cache_all, turbosparc_flush_cache_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, hypersparc_flush_cache_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, hypersparc_flush_cache_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, hypersparc_flush_cache_range, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_cache_mm, turbosparc_flush_cache_mm, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_cache_page, turbosparc_flush_cache_page, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_cache_range, turbosparc_flush_cache_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_all, hypersparc_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, hypersparc_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, hypersparc_flush_tlb_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, hypersparc_flush_tlb_range, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_all, turbosparc_flush_tlb_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_mm, turbosparc_flush_tlb_mm, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_page, turbosparc_flush_tlb_page, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_range, turbosparc_flush_tlb_range, BTFIXUPCALL_NORM);
-#ifdef TURBOSPARC_WRITEBACK
- BTFIXUPSET_CALL(flush_page_to_ram, hypersparc_flush_page_to_ram, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_chunk, hypersparc_flush_chunk, BTFIXUPCALL_NORM);
-#else
- BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NOP);
-#endif
+ BTFIXUPSET_CALL(flush_page_to_ram, turbosparc_flush_page_to_ram, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_chunk, turbosparc_flush_chunk, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NOP);
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index 448881608..fa8105d57 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.166 1998/08/04 20:49:05 davem Exp $
+/* $Id: sun4c.c,v 1.171 1998/09/21 05:05:41 jj Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -400,7 +400,9 @@ void sun4c_complete_all_stores(void)
_unused = sun4c_get_context();
sun4c_set_context(_unused);
+#ifdef CONFIG_SUN_AUXIO
_unused = *AUXREG;
+#endif
}
/* Bootup utility functions. */
@@ -622,9 +624,8 @@ __initfunc(static void sun4c_probe_mmu(void))
break;
case (SM_SUN4|SM_4_470):
- prom_printf("No support for 4400 yet\n");
- prom_halt();
- num_segmaps = 1024;
+ /* should be 1024 segmaps. when it get fixed */
+ num_segmaps = 256;
num_contexts = 64;
break;
default:
@@ -755,13 +756,15 @@ static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
~bits_off);
}
-/* the 4/260 dies real hard on the prom_putsegment line.
- not sure why, but it seems to work without it cgd */
static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
{
unsigned long vaddr;
unsigned char pseg, ctx;
-#ifndef CONFIG_SUN4
+#ifdef CONFIG_SUN4
+ /* sun4/110 and 260 have no kadb. */
+ if((idprom->id_machtype != (SM_SUN4 | SM_4_260)) &&
+ (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
+#endif
for(vaddr = KADB_DEBUGGER_BEGVM;
vaddr < LINUX_OPPROM_ENDVM;
vaddr += SUN4C_REAL_PGDIR_SIZE) {
@@ -773,6 +776,8 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
}
}
+#ifdef CONFIG_SUN4
+ }
#endif
for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
pseg = sun4c_get_segmap(vaddr);
@@ -2142,7 +2147,7 @@ static void sun4c_destroy_context_hw(struct mm_struct *mm)
{
struct ctx_list *ctx_old;
- if(mm->context != NO_CONTEXT && mm->count == 1) {
+ if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context);
ctx_old = ctx_list_pool + mm->context;
remove_from_ctx_list(ctx_old);
@@ -2205,7 +2210,7 @@ static void sun4c_destroy_context_sw(struct mm_struct *mm)
{
struct ctx_list *ctx_old;
- if(mm->context != NO_CONTEXT && mm->count == 1) {
+ if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);
ctx_old = ctx_list_pool + mm->context;
remove_from_ctx_list(ctx_old);
diff --git a/arch/sparc/mm/turbosparc.S b/arch/sparc/mm/turbosparc.S
deleted file mode 100644
index df580a85c..000000000
--- a/arch/sparc/mm/turbosparc.S
+++ /dev/null
@@ -1,48 +0,0 @@
-/* $Id: turbosparc.S,v 1.3 1998/05/04 12:41:29 ralf Exp $
- * turbosparc.S: High speed TurboSparc mmu/cache operations.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <asm/ptrace.h>
-#include <asm/psr.h>
-#include <asm/asi.h>
-#include <asm/page.h>
-#include <asm/pgtsrmmu.h>
-
-#define WINDOW_FLUSH(tmp1, tmp2) \
- mov 0, tmp1; \
-98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \
- orcc %g0, tmp2, %g0; \
- add tmp1, 1, tmp1; \
- bne 98b; \
- save %sp, -64, %sp; \
-99: subcc tmp1, 1, tmp1; \
- bne 99b; \
- restore %g0, %g0, %g0;
-
- .text
- .align 4
-
- .globl turbosparc_flush_cache_all
- .globl turbosparc_flush_sig_insns
- .globl turbosparc_flush_page_for_dma
-
-turbosparc_flush_cache_all:
- WINDOW_FLUSH(%g4, %g5)
- sethi %hi(vac_cache_size), %g4
- ld [%g4 + %lo(vac_cache_size)], %g5
- sethi %hi(vac_line_size), %g1
- ld [%g1 + %lo(vac_line_size)], %g2
-1:
- subcc %g5, %g2, %g5
- bne 1b
- sta %g0, [%g5] ASI_M_DATAC_TAG
- retl
- sta %g0, [%g0] ASI_M_IC_FLCLEAR
-
-turbosparc_flush_sig_insns:
-turbosparc_flush_page_for_dma:
- retl
- nop
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
index 3bbc7ade0..4a1a42309 100644
--- a/arch/sparc/prom/console.c
+++ b/arch/sparc/prom/console.c
@@ -1,8 +1,9 @@
-/* $Id: console.c,v 1.17 1998/03/09 14:04:21 jj Exp $
+/* $Id: console.c,v 1.20 1998/09/21 05:05:50 jj Exp $
* console.c: Routines that deal with sending and receiving IO
* to/from the current console device using the PROM.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Pete Zaitcev <zaitcev@metabyte.com>
*/
#include <linux/config.h>
@@ -17,6 +18,9 @@
extern void restore_current(void);
+static char con_name_jmc[] = "/obio/su@"; /* "/obio/su@0,3002f8"; */
+#define CON_SIZE_JMC (sizeof(con_name_jmc))
+
/* Non blocking get character from console input device, returns -1
* if no input was taken. This can be used for polling.
*/
@@ -83,7 +87,6 @@ prom_nbputchar(char c)
i = 0;
}
#endif
-
break;
default:
i = -1;
@@ -139,9 +142,14 @@ prom_query_input_device()
restore_flags(flags);
if(prom_node_has_property(st_p, "keyboard"))
return PROMDEV_IKBD;
- prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+ if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) {
+ if(strncmp(propb, "keyboard", sizeof("serial")) == 0)
+ return PROMDEV_IKBD;
+ }
+ if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) {
if(strncmp(propb, "serial", sizeof("serial")))
return PROMDEV_I_UNK;
+ }
prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
p = propb;
while(*p) p++; p -= 2;
@@ -154,7 +162,7 @@ prom_query_input_device()
return PROMDEV_I_UNK;
case PROM_AP1000:
return PROMDEV_I_UNK;
- };
+ }
}
/* Query for output device type */
@@ -190,9 +198,12 @@ prom_query_output_device()
return PROMDEV_OSCREEN;
}
if(prom_vers == PROM_V3) {
- if(strncmp("serial", propb, sizeof("serial")))
+ if(propl >= 0 &&
+ strncmp("serial", propb, sizeof("serial")) != 0)
return PROMDEV_O_UNK;
prom_getproperty(prom_root_node, "stdout-path", propb, sizeof(propb));
+ if(strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0)
+ return PROMDEV_OTTYA;
p = propb;
while(*p) p++; p -= 2;
if(p[0]==':') {
@@ -201,9 +212,7 @@ prom_query_output_device()
else if(p[1] == 'b')
return PROMDEV_OTTYB;
}
- return PROMDEV_O_UNK;
} else {
- /* This works on SS-2 (an early OpenFirmware) still. */
switch(*romvec->pv_stdin) {
case PROMDEV_TTYA: return PROMDEV_OTTYA;
case PROMDEV_TTYB: return PROMDEV_OTTYB;
@@ -212,7 +221,6 @@ prom_query_output_device()
break;
case PROM_AP1000:
default:
- return PROMDEV_I_UNK;
- };
+ }
return PROMDEV_O_UNK;
}
diff --git a/arch/sparc/prom/tree.c b/arch/sparc/prom/tree.c
index 1256aacec..2e79057d8 100644
--- a/arch/sparc/prom/tree.c
+++ b/arch/sparc/prom/tree.c
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.24 1998/03/09 14:04:29 jj Exp $
+/* $Id: tree.c,v 1.25 1998/09/17 11:04:58 jj Exp $
* tree.c: Basic device tree traversal/scanning for the Linux
* prom library.
*
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/ctype.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
@@ -257,29 +258,49 @@ char * prom_nextprop(int node, char *oprop, char *buffer)
int prom_finddevice(char *name)
{
- int topnd = prom_getchild(prom_root_node);
- int srch;
-
- if(name[0] == '/')
- name++;
- if(sparc_cpu_model == sun4d) {
- if(!strcmp(name, "sbus"))
- name = "sbi";
- if((srch = prom_searchsiblings(topnd, "io-unit")) == 0 ||
- (srch = prom_getchild(srch)) == 0 ||
- (srch = prom_searchsiblings(srch, name)) == 0) {
- prom_printf("%s prom node not found.\n", name);
- prom_halt();
- }
- } else if((srch = prom_searchsiblings(topnd, name)) == 0) {
- if((srch = prom_searchsiblings(topnd, "iommu")) == 0 ||
- (srch = prom_getchild(srch)) == 0 ||
- (srch = prom_searchsiblings(srch, name)) == 0) {
- prom_printf("Cannot find node %s\n", name);
- prom_halt();
+ char nbuf[128];
+ char *s = name, *d;
+ int node = prom_root_node, node2;
+ unsigned int which_io, phys_addr;
+ struct linux_prom_registers reg[PROMREG_MAX];
+
+ while (*s++) {
+ if (!*s) return node; /* path '.../' is legal */
+ node = prom_getchild(node);
+
+ for (d = nbuf; *s != 0 && *s != '@' && *s != '/';)
+ *d++ = *s++;
+ *d = 0;
+
+ node = prom_searchsiblings(node, nbuf);
+ if (!node)
+ return 0;
+
+ if (*s == '@') {
+ if (isxdigit(s[1]) && s[2] == ',') {
+ which_io = simple_strtoul(s+1, NULL, 16);
+ phys_addr = simple_strtoul(s+3, &d, 16);
+ if (d != s + 3 && (!*d || *d == '/')
+ && d <= s + 3 + 8) {
+ node2 = node;
+ while (node2 && node2 != -1) {
+ if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) {
+ if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) {
+ node = node2;
+ break;
+ }
+ }
+ node2 = prom_getsibling(node2);
+ if (!node2 || node2 == -1)
+ break;
+ node2 = prom_searchsiblings(prom_getsibling(node2), nbuf);
+ }
+ }
+ }
+ while (*s != 0 && *s != '/') s++;
}
}
- return srch;
+ return node;
}
int prom_node_has_property(int node, char *prop)
diff --git a/arch/sparc/vmlinux.lds b/arch/sparc/vmlinux.lds
index cbfc9fb3c..13e4d7202 100644
--- a/arch/sparc/vmlinux.lds
+++ b/arch/sparc/vmlinux.lds
@@ -22,7 +22,9 @@ SECTIONS
.data1 : { *(.data1) }
_edata = .;
PROVIDE (edata = .);
+ __start___fixup = .;
.fixup : { *(.fixup) }
+ __stop___fixup = .;
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;