diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
commit | 78c388aed2b7184182c08428db1de6c872d815f5 (patch) | |
tree | 4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /arch/sparc | |
parent | eb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff) |
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'arch/sparc')
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, ®s[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, ®s[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 *)®s[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(¤t->tss.float_regs[0], ¤t->tss.fsr, + ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + regs->psr &= ~(PSR_EF); + current->flags &= ~(PF_USEDFPU); + } +#else + if (current == last_task_used_math) { + put_psr(get_psr() | PSR_EF); + fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, + ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + last_task_used_math = 0; + regs->psr &= ~(PSR_EF); + } +#endif + memcpy(&fpregs->pr_fr.pr_regs[0], + ¤t->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], + ¤t->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(¤t->tss.float_regs[0], &fpu->si_float_regs[0], - (sizeof(unsigned long) * 32)); + err = __copy_from_user(¤t->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(¤t->tss.fpqueue[0], - &fpu->si_fpqueue[0], - ((sizeof(unsigned long) + - (sizeof(unsigned long *)))*16)); + err |= __copy_from_user(¤t->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], - ¤t->tss.reg_window[window], - sizeof(struct reg_window)); + err |= __copy_to_user(&sc->sigc_wbuf[window], + ¤t->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], ¤t->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], ¤t->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], ¤t->tss.fpqueue[0], - ((sizeof(unsigned long) + - (sizeof(unsigned long *)))*16)); + err |= __copy_to_user(&fpu->si_fpqueue[0], ¤t->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], ®s->u_regs [UREG_G1], sizeof (long) * 7); - copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8); + err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (long) * 7); + err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->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], ¤t->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], + ¤t->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], ®s->u_regs [UREG_G1], sizeof (uint) * 7); - copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8); + err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7); + err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->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(¤t->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(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7); - copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8); - return 0; + err |= __copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], + sizeof (long) * 7); + err |= __copy_from_user(®s->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(¤t->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(¤t->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(¤t->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(¤t->mm->mmap_sem); return retval; } @@ -146,6 +149,7 @@ asmlinkage int sunos_brk(unsigned long brk) unsigned long rlim; unsigned long newbrk, oldbrk; + down(¤t->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(¤t->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 = .; |