summaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
commit545f435ebcfd94a1e7c20b46efe81b4d6ac4e698 (patch)
treee9ce4bc598d06374bda906f18365984bf22a526a /arch/sparc64
parent4291a610eef89d0d5c69d9a10ee6560e1aa36c74 (diff)
Merge with Linux 2.1.55. More bugfixes and goodies from my private
CVS archive.
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/Makefile14
-rw-r--r--arch/sparc64/boot/Makefile2
-rw-r--r--arch/sparc64/config.in39
-rw-r--r--arch/sparc64/defconfig24
-rw-r--r--arch/sparc64/kernel/Makefile7
-rw-r--r--arch/sparc64/kernel/auxio.c36
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c3
-rw-r--r--arch/sparc64/kernel/central.c129
-rw-r--r--arch/sparc64/kernel/cpu.c9
-rw-r--r--arch/sparc64/kernel/devices.c10
-rw-r--r--arch/sparc64/kernel/dtlb_miss.S4
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S20
-rw-r--r--arch/sparc64/kernel/ebus.c326
-rw-r--r--arch/sparc64/kernel/entry.S203
-rw-r--r--arch/sparc64/kernel/etrap.S225
-rw-r--r--arch/sparc64/kernel/head.S28
-rw-r--r--arch/sparc64/kernel/ioctl32.c168
-rw-r--r--arch/sparc64/kernel/ioport.c15
-rw-r--r--arch/sparc64/kernel/irq.c717
-rw-r--r--arch/sparc64/kernel/process.c77
-rw-r--r--arch/sparc64/kernel/psycho.c1417
-rw-r--r--arch/sparc64/kernel/ptrace.c10
-rw-r--r--arch/sparc64/kernel/rtrap.S163
-rw-r--r--arch/sparc64/kernel/setup.c4
-rw-r--r--arch/sparc64/kernel/signal.c96
-rw-r--r--arch/sparc64/kernel/signal32.c62
-rw-r--r--arch/sparc64/kernel/smp.c373
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c62
-rw-r--r--arch/sparc64/kernel/sys32.S40
-rw-r--r--arch/sparc64/kernel/sys_sparc.c49
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c386
-rw-r--r--arch/sparc64/kernel/systbls.S391
-rw-r--r--arch/sparc64/kernel/time.c162
-rw-r--r--arch/sparc64/kernel/trampoline.S207
-rw-r--r--arch/sparc64/kernel/traps.c62
-rw-r--r--arch/sparc64/kernel/ttable.S6
-rw-r--r--arch/sparc64/kernel/unaligned.c56
-rw-r--r--arch/sparc64/kernel/winfixup.S8
-rw-r--r--arch/sparc64/lib/Makefile8
-rw-r--r--arch/sparc64/lib/PeeCeeI.c225
-rw-r--r--arch/sparc64/lib/VISbzero.S34
-rw-r--r--arch/sparc64/lib/VIScopy.S83
-rw-r--r--arch/sparc64/lib/VIScsum.S14
-rw-r--r--arch/sparc64/lib/VIScsumcopy.S880
-rw-r--r--arch/sparc64/lib/VISmemset.S16
-rw-r--r--arch/sparc64/lib/blockops.S10
-rw-r--r--arch/sparc64/lib/checksum.S632
-rw-r--r--arch/sparc64/lib/locks.S27
-rw-r--r--arch/sparc64/lib/strlen_user.S14
-rw-r--r--arch/sparc64/lib/strncpy_from_user.S6
-rw-r--r--arch/sparc64/mm/fault.c55
-rw-r--r--arch/sparc64/mm/init.c277
-rw-r--r--arch/sparc64/mm/ultra.S177
-rw-r--r--arch/sparc64/prom/console.c10
-rw-r--r--arch/sparc64/prom/p1275.c6
-rw-r--r--arch/sparc64/prom/ranges.c77
-rw-r--r--arch/sparc64/prom/tree.c10
-rw-r--r--arch/sparc64/solaris/Makefile26
-rw-r--r--arch/sparc64/solaris/conv.h28
-rw-r--r--arch/sparc64/solaris/entry64.S202
-rw-r--r--arch/sparc64/solaris/fs.c711
-rw-r--r--arch/sparc64/solaris/ioctl.c316
-rw-r--r--arch/sparc64/solaris/ipc.c122
-rw-r--r--arch/sparc64/solaris/misc.c463
-rw-r--r--arch/sparc64/solaris/signal.c419
-rw-r--r--arch/sparc64/solaris/signal.h109
-rw-r--r--arch/sparc64/solaris/socksys.c127
-rw-r--r--arch/sparc64/solaris/systbl.S289
-rw-r--r--arch/sparc64/vmlinux.lds6
69 files changed, 9412 insertions, 1577 deletions
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index b8cf06878..20b90a651 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.20 1997/07/11 11:05:29 jj Exp $
+# $Id: Makefile,v 1.22 1997/08/29 15:51:53 jj Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -17,7 +17,7 @@ LD = sparc64-linux-ld
NM = sparc64-linux-nm
AR = sparc64-linux-ar
RANLIB = sparc64-linux-ranlib
-ELF2AOUT64 = elf2aout64
+ELFTOAOUT = elftoaout
#
# Uncomment the first CFLAGS if you are doing kgdb source level
@@ -34,13 +34,21 @@ HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
SUBDIRS := $(SUBDIRS) arch/sparc64/kernel arch/sparc64/lib arch/sparc64/mm \
arch/sparc64/prom
+ifneq ($(CONFIG_SOLARIS_EMUL),n)
+ SUBDIRS += arch/sparc64/solaris
+endif
+
CORE_FILES := arch/sparc64/kernel/kernel.o arch/sparc64/mm/mm.o $(CORE_FILES)
+ifeq ($(CONFIG_SOLARIS_EMUL),y)
+ CORE_FILES += arch/sparc64/solaris/solaris.o
+endif
+
LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \
$(TOPDIR)/arch/sparc64/lib/lib.a
vmlinux.aout: vmlinux
- $(ELF2AOUT64) -o $(TOPDIR)/vmlinux.aout $(TOPDIR)/vmlinux
+ $(ELFTOAOUT) -o $(TOPDIR)/vmlinux.aout $(TOPDIR)/vmlinux
archclean:
rm -f $(TOPDIR)/vmlinux.aout
diff --git a/arch/sparc64/boot/Makefile b/arch/sparc64/boot/Makefile
index ed3fc6cdb..4f2b9ead3 100644
--- a/arch/sparc64/boot/Makefile
+++ b/arch/sparc64/boot/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.1 1997/07/18 06:26:30 ralf Exp $
+# $Id: Makefile,v 1.3 1997/08/29 11:08:34 davem Exp $
# Makefile for the Sparc64 boot stuff.
#
# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index fcbac5c1a..c3c438dc6 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.9 1997/07/04 11:33:05 davem Exp $
+# $Id: config.in,v 1.17 1997/09/04 01:54:43 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -43,6 +43,7 @@ else
define_bool CONFIG_SUN_CONSOLE y
define_bool CONFIG_SUN_AUXIO y
define_bool CONFIG_SUN_IO y
+ define_bool CONFIG_PCI y
source drivers/sbus/char/Config.in
fi
@@ -57,10 +58,11 @@ if [ "$CONFIG_SPARC32_COMPAT" != "n" ]; then
bool 'Kernel support for 32-bit (ie. SunOS) a.out binaries' CONFIG_BINFMT_AOUT32
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL
fi
endmenu
@@ -83,6 +85,19 @@ fi
tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+if [ "$CONFIG_PCI" = "y" ]; then
+ tristate 'Ultra/PCI IDE disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
+ if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
+ dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
+ dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
+ dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
+ dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
+ dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
+ define_bool CONFIG_IDE_CHIPSETS y
+ define_bool CONFIG_BLK_DEV_NS87415 y
+ fi
+fi
+
endmenu
if [ "$CONFIG_NET" = "y" ]; then
@@ -116,6 +131,21 @@ if [ "$CONFIG_SCSI" != "n" ]; then
bool 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
+
+ if [ "$CONFIG_PCI" != "n" ]; then
+ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
+ if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
+ bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
+ dep_tristate ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
+ if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
+ int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+ fi
+ bool ' Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
+ bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
+ int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+ fi
+ fi
+
endmenu
fi
endmenu
@@ -141,6 +171,9 @@ if [ "$CONFIG_NET" = "y" ]; then
tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
tristate 'Sun QuadEthernet support' CONFIG_SUNQE
tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
+ if [ "$CONFIG_PCI" = "y" ]; then
+ tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+ fi
# bool 'FDDI driver support' CONFIG_FDDI
# if [ "$CONFIG_FDDI" = "y" ]; then
# fi
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index c9c92b987..85958cd6e 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -29,6 +29,7 @@ CONFIG_SUN_KEYBOARD=y
CONFIG_SUN_CONSOLE=y
CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
+CONFIG_PCI=y
#
# SBUS Frame Buffer support
@@ -49,6 +50,7 @@ SUN_FB_CREATOR=y
#
CONFIG_SUN_OPENPROMIO=m
CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SAB82532 is not set
# CONFIG_SUN_BPP is not set
# CONFIG_SUN_VIDEOPIX is not set
CONFIG_SUN_OPENPROMFS=m
@@ -61,17 +63,26 @@ CONFIG_BINFMT_ELF32=y
CONFIG_BINFMT_AOUT32=y
CONFIG_BINFMT_JAVA=m
CONFIG_BINFMT_MISC=m
+CONFIG_SOLARIS_EMUL=m
#
# Floppy, IDE, and other block devices
#
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_LINEAR=m
CONFIG_MD_STRIPED=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_IDE=y
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_IDE_CHIPSETS=y
+CONFIG_BLK_DEV_NS87415=y
#
# Networking options
@@ -85,12 +96,13 @@ CONFIG_INET=y
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
#
# (it is safe to leave these untouched)
#
# CONFIG_INET_PCTCP is not set
-# CONFIG_INET_RARP is not set
+CONFIG_INET_RARP=m
CONFIG_PATH_MTU_DISCOVERY=y
CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
@@ -136,6 +148,12 @@ CONFIG_SCSI_CONSTANTS=y
#
CONFIG_SCSI_SUNESP=y
CONFIG_SCSI_QLOGICPTI=m
+CONFIG_SCSI_AIC7XXX=y
+# CONFIG_AIC7XXX_TAGGED_QUEUEING is not set
+# CONFIG_OVERRIDE_CMDS is not set
+# CONFIG_AIC7XXX_PAGE_ENABLE is not set
+# CONFIG_AIC7XXX_PROC_STATS is not set
+CONFIG_AIC7XXX_RESET_DELAY=5
#
# Network device support
@@ -155,6 +173,7 @@ CONFIG_SUNLANCE=y
CONFIG_HAPPYMEAL=y
CONFIG_SUNQE=m
CONFIG_MYRI_SBUS=m
+CONFIG_DE4X5=y
#
# Filesystems
@@ -187,6 +206,7 @@ CONFIG_AMIGA_PARTITION=y
CONFIG_UFS_FS=m
CONFIG_BSD_DISKLABEL=y
CONFIG_SMD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
#
# Kernel hacking
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index aecb9fd47..2b07a0e15 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
+# $Id: Makefile,v 1.34 1997/08/12 04:12:36 ecd Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -29,9 +29,10 @@ all: kernel.o head.o init_task.o
O_TARGET := kernel.o
O_OBJS := process.o setup.o cpu.o idprom.o \
- systbls.o traps.o devices.o auxio.o ioport.o \
+ traps.o devices.o auxio.o ioport.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
- unaligned.o sys_sunos32.o sunos_ioctl32.o
+ unaligned.o sys_sunos32.o sunos_ioctl32.o \
+ central.o psycho.o ebus.o
OX_OBJS := sparc64_ksyms.o
ifdef SMP
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 00e5f2722..91365af85 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -3,15 +3,21 @@
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+
#include <asm/oplib.h>
#include <asm/io.h>
#include <asm/auxio.h>
#include <asm/sbus.h>
+#include <asm/ebus.h>
+#include <asm/fhc.h>
/* Probe and map in the Auxiliary I/O register */
unsigned char *auxio_register;
@@ -31,9 +37,39 @@ __initfunc(void auxio_probe(void))
}
if (!sdev) {
+#ifdef CONFIG_PCI
+ struct linux_ebus *ebus;
+ struct linux_ebus_device *edev = 0;
+ unsigned long led_auxio;
+
+ for_all_ebusdev(edev, ebus)
+ if (!strcmp(edev->prom_name, "auxio"))
+ break;
+
+ if (edev) {
+ if (check_region(edev->base_address[0],
+ sizeof(unsigned int))) {
+ prom_printf("%s: Can't get region %lx, %d\n",
+ __FUNCTION__, edev->base_address[0],
+ sizeof(unsigned int));
+ prom_halt();
+ }
+ request_region(edev->base_address[0],
+ sizeof(unsigned int), "LED auxio");
+
+ led_auxio = edev->base_address[0];
+ outl(0x01, led_auxio);
+ return;
+ }
+#endif
+ if(central_bus) {
+ auxio_register = NULL;
+ return;
+ }
prom_printf("Cannot find auxio node, cannot continue...\n");
prom_halt();
}
+
prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs));
prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev);
/* Map the register both read and write */
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
index 9ab2b7aca..ef41e3f7a 100644
--- a/arch/sparc64/kernel/binfmt_elf32.c
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -8,6 +8,9 @@
#define elf_check_arch(x) (((x) == EM_SPARC) || ((x) == EM_SPARC32PLUS))
+#define ELF_ET_DYN_BASE 0x60000000
+
+
#include <asm/processor.h>
#include <linux/module.h>
#include <linux/config.h>
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
new file mode 100644
index 000000000..817a8ecd3
--- /dev/null
+++ b/arch/sparc64/kernel/central.c
@@ -0,0 +1,129 @@
+/* $Id: central.c,v 1.4 1997/08/19 14:17:49 jj Exp $
+ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+#include <asm/fhc.h>
+
+struct linux_central *central_bus = NULL;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+ return ((addr + (sizeof(unsigned long) - 1)) &
+ ~(sizeof(unsigned long) - 1));
+}
+
+extern void prom_central_ranges_init(int cnode, struct linux_central *central);
+extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc);
+
+unsigned long central_probe(unsigned long memory_start)
+{
+ struct linux_prom_registers fpregs[6];
+ struct linux_fhc *fhc;
+ char namebuf[128];
+ int cnode, fnode, err;
+
+ printk("CENTRAL: ");
+ cnode = prom_finddevice("/central");
+ if(cnode == 0 || cnode == -1) {
+ printk("no central found.\n");
+ return memory_start;
+ }
+ prom_printf("CENTRAL: found central PROM node.\n");
+ printk("found central PROM node.\n");
+
+ /* Ok we got one, grab some memory for software state. */
+ memory_start = long_align(memory_start);
+ central_bus = (struct linux_central *) (memory_start);
+
+ prom_printf("CENTRAL: central_bus[%p] ", central_bus);
+ memory_start += sizeof(struct linux_central);
+ memory_start = long_align(memory_start);
+ fhc = (struct linux_fhc *)(memory_start);
+ memory_start += sizeof(struct linux_fhc);
+ memory_start = long_align(memory_start);
+
+ prom_printf("fhc[%p] ", fhc);
+
+ /* First init central. */
+ central_bus->child = fhc;
+ central_bus->prom_node = cnode;
+
+ prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
+ strcpy(central_bus->prom_name, namebuf);
+
+ prom_printf("init_central_ranges ");
+ prom_central_ranges_init(cnode, central_bus);
+
+ /* And then central's FHC. */
+ fhc->next = NULL;
+ fhc->parent = central_bus;
+ fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
+ if(fnode == 0 || fnode == -1) {
+ prom_printf("Critical error, central board lacks fhc.\n");
+ prom_halt();
+ }
+ fhc->prom_node = fnode;
+ prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
+ strcpy(fhc->prom_name, namebuf);
+
+ prom_printf("cnode[%x] fnode[%x] init_fhc_ranges\n", cnode, fnode);
+ prom_fhc_ranges_init(fnode, fhc);
+
+ /* Finally, map in FHC register set. (From the prtconf dumps
+ * I have seen on Ex000 boxes only the central ranges need to
+ * be applied to the fhc internal register set) -DaveM
+ */
+ err = prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs));
+ if(err == -1) {
+ prom_printf("CENTRAL: fatal error, cannot get fhc regs.\n");
+ prom_halt();
+ }
+ prom_apply_central_ranges(central_bus, &fpregs[0], 6);
+ prom_printf("CENTRAL: FHC_REGS[(%08x,%08x) (%08x,%08x) "
+ "(%08x,%08x) (%08x,%08x) (%08x,%08x) (%08x,%08x)]\n",
+ fpregs[0].which_io, fpregs[0].phys_addr,
+ fpregs[1].which_io, fpregs[1].phys_addr,
+ fpregs[2].which_io, fpregs[2].phys_addr,
+ fpregs[3].which_io, fpregs[3].phys_addr,
+ fpregs[4].which_io, fpregs[4].phys_addr,
+ fpregs[5].which_io, fpregs[5].phys_addr);
+ fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
+ __va((((unsigned long)fpregs[0].which_io)<<32) |
+ (((unsigned long)fpregs[0].phys_addr)));
+ fhc->fhc_regs.ireg = (struct fhc_ign_reg *)
+ __va((((unsigned long)fpregs[1].which_io)<<32) |
+ (((unsigned long)fpregs[1].phys_addr)));
+ fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *)
+ __va((((unsigned long)fpregs[2].which_io)<<32) |
+ (((unsigned long)fpregs[2].phys_addr)));
+ fhc->fhc_regs.sregs = (struct fhc_system_regs *)
+ __va((((unsigned long)fpregs[3].which_io)<<32) |
+ (((unsigned long)fpregs[3].phys_addr)));
+ fhc->fhc_regs.uregs = (struct fhc_uart_regs *)
+ __va((((unsigned long)fpregs[4].which_io)<<32) |
+ (((unsigned long)fpregs[4].phys_addr)));
+ fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
+ __va((((unsigned long)fpregs[5].which_io)<<32) |
+ (((unsigned long)fpregs[5].phys_addr)));
+ prom_printf("CENTRAL: FHC_REGS[%p %p %p %p %p %p]\n",
+ fhc->fhc_regs.pregs, fhc->fhc_regs.ireg,
+ fhc->fhc_regs.ffregs, fhc->fhc_regs.sregs,
+ fhc->fhc_regs.uregs, fhc->fhc_regs.tregs);
+
+ prom_printf("CENTRAL: reading FHC_ID register... ");
+ err = fhc->fhc_regs.pregs->fhc_id;
+ prom_printf("VALUE[%x]\n", err);
+ printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n",
+ ((err & FHC_ID_VERS) >> 28),
+ ((err & FHC_ID_PARTID) >> 12),
+ ((err & FHC_ID_MANUF) >> 1));
+
+ return memory_start;
+}
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 2c96a83e9..d009f39d8 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -46,8 +46,13 @@ struct cpu_iu_info linux_sparc_chips[] = {
#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
-char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
-char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#ifdef __SMP__
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#else
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", };
+#endif
unsigned int fsr_storage;
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 9327058a8..24ca3ff10 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -17,13 +17,14 @@ struct prom_cpuinfo linux_cpus[NR_CPUS];
int linux_num_cpus = 0;
extern void cpu_probe(void);
+extern unsigned long central_probe(unsigned long);
__initfunc(unsigned long
device_scan(unsigned long mem_start))
{
char node_str[128];
int nd, prom_node_cpu, thismid;
- int cpu_nds[NCPUS]; /* One node for each cpu */
+ int cpu_nds[NR_CPUS]; /* One node for each cpu */
int cpu_ctr = 0;
prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
@@ -43,11 +44,14 @@ device_scan(unsigned long mem_start))
if(strcmp(node_str, "cpu") == 0) {
cpu_nds[cpu_ctr] = scan;
linux_cpus[cpu_ctr].prom_node = scan;
- prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+ prom_getproperty(scan, "upa-portid",
+ (char *) &thismid, sizeof(thismid));
linux_cpus[cpu_ctr].mid = thismid;
prom_printf("Found CPU %d <node=%08x,mid=%d>\n",
cpu_ctr, (unsigned) scan,
thismid);
+ printk("Found CPU %d <node=%08x,mid=%d>\n",
+ cpu_ctr, (unsigned) scan, thismid);
cpu_ctr++;
}
};
@@ -62,5 +66,5 @@ device_scan(unsigned long mem_start))
linux_num_cpus = cpu_ctr;
cpu_probe();
- return mem_start;
+ return central_probe(mem_start);
}
diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S
index b034ef407..04efb1cec 100644
--- a/arch/sparc64/kernel/dtlb_miss.S
+++ b/arch/sparc64/kernel/dtlb_miss.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_miss.S,v 1.12 1997/06/26 12:47:08 jj Exp $
+/* $Id: dtlb_miss.S,v 1.13 1997/08/14 19:27:15 davem Exp $
* dtlb_miss.S: Data TLB miss code, this is included directly
* into the trap table.
*
@@ -62,7 +62,7 @@
/*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET
/*0x44*/ brgez,pn %g5, 4f ! If >= 0, then walk down page tables
/*0x48*/ sethi %uhi(KERN_HIGHBITS), %g1 ! Construct PTE ^ PAGE_OFFSET
- /*0x4c*/ andcc %g3, 0x80, %g0 ! Slick trick...
+ /*0x4c*/ andcc %g3, 0x400, %g0 ! Slick trick...
/*0x50*/ sllx %g1, 32, %g1 ! Move high bits up
/*0x54*/ or %g1, (KERN_LOWBITS), %g1 ! Assume not IO
/*0x58*/ bne,a,pn %icc, 5f ! Is it an IO page?
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index 2cf372ca9..55e86c887 100644
--- a/arch/sparc64/kernel/dtlb_prot.S
+++ b/arch/sparc64/kernel/dtlb_prot.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $
+/* $Id: dtlb_prot.S,v 1.14 1997/08/03 09:07:00 davem Exp $
* dtlb_prot.S: Data TLB protection code, this is included directly
* into the trap table.
*
@@ -36,17 +36,17 @@
/* ICACHE line 3 */
/*0x40*/ add %g2, 7, %g5 ! Compute mask
/*0x44*/ andn %g4, %g5, %g4 ! Mask page
- /*0x48*/ or %g4, 0x10, %g4 ! 2ndary Context
- /*0x4c*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
- /*0x50*/ membar #Sync ! Synchronize
- /*0x54*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE
- /*0x58*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
- /*0x5c*/ retry ! Trap return
+ /*0x48*/ mov TLB_SFSR, %g5 ! read SFSR
+ /*0x4c*/ ldxa [%g5] ASI_DMMU, %g5 ! from DMMU for
+ /*0x50*/ and %g5, 0x10, %g5 ! context bit
+ /*0x54*/ or %g4, %g5, %g4 ! for prot trap
+1:/*0x58*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
+ /*0x5c*/ membar #Sync ! Synchronize
/* ICACHE line 4 */
- /*0x60*/ nop
- /*0x64*/ nop
- /*0x68*/ nop
+ /*0x60*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE
+ /*0x64*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x68*/ retry ! Trap return
/*0x6c*/ nop
/*0x70*/ nop
/*0x74*/ nop
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
new file mode 100644
index 000000000..f484cfef8
--- /dev/null
+++ b/arch/sparc64/kernel/ebus.c
@@ -0,0 +1,326 @@
+/* $Id: ebus.c,v 1.8 1997/09/05 22:59:39 ecd Exp $
+ * ebus.c: PCI to EBus bridge device.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#include <asm/oplib.h>
+#include <asm/bpp.h>
+
+#undef DEBUG_FILL_EBUS_DEV
+
+struct linux_ebus *ebus_chain = 0;
+
+extern void prom_ebus_ranges_init(struct linux_ebus *);
+extern unsigned long pci_console_init(unsigned long memory_start);
+
+#ifdef CONFIG_SUN_OPENPROMIO
+extern int openprom_init(void);
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+extern int rtc_init(void);
+#endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
+#ifdef CONFIG_SUN_AUXIO
+extern void auxio_probe(void);
+#endif
+
+extern unsigned int psycho_irq_build(unsigned int full_ino);
+
+static inline unsigned long
+ebus_alloc(unsigned long *memory_start, size_t size)
+{
+ unsigned long mem;
+
+ *memory_start = (*memory_start + 7) & ~(7);
+ mem = *memory_start;
+ *memory_start += size;
+ return mem;
+}
+
+__initfunc(void fill_ebus_child(int node, 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;
+ } else {
+ dev->num_irqs = len / sizeof(irqs[0]);
+ for (i = 0; i < dev->num_irqs; i++)
+ dev->irqs[i] = psycho_irq_build(irqs[i]);
+ }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+ printk("child '%s': address%s\n", dev->prom_name,
+ dev->num_addrs > 1 ? "es" : "");
+ for (i = 0; i < dev->num_addrs; i++)
+ printk(" %016lx\n", dev->base_address[i]);
+ if (dev->num_irqs) {
+ printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ for (i = 0; i < dev->num_irqs; i++)
+ printk(" %08x", dev->irqs[i]);
+ printk("\n");
+ }
+#endif
+}
+
+__initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *dev,
+ unsigned long memory_start))
+{
+ 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->parent->self->base_address[n];
+ dev->base_address[i] += (unsigned long)regs[i].phys_addr;
+ }
+
+ 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]);
+ for (i = 0; i < dev->num_irqs; i++)
+ dev->irqs[i] = psycho_irq_build(irqs[i]);
+ }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+ printk("'%s': address%s\n", dev->prom_name,
+ dev->num_addrs > 1 ? "es" : "");
+ for (i = 0; i < dev->num_addrs; i++)
+ printk(" %016lx\n", dev->base_address[i]);
+ if (dev->num_irqs) {
+ printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ for (i = 0; i < dev->num_irqs; i++)
+ printk(" %08x", dev->irqs[i]);
+ printk("\n");
+ }
+#endif
+ if ((node = prom_getchild(node))) {
+ dev->children = (struct linux_ebus_child *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+
+ child = dev->children;
+ child->next = 0;
+ child->parent = dev;
+ fill_ebus_child(node, child);
+
+ while ((node = prom_getsibling(node))) {
+ child->next = (struct linux_ebus_child *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+
+ child = child->next;
+ child->next = 0;
+ child->parent = dev;
+ fill_ebus_child(node, child);
+ }
+ }
+
+ return memory_start;
+}
+
+__initfunc(unsigned long ebus_init(unsigned long memory_start,
+ unsigned long memory_end))
+{
+ 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, rng, nreg;
+ int num_ebus = 0;
+
+ if (!pcibios_present())
+ return memory_start;
+
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
+ break;
+ }
+ if (!pdev) {
+ printk("ebus: No EBus's found.\n");
+ return memory_start;
+ }
+
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus_chain = ebus = (struct linux_ebus *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus));
+ ebus->next = 0;
+
+ while (ebusnd) {
+ printk("ebus%d:\n", num_ebus);
+
+ 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. */
+ pcibios_read_config_word(pdev->bus->number, pdev->devfn,
+ PCI_COMMAND, &pci_command);
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pdev->bus->number, pdev->devfn,
+ 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].phys_hi & 0x03000000))
+ continue;
+
+ for (rng = 0; rng < pbm->num_pbm_ranges; rng++) {
+ struct linux_prom_pci_ranges *rp =
+ &pbm->pbm_ranges[rng];
+
+ if ((rp->child_phys_hi ^ regs[reg].phys_hi)
+ & 0x03000000)
+ continue;
+
+ addr = (u64)regs[reg].phys_lo;
+ addr += (u64)regs[reg].phys_mid << 32UL;
+ addr += (u64)rp->parent_phys_lo;
+ addr += (u64)rp->parent_phys_hi << 32UL;
+ *base++ = (unsigned long)__va(addr);
+
+ break;
+ }
+ }
+
+ prom_ebus_ranges_init(ebus);
+
+ nd = prom_getchild(ebusnd);
+ ebus->devices = (struct linux_ebus_device *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
+
+ dev = ebus->devices;
+ dev->next = 0;
+ dev->children = 0;
+ dev->parent = ebus;
+ memory_start = fill_ebus_device(nd, dev, memory_start);
+
+ while ((nd = prom_getsibling(nd))) {
+ dev->next = (struct linux_ebus_device *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
+
+ dev = dev->next;
+ dev->next = 0;
+ dev->children = 0;
+ dev->parent = ebus;
+ memory_start = fill_ebus_device(nd, dev, memory_start);
+ }
+
+ for (pdev = pdev->next; pdev; pdev = pdev->next) {
+ if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
+ break;
+ }
+ if (!pdev)
+ break;
+
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus->next = (struct linux_ebus *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus));
+ ebus = ebus->next;
+ ebus->next = 0;
+ ++num_ebus;
+ }
+
+ memory_start = pci_console_init(memory_start);
+
+#ifdef CONFIG_SUN_OPENPROMIO
+ openprom_init();
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+ rtc_init();
+#endif
+#ifdef CONFIG_SPARCAUDIO
+ sparcaudio_init();
+#endif
+#ifdef CONFIG_SUN_BPP
+ bpp_init();
+#endif
+#ifdef CONFIG_SUN_AUXIO
+ if (sparc_cpu_model == sun4u)
+ auxio_probe();
+#endif
+#ifdef __sparc_v9__
+ if (sparc_cpu_model == sun4u) {
+ extern void sun4u_start_timers(void);
+ extern void clock_probe(void);
+
+ sun4u_start_timers();
+ clock_probe();
+ }
+#endif
+ return memory_start;
+}
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 425c2d873..a6e2d6da7 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,9 +1,9 @@
-/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
+/* $Id: entry.S,v 1.65 1997/08/29 15:51:29 jj Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
@@ -17,6 +17,7 @@
#include <asm/page.h>
#include <asm/signal.h>
#include <asm/pgtable.h>
+#include <asm/processor.h>
/* #define SYSCALL_TRACING */
@@ -50,41 +51,39 @@ sparc64_dtlb_prot_catch:
bgu,a,pn %icc, winfix_trampoline
rdpr %tpc, %g3
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
b,pt %xcc, 1f
mov 1, %o2
+ .align 32
sparc64_dtlb_refbit_catch:
srlx %g5, 9, %g4
and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
-
cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
be,a,pt %xcc, 2f
mov 1, %g4
wr %g0, ASI_DMMU, %asi
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+
rdpr %tl, %g3
ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
-
cmp %g3, 1
bgu,pn %icc, winfix_trampoline
rdpr %tpc, %g3
+ sethi %hi(109f), %g7
b,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
+
clr %o2
1: srlx %l5, PAGE_SHIFT, %o1
add %sp, STACK_BIAS + REGWIN_SZ, %o0
-
call do_sparc64_fault
sllx %o1, PAGE_SHIFT, %o1
b,pt %xcc, rtrap
clr %l6
- nop
- nop
- nop
- nop
-
+ .align 32
sparc64_itlb_refbit_catch:
srlx %g5, 9, %g4
and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
@@ -95,17 +94,21 @@ sparc64_itlb_refbit_catch:
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
rdpr %tpc, %g5
+ sethi %hi(109f), %g7
b,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
b,pt %xcc, 1b
clr %o2
+
+ .align 32
2: sllx %g4, 63, %g4 ! _PAGE_VALID
or %g5, _PAGE_ACCESSED, %g5
or %g5, %g4, %g5
stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE
-
stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
retry
+
+ .align 32
3: sllx %g4, 63, %g4 ! _PAGE_VALID
or %g5, _PAGE_ACCESSED, %g5
or %g5, %g4, %g5
@@ -113,24 +116,33 @@ sparc64_itlb_refbit_catch:
stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
retry
+#define FPDIS_OFF (((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))
/* This is trivial with the new code... */
.align 32
.globl do_fpdis
do_fpdis:
- wr %g0, FPRS_FEF, %fprs
- ldx [%g6 + AOFF_task_flags], %g2
- sethi %hi(0x00100000), %g4 ! XXX PF_USEDFPU
- andcc %g2, %g4, %g0
-
- bne,a,pt %xcc, fpload_fromkstk
- sethi %hi((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2
- fzero %f0
- fzero %f2
+ ldx [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group
+ sethi %hi(TSTATE_PEF), %g4 ! IEU0
+ sethi %hi(FPDIS_OFF), %g3 ! IEU1
+ wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles
+ andcc %g5, SPARC_FLAG_USEDFPU, %g0 ! IEU1 Group
+ or %g3, %lo(FPDIS_OFF), %g2 ! IEU0
+ sethi %hi(empty_zero_page), %g1 ! IEU0 Group
+ add %g6, %g2, %g2 ! IEU1
+ be,a,pn %icc, 1f ! CTI
+ clr %g7 ! IEU0 Group
+ add %g2, 0x100, %g1 ! IEU1
+ ldx [%g2 + 0x108], %g7 ! Load
+1: andcc %g5, SPARC_FLAG_USEDFPUL, %g0 ! IEU1 Group
+ bne,pn %icc, 2f ! CTI
+ fzero %f0 ! FPA
+ andcc %g5, SPARC_FLAG_USEDFPUU, %g0 ! IEU1 Group
+ bne,pn %icc, 1f ! CTI
+ fzero %f2 ! FPA
faddd %f0, %f2, %f4
fmuld %f0, %f2, %f6
faddd %f0, %f2, %f8
fmuld %f0, %f2, %f10
-
faddd %f0, %f2, %f12
fmuld %f0, %f2, %f14
faddd %f0, %f2, %f16
@@ -139,7 +151,6 @@ do_fpdis:
fmuld %f0, %f2, %f22
faddd %f0, %f2, %f24
fmuld %f0, %f2, %f26
-
faddd %f0, %f2, %f28
fmuld %f0, %f2, %f30
faddd %f0, %f2, %f32
@@ -148,54 +159,92 @@ do_fpdis:
fmuld %f0, %f2, %f38
faddd %f0, %f2, %f40
fmuld %f0, %f2, %f42
-
faddd %f0, %f2, %f44
fmuld %f0, %f2, %f46
- ldx [%g6 + AOFF_task_flags], %g2
faddd %f0, %f2, %f48
fmuld %f0, %f2, %f50
- or %g2, %g4, %g2
faddd %f0, %f2, %f52
fmuld %f0, %f2, %f54
-
- stx %g2, [%g6 + AOFF_task_flags]
faddd %f0, %f2, %f56
- sethi %hi(empty_zero_page), %g3
fmuld %f0, %f2, %f58
-
- faddd %f0, %f2, %f60
- ldx [%g3], %fsr ! wheee, empty_zero_page
+ b,pt %xcc, fpdis_exit2
+ faddd %f0, %f2, %f60
+1: mov SECONDARY_CONTEXT, %g3
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+ ldxa [%g3] ASI_DMMU, %g5
+ stxa %g0, [%g3] ASI_DMMU
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ flush %g2
+ wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ membar #StoreLoad | #LoadLoad
+ ldda [%g2 + 0x080] %asi, %f32
+ ldda [%g2 + 0x0c0] %asi, %f48
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
b,pt %xcc, fpdis_exit
- wr %g0, 0, %gsr
-
-fpload_fromkstk:
- or %g2, %lo((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2
- add %g6, %g2, %g2
+ membar #Sync
+2: andcc %g5, SPARC_FLAG_USEDFPUU, %g0
+ bne,pt %icc, 3f
+ fzero %f32
mov SECONDARY_CONTEXT, %g3
+ fzero %f34
+ ldxa [%g3] ASI_DMMU, %g5
+ stxa %g0, [%g3] ASI_DMMU
+ faddd %f32, %f34, %f36
+ fmuld %f32, %f34, %f38
+ flush %g2
+ wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ membar #StoreLoad | #LoadLoad
+ ldda [%g2 + 0x000] %asi, %f0
+ ldda [%g2 + 0x040] %asi, %f16
+ faddd %f32, %f34, %f40
+ fmuld %f32, %f34, %f42
+ faddd %f32, %f34, %f44
+ fmuld %f32, %f34, %f46
+ faddd %f32, %f34, %f48
+ fmuld %f32, %f34, %f50
+ faddd %f32, %f34, %f52
+ fmuld %f32, %f34, %f54
+ faddd %f32, %f34, %f56
+ fmuld %f32, %f34, %f58
+ faddd %f32, %f34, %f60
+ fmuld %f32, %f34, %f62
+ b,pt %xcc, fpdis_exit
+ membar #Sync
+3: mov SECONDARY_CONTEXT, %g3
+ ldxa [%g3] ASI_DMMU, %g5
stxa %g0, [%g3] ASI_DMMU
flush %g2
wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
membar #StoreLoad | #LoadLoad
-
ldda [%g2 + 0x000] %asi, %f0
ldda [%g2 + 0x040] %asi, %f16
ldda [%g2 + 0x080] %asi, %f32
ldda [%g2 + 0x0c0] %asi, %f48
- ldx [%g2 + 0x100], %fsr
- ldx [%g2 + 0x108], %g2
membar #Sync
- wr %g2, 0, %gsr
fpdis_exit:
+ stxa %g5, [%g3] ASI_DMMU
+ flush %g2
+fpdis_exit2:
+ wr %g7, 0, %gsr
+ ldx [%g1], %fsr
rdpr %tstate, %g3
- sethi %hi(TSTATE_PEF), %g4
or %g3, %g4, %g3 ! anal...
wrpr %g3, %tstate
+ wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits
retry
-#ifdef __SMP__
- /* Note check out head.h, this code isn't even used for UP,
- * for SMP things will be different. In particular the data
- * registers for cross calls will be:
+ /* The registers for cross calls will be:
*
* DATA 0: [low 32-bits] Address of function to call, jmp to this
* [high 32-bits] MMU Context Argument 0, place in %g5
@@ -205,11 +254,17 @@ fpdis_exit:
* With this method we can do most of the cross-call tlb/cache
* flushing very quickly.
*/
+ .data
+ .align 8
+ .globl ivec_spurious_cookie
+ivec_spurious_cookie: .xword 0
+
+ .text
.align 32
- .globl do_ivec, do_ivec_return
+ .globl do_ivec
do_ivec:
- ldxa [%g0] ASI_INTR_RECEIVE, %g1
- andcc %g1, 0x20, %g0
+ ldxa [%g0] ASI_INTR_RECEIVE, %g5
+ andcc %g5, 0x20, %g0
be,pn %xcc, do_ivec_return
mov 0x40, %g2
@@ -223,39 +278,45 @@ do_ivec:
sllx %g3, 3, %g3
ldx [%g1 + %g3], %g2
brz,pn %g2, do_ivec_spurious
- nop
+ sethi %hi(0x80000000), %g5
+
+ or %g2, %g5, %g2
+ stx %g2, [%g1 + %g3]
/* No branches, worse case we don't know about this interrupt
* yet, so we would just write a zero into the softint register
* which is completely harmless.
*/
wr %g2, 0x0, %set_softint
-
do_ivec_return:
- /* Acknowledge the UPA */
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
retry
do_ivec_xcall:
srlx %g3, 32, %g5
add %g2, 0x10, %g2
- sra %g3, 0, %g3
+ srl %g3, 0, %g3
ldxa [%g2] ASI_UDB_INTR_R, %g6
add %g2, 0x10, %g2
+ ldxa [%g2] ASI_UDB_INTR_R, %g7
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
jmpl %g3, %g0
- ldxa [%g2] ASI_UDB_INTR_R, %g7
+ membar #Sync
do_ivec_spurious:
+ srl %g3, 3, %g3
+ sethi %hi(ivec_spurious_cookie), %g2
+ stx %g3, [%g2 + %lo(ivec_spurious_cookie)]
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pstate, %g5
+ wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
call report_spurious_ivec
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
clr %l6
-#endif /* __SMP__ */
.globl getcc, setcc
getcc:
@@ -359,8 +420,9 @@ floppy_overrun:
floppy_dosoftint:
rdpr %pil, %g2
wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
b,pt %xcc, etrap_irq
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
mov 11, %o0
mov 0, %o1
@@ -373,10 +435,8 @@ floppy_dosoftint:
#endif /* CONFIG_BLK_DEV_FD */
/* XXX Here is stuff we still need to write... -DaveM XXX */
- .globl indirect_syscall, netbsd_syscall, solaris_syscall
-indirect_syscall:
+ .globl netbsd_syscall
netbsd_syscall:
-solaris_syscall:
retl
nop
@@ -386,8 +446,9 @@ do_mna:
cmp %g3, 1
bgu,a,pn %icc, winfix_mna
rdpr %tpc, %g3
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
call mem_address_unaligned
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
@@ -573,14 +634,8 @@ sys_fork:
sys_vfork: mov SIGCHLD, %o0
clr %o1
sys_clone: mov %o7, %l5
-/*???*/ save %sp, -REGWIN_SZ, %sp
- flushw
-/*???*/ restore %g0, %g0, %g0
- rdpr %cwp, %o4
add %sp, STACK_BIAS + REGWIN_SZ, %o2
-
movrz %o1, %fp, %o1
- stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
call do_fork
mov %l5, %o7
#ifdef __SMP__
@@ -611,9 +666,9 @@ linux_sparc_syscall:
cmp %g1, NR_SYSCALLS ! IEU1 Group
bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
mov %i0, %o0 ! IEU0
- sll %g1, 3, %l4 ! IEU0 Group
+ sll %g1, 2, %l4 ! IEU0 Group
mov %i1, %o1 ! IEU1
- ldx [%l7 + %l4], %l7 ! Load
+ lduw [%l7 + %l4], %l7 ! Load
syscall_is_too_hard:
mov %i2, %o2 ! IEU0 Group
ldx [%curptr + AOFF_task_flags], %l5 ! Load
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 4daf30e21..e10480454 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.30 1997/06/30 10:31:37 jj Exp $
+/* $Id: etrap.S,v 1.37 1997/08/21 09:13:18 davem Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
* Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -15,118 +15,127 @@
#define FPUREG_SZ ((64 * 4) + (2 * 8))
#define TASK_REGOFF ((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \
TRACEREG_SZ-REGWIN_SZ)
+#define FPU_OFF (STACK_BIAS + REGWIN_SZ + TRACEREG_SZ)
+
+/*
+ * On entry, %g7 is return address - 0x4.
+ * %g4 and %g5 will be preserved %l4 and %l5 respectively.
+ */
.text
.align 32
+etrap_priv: or %g1, %g3, %g1 ! IEU0 Group
+ rd %fprs, %g3 ! Single Group+4bubbles
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU0 Group
+ andcc %g3, FPRS_FEF, %g0 ! IEU1
+ add %g2, REGWIN_SZ + TRACEREG_SZ - FPUREG_SZ, %g3 ! IEU0 Group
+ be,pt %icc, 1f ! CTI
+ andcc %g1, TSTATE_PRIV, %g0 ! IEU1
+ andn %g3, (64 - 1), %g3 ! IEU0 Group
+ ba,pt %xcc, 1f ! CTI
+ sub %g3, REGWIN_SZ + TRACEREG_SZ, %g2 ! IEU0 Group
+
+ .align 32
.globl etrap, etrap_irq, etraptl1
-etrap: rdpr %pil, %g2
-etrap_irq: rdpr %tstate, %g1
- sllx %g2, 20, %g2
- or %g1, %g2, %g1
- andcc %g1, TSTATE_PRIV, %g0
- bne,pn %xcc, etrap_maybe_fpu
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
- sethi %hi(TASK_REGOFF), %g2
-
- or %g2, %lo(TASK_REGOFF), %g2
- add %g6, %g2, %g2
-etrap_maybe_fpu:rd %fprs, %g3
- brnz,pn %g3, etrap_save_fpu
- st %g0, [%g2 + REGWIN_SZ + PT_V9_FPRS]
-etrap_after_fpu:rdpr %tpc, %g3
- stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]
- rdpr %tnpc, %g1
-
- stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC]
- rd %y, %g3
- stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]
- st %g3, [%g2 + REGWIN_SZ + PT_V9_Y]
- save %g2, -STACK_BIAS, %sp ! The ordering here is
- rdpr %pstate, %g1 ! critical, see winfixup
- bne,pn %xcc, 2f
- rdpr %canrestore, %g3
-
- rdpr %wstate, %g2
- wrpr %g0, 7, %cleanwin
- wrpr %g0, 0, %canrestore
- sll %g2, 3, %g2
- wrpr %g3, 0, %otherwin
- wrpr %g2, 0, %wstate
- wr %g0, ASI_DMMU, %asi
- ldxa [%g0 + PRIMARY_CONTEXT] %asi, %g2
-
- stxa %g0, [%g0 + PRIMARY_CONTEXT] %asi
- stxa %g2, [%g0 + SECONDARY_CONTEXT] %asi
- flush %g6
-2: wrpr %g0, 0x0, %tl
- or %g1, 0, %l1
- add %g4, 0, %l4
- or %g5, 0, %l5
- add %g7, 0, %l2
-
- or %g6, 0, %l6
- wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate
- stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
- stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]
- stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]
- stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]
- stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]
-
- stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]
- stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
- stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
- stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
- stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]
- stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]
- sethi %uhi(PAGE_OFFSET), %g4
- stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]
-
- stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]
- sllx %g4, 32, %g4
- stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
- wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate
- jmpl %l2 + 0x4, %g0
- mov %l6, %g6
-etrap_save_fpu: and %g3, FPRS_FEF, %g3
- brz,pn %g3, 2f
-
- nop
- be,a,pt %xcc, 3f
- add %g2, (TRACEREG_SZ + REGWIN_SZ), %g2
- wr %g0, ASI_BLK_P, %asi
- add %g2, ((TRACEREG_SZ+REGWIN_SZ)-FPUREG_SZ), %g2
- andn %g2, (64 - 1), %g2
-1: st %g3, [%g2 - 0x4 /*REGWIN_SZ + PT_V9_FPRS*/]
- rd %gsr, %g3
-
- stx %fsr, [%g2 + 0x100]
- stx %g3, [%g2 + 0x108]
- membar #StoreStore | #LoadStore
- stda %f0, [%g2 + 0x000] %asi
- stda %f16, [%g2 + 0x040] %asi
- stda %f32, [%g2 + 0x080] %asi
- stda %f48, [%g2 + 0x0c0] %asi
- membar #Sync
-
- sub %g2, (TRACEREG_SZ + REGWIN_SZ), %g2
-2: b,pt %xcc, etrap_after_fpu
- wr %g0, 0, %fprs
-3: /* Because Ultra lacks ASI_BLK_NUCLEUS a hack has to take place. */
- mov SECONDARY_CONTEXT, %g3
- stxa %g0, [%g3] ASI_DMMU
- flush %g2
- wr %g0, ASI_BLK_S, %asi
- nop
+etrap: rdpr %pil, %g2 ! Single Group
+etrap_irq: rdpr %tstate, %g1 ! Single Group
+ sllx %g2, 20, %g3 ! IEU0 Group
+ andcc %g1, TSTATE_PRIV, %g0 ! IEU1
+ bne,pn %xcc, etrap_priv ! CTI
+ sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group
+ or %g1, %g3, %g1 ! IEU1
+ or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group
+ add %g6, %g2, %g2 ! IEU0 Group
+1: rdpr %tpc, %g3 ! Single Group
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group
+ rdpr %tnpc, %g1 ! Single Group
+ stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] ! Store Group
+ rd %y, %g3 ! Single Group+4bubbles
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] ! Store Group
+ st %g3, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group
+ save %g2, -STACK_BIAS, %sp ! The ordering here is ! Single Group
+ rdpr %pstate, %g1 ! critical, see winfixup ! Single Group+9bubbles
+ bne,pn %xcc, 2f ! CTI Group
+ sethi %hi(TSTATE_PEF), %l2 ! IEU0
+ mov PRIMARY_CONTEXT, %l4 ! IEU1
+ rdpr %canrestore, %g3 ! Single Group+4bubbles
+ rdpr %wstate, %g2 ! Single Group+4bubbles
+ wrpr %g0, 7, %cleanwin ! Single Group+4bubbles
+ wrpr %g0, 0, %canrestore ! Single Group+4bubbles
+ sll %g2, 3, %g2 ! IEU0 Group
+ mov SECONDARY_CONTEXT, %l5 ! IEU1
+ wrpr %g3, 0, %otherwin ! Single Group+4bubbles
+ wrpr %g2, 0, %wstate ! Single Group+4bubbles
+ rdpr %tstate, %l3 ! Single Group
+ ldxa [%l4] ASI_DMMU, %g2 ! Load Group
+ stxa %g0, [%l4] ASI_DMMU ! Store Group
+ stxa %g2, [%l5] ASI_DMMU ! Store Group
+ flush %g6 ! Single Group+9bubbles
+ andcc %l3, %l2, %g0 ! IEU1 Group
+ be,a,pt %icc, 6f ! CTI
+ st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
+ rd %fprs, %l0 ! Single Group+4bubbles
+ andcc %l0, FPRS_FEF, %g0 ! IEU1 Group
+ be,pn %icc, 6f ! CTI
+ st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
+ ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group
+ stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group
+ or %l4, %l0, %l4 ! IEU0 Group
+ ba,pt %xcc, 3f ! CTI
+ st %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store
+2: rd %fprs, %l0 ! Single Group+4bubbles
+ andcc %l0, FPRS_FEF, %g0 ! IEU1 Group
+ be,pn %icc, 6f ! CTI
+ st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
+ stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group
+3: rd %gsr, %l7 ! Single Group+4bubbles
+ cmp %l0, FPRS_FEF ! IEU1 Group
+ be,pn %icc, 6f ! CTI
+ stx %l7, [%sp + FPU_OFF + 0x108] ! Store
+ wr %g0, ASI_BLK_P, %asi ! Singe Group+4bubbles
+ andcc %l0, FPRS_DL, %g0 ! IEU1 Group
+ be,pn %icc, 4f ! CTI
+ membar #StoreStore | #LoadStore ! Memory
+ stda %f0, [%sp + FPU_OFF + 0x000] %asi ! Store Group
+ stda %f16, [%sp + FPU_OFF + 0x040] %asi ! Store Group
+ andcc %l0, FPRS_DU, %g0 ! IEU1
+ be,pn %icc, 5f ! CTI
+ nop ! IEU0 Group
+4: stda %f32, [%sp + FPU_OFF + 0x080] %asi ! Store Group
+ stda %f48, [%sp + FPU_OFF + 0x0c0] %asi ! Store Group
+5: membar #Sync ! Memory
+6: wr %g0, 0x0, %fprs ! Single Group+4bubbles
+ wrpr %g0, 0x0, %tl ! Single Group+4bubbles
+ mov %g1, %l1 ! IEU0 Group
+ mov %g4, %l4 ! IEU1
+ mov %g5, %l5 ! IEU0 Group
+ mov %g7, %l2 ! IEU1
+ mov %g6, %l6 ! IEU0 Group
+ wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
+ stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group
+ stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] ! Store Group
+ stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] ! Store Group
+ stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] ! Store Group
+ stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] ! Store Group
+ stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] ! Store Group
+ stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ! Store Group
+ stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] ! Store Group
+ stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] ! Store Group
+ stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] ! Store Group
+ stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] ! Store Group
+ sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
+ stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] ! Store Group
+ stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] ! Store Group
+ sllx %g4, 32, %g4 ! IEU0
+ stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] ! Store Group
+ wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
+ jmpl %l2 + 0x4, %g0 ! CTI Group
+ mov %l6, %g6 ! IEU0
- b,pt %xcc, 1b
- mov FPRS_FEF, %g3
- nop
-etraptl1: rdpr %tstate, %g1
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
- ba,pt %xcc, etrap_maybe_fpu
- andcc %g1, TSTATE_PRIV, %g0
- nop
+etraptl1: rdpr %tstate, %g1 ! Single Group+4bubbles
+ ba,pt %xcc, etrap_priv ! CTI Group
+ clr %g3 ! IEU0
#undef TASK_REGOFF
#undef FPUREG_SZ
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 0ed975aff..43f950b25 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.43 1997/07/07 03:05:25 davem Exp $
+/* $Id: head.S,v 1.46 1997/08/08 08:33:30 jj Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -21,6 +21,7 @@
#include <asm/processor.h>
#include <asm/lsu.h>
#include <asm/head.h>
+#include <asm/ttable.h>
/* This section from from _start to sparc64_boot_end should fit into
* 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
@@ -89,6 +90,28 @@ sparc64_boot:
*/
wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
+#ifdef __SMP__
+ /* Ugly but necessary... */
+ sethi %hi(KERNBASE), %g7
+ sethi %hi(sparc64_cpu_startup), %g5
+ or %g5, %lo(sparc64_cpu_startup), %g5
+ sub %g5, %g7, %g5
+ sethi %hi(sparc64_cpu_startup_end), %g6
+ or %g6, %lo(sparc64_cpu_startup_end), %g6
+ sub %g6, %g7, %g6
+ sethi %hi(smp_trampoline), %g3
+ or %g3, %lo(smp_trampoline), %g3
+ sub %g3, %g7, %g3
+1: ldx [%g5], %g1
+ stx %g1, [%g3]
+ membar #StoreStore
+ flush %g3
+ add %g5, 8, %g5
+ cmp %g5, %g6
+ blu,pt %xcc, 1b
+ add %g3, 8, %g3
+#endif
+
create_mappings:
/* %g5 holds the tlb data */
sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
@@ -340,7 +363,7 @@ setup_tba:
mov 0x40, %g2 /* INTR data 0 register */
/* Ok, we're done setting up all the state our trap mechanims needs,
- * now get back into normal globals and let the PROM know what it up.
+ * now get back into normal globals and let the PROM know what is up.
*/
wrpr %g0, %g0, %wstate
wrpr %o1, PSTATE_IE, %pstate
@@ -374,6 +397,7 @@ bootup_kernel_stack:
! 0x0000000000408000
#include "ttable.S"
+#include "systbls.S"
#include "etrap.S"
#include "rtrap.S"
#include "winfixup.S"
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 81eb45e42..af88ca4b6 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
+/* $Id: ioctl32.c,v 1.18 1997/09/06 02:25:13 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -23,6 +23,7 @@
#include <linux/vt.h>
#include <linux/fs.h>
#include <linux/fd.h>
+#include <linux/if_ppp.h>
#include <asm/types.h>
#include <asm/uaccess.h>
@@ -102,6 +103,7 @@ static inline int dev_ifconf(unsigned int fd, u32 arg)
if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32)))
return -EFAULT;
+
ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq);
ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
if (!ifc.ifc_buf) return -ENOMEM;
@@ -145,7 +147,8 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
unsigned long old_fs;
int err;
- if (cmd == SIOCSIFMAP) {
+ switch (cmd) {
+ case SIOCSIFMAP:
if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(ifr.ifr_name)) ||
__get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
__get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) ||
@@ -154,9 +157,20 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
__get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) ||
__get_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port)))
return -EFAULT;
- } else {
+ break;
+ case SIOCGPPPSTATS:
+ case SIOCGPPPCSTATS:
+ case SIOCGPPPVER:
+ if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32)))
+ return -EFAULT;
+ ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+ if (!ifr.ifr_data)
+ return -EAGAIN;
+ break;
+ default:
if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32)))
return -EFAULT;
+ break;
}
old_fs = get_fs();
set_fs (KERNEL_DS);
@@ -177,6 +191,25 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(struct ifreq32)))
return -EFAULT;
break;
+ case SIOCGPPPSTATS:
+ case SIOCGPPPCSTATS:
+ case SIOCGPPPVER:
+ {
+ u32 data;
+ int len;
+
+ __get_user(data, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_data));
+ if(cmd == SIOCGPPPVER)
+ len = strlen(PPP_VERSION) + 1;
+ else if(cmd == SIOCGPPPCSTATS)
+ len = sizeof(struct ppp_comp_stats);
+ else
+ len = sizeof(struct ppp_stats);
+
+ if (copy_to_user((char *)A(data), ifr.ifr_data, len))
+ return -EFAULT;
+ break;
+ }
case SIOCGIFMAP:
if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(ifr.ifr_name)) ||
__put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
@@ -481,6 +514,74 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg)
return ret;
}
+static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ unsigned long old_fs = get_fs();
+ unsigned long kval;
+ unsigned int *uvp;
+ int error;
+
+ set_fs(KERNEL_DS);
+ error = sys_ioctl(fd, cmd, (long)&kval);
+ set_fs(old_fs);
+
+ if(error == 0) {
+ uvp = (unsigned int *)A(arg);
+ if(put_user(kval, uvp))
+ error = -EFAULT;
+ }
+ return error;
+}
+
+struct ppp_option_data32 {
+ __kernel_caddr_t32 ptr;
+ __u32 length;
+ int transmit;
+};
+#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32)
+
+static int ppp_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ unsigned long old_fs = get_fs();
+ struct ppp_option_data32 data32;
+ struct ppp_option_data data;
+ int err;
+
+ switch (cmd) {
+ case PPPIOCSCOMPRESS32:
+ if (copy_from_user(&data32, (struct ppp_option_data32 *)A(arg), sizeof(struct ppp_option_data32)))
+ return -EFAULT;
+ data.ptr = kmalloc (data32.length, GFP_KERNEL);
+ if (!data.ptr)
+ return -ENOMEM;
+ if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) {
+ err = -EFAULT;
+ goto out;
+ }
+ data.length = data32.length;
+ data.transmit = data32.transmit;
+ break;
+ default:
+ printk("ppp_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
+ (int)fd, (unsigned int)cmd, (unsigned int)arg);
+ return -EINVAL;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, cmd, (unsigned long)&data);
+ set_fs (old_fs);
+ if (err)
+ goto out;
+ switch (cmd) {
+ case PPPIOCSCOMPRESS32:
+ default:
+ break;
+ }
+out:
+ kfree(data.ptr);
+ return err;
+}
+
asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
{
struct file * filp;
@@ -527,6 +628,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case SIOCSIFDSTADDR:
case SIOCGIFNETMASK:
case SIOCSIFNETMASK:
+ case SIOCGPPPSTATS:
+ case SIOCGPPPCSTATS:
+ case SIOCGPPPVER:
error = dev_ifsioc(fd, cmd, arg);
goto out;
@@ -557,6 +661,16 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
error = fbiogscursor(fd, cmd, arg);
goto out;
+ case HDIO_GET_KEEPSETTINGS:
+ case HDIO_GET_UNMASKINTR:
+ case HDIO_GET_DMA:
+ case HDIO_GET_32BIT:
+ case HDIO_GET_MULTCOUNT:
+ case HDIO_GET_NOWERR:
+ case HDIO_GET_NICE:
+ error = hdio_ioctl_trans(fd, cmd, arg);
+ goto out;
+
/* List here exlicitly which ioctl's are known to have
* compatable types passed or none at all...
*/
@@ -619,6 +733,23 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case FIBMAP:
case FIGETBSZ:
+ /* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
+ * Some need translations, these do not.
+ */
+ case HDIO_GET_IDENTITY:
+ case HDIO_SET_DMA:
+ case HDIO_SET_KEEPSETTINGS:
+ case HDIO_SET_UNMASKINTR:
+ case HDIO_SET_NOWERR:
+ case HDIO_SET_32BIT:
+ case HDIO_SET_MULTCOUNT:
+ case HDIO_DRIVE_CMD:
+ case HDIO_SET_PIO_MODE:
+ case HDIO_SCAN_HWIF:
+ case HDIO_SET_NICE:
+ case BLKROSET:
+ case BLKROGET:
+
/* 0x02 -- Floppy ioctls */
case FDSETEMSGTRESH:
case FDFLUSH:
@@ -729,11 +860,40 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case SIOCSARP:
case SIOCGARP:
case SIOCDARP:
+ case OLD_SIOCSARP:
+ case OLD_SIOCGARP:
+ case OLD_SIOCDARP:
+ case SIOCSRARP:
+ case SIOCGRARP:
+ case SIOCDRARP:
case SIOCADDDLCI:
case SIOCDELDLCI:
+
+ /* PPP stuff */
+ case PPPIOCGFLAGS:
+ case PPPIOCSFLAGS:
+ case PPPIOCGASYNCMAP:
+ case PPPIOCSASYNCMAP:
+ case PPPIOCGUNIT:
+ case PPPIOCGRASYNCMAP:
+ case PPPIOCSRASYNCMAP:
+ case PPPIOCGMRU:
+ case PPPIOCSMRU:
+ case PPPIOCSMAXCID:
+ case PPPIOCGXASYNCMAP:
+ case PPPIOCSXASYNCMAP:
+ case PPPIOCXFERUNIT:
+ case PPPIOCGNPMODE:
+ case PPPIOCSNPMODE:
+ case PPPIOCGDEBUG:
+ case PPPIOCSDEBUG:
+ case PPPIOCGIDLE:
error = sys_ioctl (fd, cmd, (unsigned long)arg);
goto out;
- break;
+
+ case PPPIOCSCOMPRESS32:
+ error = ppp_ioctl (fd, cmd, (unsigned long)arg);
+ goto out;
default:
printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
diff --git a/arch/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c
index 7d1580b39..7ae12df11 100644
--- a/arch/sparc64/kernel/ioport.c
+++ b/arch/sparc64/kernel/ioport.c
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
+/* $Id: ioport.c,v 1.13 1997/08/18 01:20:22 davem Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -45,7 +45,7 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
u32 bus_type, int rdonly)
{
unsigned long vaddr, base_address;
- unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32);
+ unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32);
unsigned long offset = (addr & (~PAGE_MASK));
if (virtual) {
@@ -64,7 +64,12 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
/* Tell Linux resource manager about the mapping */
request_region ((vaddr | offset), len, name);
} else {
- return __va(addr);
+ unsigned long vaddr = (unsigned long) __va(addr);
+
+ if(!check_region(vaddr, len))
+ request_region(vaddr, len, name);
+
+ return (void *) vaddr;
}
base_address = vaddr;
@@ -83,11 +88,11 @@ void sparc_free_io (void *virtual, int len)
unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
+ release_region(vaddr, plen);
+
if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL)
return;
- release_region(vaddr, plen);
-
for (; plen != 0;) {
plen -= PAGE_SIZE;
unmapioaddr(vaddr + plen);
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index f76c27c57..6f4c9dfdf 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
+/* $Id: irq.c,v 1.39 1997/08/31 03:11:18 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -28,8 +28,18 @@
#include <asm/hardirq.h>
#include <asm/softirq.h>
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#include <asm/pbm.h>
+#endif
+
/* Internal flag, should not be visible elsewhere at all. */
-#define SA_SYSIO_MASKED 0x100
+#define SA_IMAP_MASKED 0x100
+
+#ifdef __SMP__
+void distribute_irqs(void);
+static int irqs_have_been_distributed = 0;
+#endif
/* UPA nodes send interrupt packet to UltraSparc with first data reg value
* low 5 bits holding the IRQ identifier being delivered. We must translate
@@ -37,10 +47,39 @@
* make things even more swift we store the complete mask here.
*/
-#define NUM_IVECS 2048 /* XXX may need more on sunfire/wildfire */
+#define NUM_HARD_IVECS 2048
+#define NUM_IVECS (NUM_HARD_IVECS + 64) /* For SMP IRQ distribution alg. */
unsigned long ivector_to_mask[NUM_IVECS];
+struct ino_bucket {
+ struct ino_bucket *next;
+ unsigned int ino;
+ unsigned int *imap;
+ unsigned int *iclr;
+};
+
+#define INO_HASHSZ (NUM_HARD_IVECS >> 2)
+#define NUM_INO_STATIC 4
+static struct ino_bucket *ino_hash[INO_HASHSZ] = { NULL, };
+static struct ino_bucket static_ino_buckets[NUM_INO_STATIC];
+static int static_ino_bucket_count = 0;
+
+static inline struct ino_bucket *__ino_lookup(unsigned int hash, unsigned int ino)
+{
+ struct ino_bucket *ret = ino_hash[hash];
+
+ for(ret = ino_hash[hash]; ret && ret->ino != ino; ret = ret->next)
+ ;
+
+ return ret;
+}
+
+static inline struct ino_bucket *ino_lookup(unsigned int ino)
+{
+ return __ino_lookup((ino & (INO_HASHSZ - 1)), ino);
+}
+
/* This is based upon code in the 32-bit Sparc kernel written mostly by
* David Redman (djhr@tadpole.co.uk).
*/
@@ -73,15 +112,22 @@ int get_irq_list(char *buf)
}
len += sprintf(buf + len, "\n");
}
+#if 0
+#ifdef CONFIG_PCI
+ len += sprintf(buf + len, "ISTAT: PCI[%016lx] OBIO[%016lx]\n",
+ psycho_root->psycho_regs->pci_istate,
+ psycho_root->psycho_regs->obio_istate);
+#endif
+#endif
return len;
}
-/* INO number to Sparc PIL level. */
-unsigned char ino_to_pil[] = {
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 0 */
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 1 */
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 2 */
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 3 */
+/* SBUS SYSIO INO number to Sparc PIL level. */
+unsigned char sysio_ino_to_pil[] = {
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */
3, /* Onboard SCSI */
5, /* Onboard Ethernet */
/*XXX*/ 8, /* Onboard BPP */
@@ -112,7 +158,7 @@ unsigned char ino_to_pil[] = {
*/
#define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x)))
#define bogon ((unsigned long) -1)
-static unsigned long irq_offsets[] = {
+static unsigned long sysio_irq_offsets[] = {
/* SBUS Slot 0 --> 3, level 1 --> 7 */
offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
@@ -134,29 +180,29 @@ offset(imap_pmgmt),
#undef bogon
-#define NUM_IRQ_ENTRIES (sizeof(irq_offsets) / sizeof(irq_offsets[0]))
+#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
-/* Convert an "interrupts" property IRQ level to an SBUS/SYSIO
- * Interrupt Mapping register pointer, or NULL if none exists.
+/* XXX Old compatability cruft, get rid of me when all drivers have been
+ * XXX converted to dcookie registry calls... -DaveM
*/
-static unsigned int *irq_to_imap(unsigned int irq)
+static unsigned int *sysio_irq_to_imap(unsigned int irq)
{
unsigned long offset;
struct sysio_regs *sregs;
if((irq == 14) ||
- (irq >= NUM_IRQ_ENTRIES) ||
- ((offset = irq_offsets[irq]) == ((unsigned long)-1)))
+ (irq >= NUM_SYSIO_OFFSETS) ||
+ ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1)))
return NULL;
sregs = SBus_chain->iommu->sysio_regs;
offset += ((unsigned long) sregs);
- return ((unsigned int *)offset) + 1;
+ return ((unsigned int *)offset);
}
/* Convert Interrupt Mapping register pointer to assosciated
- * Interrupt Clear register pointer.
+ * Interrupt Clear register pointer, SYSIO specific version.
*/
-static unsigned int *imap_to_iclr(unsigned int *imap)
+static unsigned int *sysio_imap_to_iclr(unsigned int *imap)
{
unsigned long diff;
@@ -166,32 +212,68 @@ static unsigned int *imap_to_iclr(unsigned int *imap)
#undef offset
-/* For non-SBUS IRQ's we do nothing, else we must enable them in the
- * appropriate SYSIO interrupt map registers.
+#ifdef CONFIG_PCI
+/* PCI PSYCHO INO number to Sparc PIL level. */
+unsigned char psycho_ino_to_pil[] = {
+ 7, 5, 5, 2, /* PCI A slot 0 Int A, B, C, D */
+ 7, 5, 5, 2, /* PCI A slot 1 Int A, B, C, D */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 6, 4, 3, 1, /* PCI B slot 0 Int A, B, C, D */
+ 6, 4, 3, 1, /* PCI B slot 1 Int A, B, C, D */
+ 6, 4, 3, 1, /* PCI B slot 2 Int A, B, C, D */
+ 6, 4, 3, 1, /* PCI B slot 3 Int A, B, C, D */
+ 3, /* SCSI */
+ 5, /* Ethernet */
+ 8, /* Parallel Port */
+ 13, /* Audio Record */
+ 14, /* Audio Playback */
+ 15, /* PowerFail */
+ 12, /* Keyboard/Mouse/Serial */
+ 11, /* Floppy */
+ 2, /* Spare Hardware */
+ 12, /* Keyboard */
+ 4, /* Mouse */
+ 12, /* Serial */
+ 10, /* Timer 0 */
+ 11, /* Timer 1 */
+ 15, /* Uncorrectable ECC */
+ 15, /* Correctable ECC */
+ 15, /* PCI Bus A Error */
+ 15, /* PCI Bus B Error */
+ 1, /* Power Management */
+};
+
+/* INO number to IMAP register offset for PSYCHO external IRQ's.
*/
-void enable_irq(unsigned int irq)
+#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x)))
+
+#define psycho_imap_offset(ino) \
+ ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \
+ (psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1)))
+
+#define psycho_iclr_offset(ino) \
+ ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \
+ (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f) << 3)))
+
+#endif
+
+/* Now these are always passed a true fully specified sun4u INO. */
+void enable_irq(unsigned int ino)
{
+ struct ino_bucket *bucket;
unsigned long tid;
unsigned int *imap;
- /* If this is for the tick interrupt, just ignore, note
- * that this is the one and only locally generated interrupt
- * source, all others come from external sources (essentially
- * any UPA device which is an interruptor). (actually, on
- * second thought Ultra can generate local interrupts for
- * async memory errors and we may setup handlers for those
- * at some point as well)
- *
- * XXX See commentary below in request_irq() this assumption
- * XXX is broken and needs to be fixed.
- */
- if(irq == 14)
+#ifdef CONFIG_PCI
+ if(PCI_IRQ_P(ino))
+ ino &= (PCI_IRQ_IGN | PCI_IRQ_INO);
+#endif
+ bucket = ino_lookup(ino);
+ if(!bucket)
return;
- /* Check for bogons. */
- imap = irq_to_imap(irq);
- if(imap == NULL)
- goto do_the_stb_watoosi;
+ imap = bucket->imap;
/* We send it to our UPA MID, for SMP this will be different. */
__asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
@@ -202,28 +284,27 @@ void enable_irq(unsigned int irq)
* Register, the hardware just mirrors that value here.
* However for Graphics and UPA Slave devices the full
* SYSIO_IMAP_INR field can be set by the programmer here.
- * (XXX we will have to handle those for FFB etc. XXX)
+ *
+ * Things like FFB can now be handled via the dcookie mechanism.
*/
*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
- return;
-
-do_the_stb_watoosi:
- printk("Cannot enable irq(%d), doing the \"STB Watoosi\" instead.", irq);
- panic("Trying to enable bogon IRQ");
}
-void disable_irq(unsigned int irq)
+/* This now gets passed true ino's as well. */
+void disable_irq(unsigned int ino)
{
+ struct ino_bucket *bucket;
unsigned int *imap;
- /* XXX Grrr, I know this is broken... */
- if(irq == 14)
+#ifdef CONFIG_PCI
+ if(PCI_IRQ_P(ino))
+ ino &= (PCI_IRQ_IGN | PCI_IRQ_INO);
+#endif
+ bucket = ino_lookup(ino);
+ if(!bucket)
return;
- /* Check for bogons. */
- imap = irq_to_imap(irq);
- if(imap == NULL)
- goto do_the_stb_watoosi;
+ imap = bucket->imap;
/* NOTE: We do not want to futz with the IRQ clear registers
* and move the state to IDLE, the SCSI code does call
@@ -231,34 +312,254 @@ void disable_irq(unsigned int irq)
* SCSI adapter driver code. Thus we'd lose interrupts.
*/
*imap &= ~(SYSIO_IMAP_VALID);
- return;
+}
+
+static void get_irq_translations(int *cpu_irq, int *ivindex_fixup,
+ unsigned int **imap, unsigned int **iclr,
+ void *busp, unsigned long flags,
+ unsigned int irq)
+{
+ if(*cpu_irq != -1 && *imap != NULL && *iclr != NULL)
+ return;
+
+ if(*cpu_irq != -1 || *imap != NULL || *iclr != NULL || busp == NULL) {
+ printk("get_irq_translations: Partial specification, this is bad.\n");
+ printk("get_irq_translations: cpu_irq[%d] imap[%p] iclr[%p] busp[%p]\n",
+ *cpu_irq, *imap, *iclr, busp);
+ panic("Bad IRQ translations...");
+ }
+
+ if(SA_BUS(flags) == SA_SBUS) {
+ struct linux_sbus *sbusp = busp;
+ struct sysio_regs *sregs = sbusp->iommu->sysio_regs;
+ unsigned long offset;
-do_the_stb_watoosi:
- printk("Cannot disable irq(%d), doing the \"STB Watoosi\" instead.", irq);
- panic("Trying to enable bogon IRQ");
+ *cpu_irq = sysio_ino_to_pil[irq];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: Bad SYSIO INO[%x]\n", irq);
+ panic("Bad SYSIO IRQ translations...");
+ }
+ offset = sysio_irq_offsets[irq];
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
+ irq, *cpu_irq);
+ panic("BAD SYSIO IRQ offset...");
+ }
+ offset += ((unsigned long)sregs);
+ *imap = ((unsigned int *)offset);
+
+ /* SYSIO inconsistancy. For external SLOTS, we have to select
+ * the right ICLR register based upon the lower SBUS irq level
+ * bits.
+ */
+ if(irq >= 0x20) {
+ *iclr = sysio_imap_to_iclr(*imap);
+ } else {
+ unsigned long iclraddr;
+ int sbus_slot = (irq & 0x18)>>3;
+ int sbus_level = irq & 0x7;
+
+ switch(sbus_slot) {
+ case 0:
+ *iclr = &sregs->iclr_slot0;
+ break;
+ case 1:
+ *iclr = &sregs->iclr_slot1;
+ break;
+ case 2:
+ *iclr = &sregs->iclr_slot2;
+ break;
+ case 3:
+ *iclr = &sregs->iclr_slot3;
+ break;
+ };
+
+ iclraddr = (unsigned long) *iclr;
+ iclraddr += ((sbus_level - 1) * 8);
+ *iclr = (unsigned int *) iclraddr;
+
+#if 0 /* DEBUGGING */
+ printk("SYSIO_FIXUP: slot[%x] level[%x] iclr[%p] ",
+ sbus_slot, sbus_level, *iclr);
+#endif
+
+ /* Also, make sure this is accounted for in ivindex
+ * computations done by the caller.
+ */
+ *ivindex_fixup = sbus_level;
+ }
+ return;
+ }
+#ifdef CONFIG_PCI
+ if(SA_BUS(flags) == SA_PCI) {
+ struct pci_bus *pbusp = busp;
+ struct linux_pbm_info *pbm = pbusp->sysdata;
+ struct psycho_regs *pregs = pbm->parent->psycho_regs;
+ unsigned long offset;
+
+ *cpu_irq = psycho_ino_to_pil[irq & 0x3f];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: Bad PSYCHO INO[%x]\n", irq);
+ panic("Bad PSYCHO IRQ translations...");
+ }
+ offset = psycho_imap_offset(irq);
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad PSYCHO INO[%x] cpu[%d]\n",
+ irq, *cpu_irq);
+ panic("Bad PSYCHO IRQ offset...");
+ }
+ offset += ((unsigned long)pregs);
+ *imap = ((unsigned int *)offset) + 1;
+ *iclr = (unsigned int *)
+ (((unsigned long)pregs) + psycho_imap_offset(irq));
+ return;
+ }
+#endif
+#if 0 /* XXX More to do before we can use this. -DaveM */
+ if(SA_BUS(flags) == SA_FHC) {
+ struct fhc_bus *fbusp = busp;
+ struct fhc_regs *fregs = fbusp->regs;
+ unsigned long offset;
+
+ *cpu_irq = fhc_ino_to_pil[irq];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: Bad FHC INO[%x]\n", irq);
+ panic("Bad FHC IRQ translations...");
+ }
+ offset = fhc_irq_offset[*cpu_irq];
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad FHC INO[%x] cpu[%d]\n",
+ irq, *cpu_irq);
+ panic("Bad FHC IRQ offset...");
+ }
+ offset += ((unsigned long)pregs);
+ *imap = (((unsigned int *)offset)+1);
+ *iclr = fhc_imap_to_iclr(*imap);
+ return;
+ }
+#endif
+ printk("get_irq_translations: IRQ register for unknown bus type.\n");
+ printk("get_irq_translations: BUS[%lx] IRQ[%x]\n",
+ SA_BUS(flags), irq);
+ panic("Bad IRQ bus type...");
+}
+
+#ifdef CONFIG_PCI
+static void pci_irq_frobnicate(int *cpu_irq, int *ivindex_fixup,
+ unsigned int **imap, unsigned int **iclr,
+ unsigned int irq)
+{
+ struct linux_psycho *psycho = psycho_root;
+ struct psycho_regs *pregs = psycho->psycho_regs;
+ unsigned long addr, imoff;
+
+ addr = (unsigned long) &pregs->imap_a_slot0;
+ imoff = (irq & PCI_IRQ_IMAP_OFF) >> PCI_IRQ_IMAP_OFF_SHFT;
+ addr = addr + imoff;
+
+ *imap = ((unsigned int *)addr) + 1;
+
+ addr = (unsigned long) pregs;
+ addr += psycho_iclr_offset(irq & (PCI_IRQ_INO));
+ *iclr = ((unsigned int *)addr) + 1;
+
+ *cpu_irq = psycho_ino_to_pil[irq & (PCI_IRQ_INO)];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: BAD PSYCHO INO[%x]\n", irq);
+ panic("Bad PSYCHO IRQ frobnication...");
+ }
+
+ /* IVINDEX fixup only needed for PCI slot irq lines. */
+ if(!(irq & 0x20))
+ *ivindex_fixup = irq & 0x03;
+}
+#endif
+
+/* Once added, they are never removed. */
+static struct ino_bucket *add_ino_hash(unsigned int ivindex,
+ unsigned int *imap, unsigned int *iclr,
+ unsigned long flags)
+{
+ struct ino_bucket *new = NULL, **hashp;
+ unsigned int hash = (ivindex & (INO_HASHSZ - 1));
+
+ new = __ino_lookup(hash, ivindex);
+ if(new)
+ return new;
+ if(flags & SA_STATIC_ALLOC) {
+ if(static_ino_bucket_count < NUM_INO_STATIC)
+ new = &static_ino_buckets[static_ino_bucket_count++];
+ else
+ printk("Request for ino bucket SA_STATIC_ALLOC failed "
+ "using kmalloc\n");
+ }
+ if(new == NULL)
+ new = kmalloc(sizeof(struct ino_bucket), GFP_KERNEL);
+ if(new) {
+ hashp = &ino_hash[hash];
+ new->imap = imap;
+ new->iclr = iclr;
+ new->ino = ivindex;
+ new->next = *hashp;
+ *hashp = new;
+ }
+ return new;
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char *name, void *dev_cookie)
+ unsigned long irqflags, const char *name, void *dev_id)
{
struct irqaction *action, *tmp = NULL;
+ struct devid_cookie *dcookie = NULL;
+ struct ino_bucket *bucket = NULL;
unsigned long flags;
- unsigned int cpu_irq, *imap, *iclr;
+ unsigned int *imap, *iclr;
+ void *bus_id = NULL;
+ int ivindex, ivindex_fixup, cpu_irq = -1;
- /* XXX This really is not the way to do it, the "right way"
- * XXX is to have drivers set SA_SBUS or something like that
- * XXX in irqflags and we base our decision here on whether
- * XXX that flag bit is set or not.
- */
- if(irq == 14)
- cpu_irq = irq;
- else
- cpu_irq = ino_to_pil[irq];
-
if(!handler)
return -EINVAL;
- imap = irq_to_imap(irq);
+ imap = iclr = NULL;
+
+ ivindex_fixup = 0;
+#ifdef CONFIG_PCI
+ if(PCI_IRQ_P(irq)) {
+ pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
+ } else
+#endif
+ if(irqflags & SA_DCOOKIE) {
+ if(!dev_id) {
+ printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
+ panic("Bogus irq registry.");
+ }
+ dcookie = dev_id;
+ dev_id = dcookie->real_dev_id;
+ cpu_irq = dcookie->pil;
+ imap = dcookie->imap;
+ iclr = dcookie->iclr;
+ bus_id = dcookie->bus_cookie;
+ get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
+ &iclr, bus_id, irqflags, irq);
+ } else {
+ /* XXX NOTE: This code is maintained for compatability until I can
+ * XXX verify that all drivers sparc64 will use are updated
+ * XXX to use the new IRQ registry dcookie interface. -DaveM
+ */
+ if(irq == 14)
+ cpu_irq = irq;
+ else
+ cpu_irq = sysio_ino_to_pil[irq];
+ imap = sysio_irq_to_imap(irq);
+ if(!imap) {
+ printk("request_irq: BAD, null imap for old style "
+ "irq registry IRQ[%x].\n", irq);
+ panic("Bad IRQ registery...");
+ }
+ iclr = sysio_imap_to_iclr(imap);
+ }
+ ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+ ivindex += ivindex_fixup;
action = *(cpu_irq + irq_action);
if(action) {
@@ -297,52 +598,67 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
return -ENOMEM;
}
- if(imap) {
- int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+ bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
+ if(!bucket) {
+ kfree(action);
+ restore_flags(flags);
+ return -ENOMEM;
+ }
- ivector_to_mask[ivindex] = (1<<cpu_irq);
- iclr = imap_to_iclr(imap);
- action->mask = (unsigned long) iclr;
- irqflags |= SA_SYSIO_MASKED;
- } else {
- action->mask = 0;
+ ivector_to_mask[ivindex] = (1 << cpu_irq);
+
+ if(dcookie) {
+ dcookie->ret_ino = ivindex;
+ dcookie->ret_pil = cpu_irq;
}
+ action->mask = (unsigned long) bucket;
action->handler = handler;
- action->flags = irqflags;
+ action->flags = irqflags | SA_IMAP_MASKED;
action->name = name;
action->next = NULL;
- action->dev_id = dev_cookie;
+ action->dev_id = dev_id;
if(tmp)
tmp->next = action;
else
*(cpu_irq + irq_action) = action;
- enable_irq(irq);
+ enable_irq(ivindex);
restore_flags(flags);
+#ifdef __SMP__
+ if(irqs_have_been_distributed)
+ distribute_irqs();
+#endif
return 0;
}
-void free_irq(unsigned int irq, void *dev_cookie)
+void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction *action;
struct irqaction *tmp = NULL;
unsigned long flags;
unsigned int cpu_irq;
+ int ivindex = -1;
- if(irq == 14)
+ if(irq == 14) {
cpu_irq = irq;
- else
- cpu_irq = ino_to_pil[irq];
+ } else {
+#ifdef CONFIG_PCI
+ if(PCI_IRQ_P(irq))
+ cpu_irq = psycho_ino_to_pil[irq & PCI_IRQ_INO];
+ else
+#endif
+ cpu_irq = sysio_ino_to_pil[irq];
+ }
action = *(cpu_irq + irq_action);
if(!action->handler) {
printk("Freeing free IRQ %d\n", irq);
return;
}
- if(dev_cookie) {
+ if(dev_id) {
for( ; action; action = action->next) {
- if(action->dev_id == dev_cookie)
+ if(action->dev_id == dev_id)
break;
tmp = action;
}
@@ -351,7 +667,7 @@ void free_irq(unsigned int irq, void *dev_cookie)
return;
}
} else if(action->flags & SA_SHIRQ) {
- printk("Trying to free shared IRQ %d with NULL device cookie\n", irq);
+ printk("Trying to free shared IRQ %d with NULL device ID\n", irq);
return;
}
@@ -367,29 +683,37 @@ void free_irq(unsigned int irq, void *dev_cookie)
else
*(cpu_irq + irq_action) = action->next;
- if(action->flags & SA_SYSIO_MASKED) {
- unsigned int *imap = irq_to_imap(irq);
- if(imap != NULL)
- ivector_to_mask[*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)] = 0;
+ if(action->flags & SA_IMAP_MASKED) {
+ struct ino_bucket *bucket = (struct ino_bucket *)action->mask;
+ unsigned int *imap = bucket->imap;
+
+ if(imap != NULL) {
+ ivindex = bucket->ino;
+ ivector_to_mask[ivindex] = 0;
+ }
else
printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n");
}
kfree(action);
- if(!*(cpu_irq + irq_action))
- disable_irq(irq);
+ if(ivindex != -1)
+ disable_irq(ivindex);
restore_flags(flags);
}
-/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
-unsigned int local_irq_count[NR_CPUS];
+/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu
+ * structure for cache reasons.
+ */
+#ifndef __SMP__
+unsigned int local_irq_count;
+#endif
#ifndef __SMP__
int __sparc64_bh_counter = 0;
-#define irq_enter(cpu, irq) (local_irq_count[cpu]++)
-#define irq_exit(cpu, irq) (local_irq_count[cpu]--)
+#define irq_enter(cpu, irq) (local_irq_count++)
+#define irq_exit(cpu, irq) (local_irq_count--)
#else
@@ -407,18 +731,31 @@ spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
/* Global IRQ locking depth. */
atomic_t global_irq_count = ATOMIC_INIT(0);
-static inline void wait_on_irq(int cpu)
+static unsigned long previous_irqholder;
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+
+static inline void wait_on_irq(int cpu, unsigned long where)
{
- int local_count = local_irq_count[cpu];
+ int stuck = INIT_STUCK;
+ int local_count = local_irq_count;
while(local_count != atomic_read(&global_irq_count)) {
atomic_sub(local_count, &global_irq_count);
spin_unlock(&global_irq_lock);
for(;;) {
+ STUCK;
+ membar("#StoreLoad | #LoadLoad");
if (atomic_read(&global_irq_count))
continue;
- if (*((unsigned char *)&global_irq_lock))
+ if (*((volatile unsigned char *)&global_irq_lock))
continue;
+ membar("#LoadLoad | #LoadStore");
if (spin_trylock(&global_irq_lock))
break;
}
@@ -426,25 +763,41 @@ static inline void wait_on_irq(int cpu)
}
}
-static inline void get_irqlock(int cpu)
+#undef INIT_STUCK
+#define INIT_STUCK 10000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+
+static inline void get_irqlock(int cpu, unsigned long where)
{
+ int stuck = INIT_STUCK;
+
if (!spin_trylock(&global_irq_lock)) {
+ membar("#StoreLoad | #LoadLoad");
if ((unsigned char) cpu == global_irq_holder)
return;
do {
- barrier();
+ do {
+ STUCK;
+ membar("#LoadLoad");
+ } while(*((volatile unsigned char *)&global_irq_lock));
} while (!spin_trylock(&global_irq_lock));
}
- wait_on_irq(cpu);
+ wait_on_irq(cpu, where);
global_irq_holder = cpu;
+ previous_irqholder = where;
}
void __global_cli(void)
{
int cpu = smp_processor_id();
+ unsigned long where;
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (where));
__cli();
- get_irqlock(cpu);
+ get_irqlock(cpu, where);
}
void __global_sti(void)
@@ -453,11 +806,6 @@ void __global_sti(void)
__sti();
}
-unsigned long __global_save_flags(void)
-{
- return global_irq_holder == (unsigned char) smp_processor_id();
-}
-
void __global_restore_flags(unsigned long flags)
{
if (flags & 1) {
@@ -472,15 +820,24 @@ void __global_restore_flags(unsigned long flags)
}
}
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
+
void irq_enter(int cpu, int irq)
{
+ int stuck = INIT_STUCK;
+
hardirq_enter(cpu);
- barrier();
- while (*((unsigned char *)&global_irq_lock)) {
+ while (*((volatile unsigned char *)&global_irq_lock)) {
if ((unsigned char) cpu == global_irq_holder)
printk("irq_enter: Frosted Lucky Charms, "
"they're magically delicious!\n");
- barrier();
+ STUCK;
+ membar("#LoadLoad");
}
}
@@ -492,8 +849,7 @@ void irq_exit(int cpu, int irq)
void synchronize_irq(void)
{
- int cpu = smp_processor_id();
- int local_count = local_irq_count[cpu];
+ int local_count = local_irq_count;
unsigned long flags;
if (local_count != atomic_read(&global_irq_count)) {
@@ -506,9 +862,13 @@ void synchronize_irq(void)
void report_spurious_ivec(struct pt_regs *regs)
{
- printk("IVEC: Spurious interrupt vector received at (%016lx)\n",
- regs->tpc);
- return;
+ extern unsigned long ivec_spurious_cookie;
+ static int times = 0;
+
+ printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n",
+ ivec_spurious_cookie, regs->tpc);
+ if(times++ > 1)
+ prom_halt();
}
void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs)
@@ -547,13 +907,28 @@ void handler_irq(int irq, struct pt_regs *regs)
irq_enter(cpu, irq);
action = *(irq + irq_action);
kstat.interrupts[irq]++;
- do {
- if(!action || !action->handler)
- unexpected_irq(irq, 0, regs);
- action->handler(irq, action->dev_id, regs);
- if(action->flags & SA_SYSIO_MASKED)
- *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
- } while((action = action->next) != NULL);
+ if(!action) {
+ unexpected_irq(irq, 0, regs);
+ } else {
+ do {
+ struct ino_bucket *bucket = NULL;
+ unsigned int ino = 0;
+
+ if(action->flags & SA_IMAP_MASKED) {
+ bucket = (struct ino_bucket *)action->mask;
+
+ ino = bucket->ino;
+ if(!(ivector_to_mask[ino] & 0x80000000))
+ continue;
+ }
+
+ action->handler(irq, action->dev_id, regs);
+ if(bucket) {
+ ivector_to_mask[ino] &= ~(0x80000000);
+ *(bucket->iclr) = SYSIO_ICLR_IDLE;
+ }
+ } while((action = action->next) != NULL);
+ }
irq_exit(cpu, irq);
}
@@ -567,7 +942,7 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
irq_enter(cpu, irq);
floppy_interrupt(irq, dev_cookie, regs);
- if(action->flags & SA_SYSIO_MASKED)
+ if(action->flags & SA_IMAP_MASKED)
*((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
irq_exit(cpu, irq);
}
@@ -595,7 +970,7 @@ static void install_fast_irq(unsigned int cpu_irq,
insns[0] = SPARC_BRANCH(((unsigned long) handler),
((unsigned long)&insns[0]));
insns[1] = SPARC_NOP;
- __asm__ __volatile__("flush %0" : : "r" (ttent));
+ __asm__ __volatile__("membar #StoreStore; flush %0" : : "r" (ttent));
}
int request_fast_irq(unsigned int irq,
@@ -605,6 +980,7 @@ int request_fast_irq(unsigned int irq,
struct irqaction *action;
unsigned long flags;
unsigned int cpu_irq, *imap, *iclr;
+ int ivindex = -1;
/* XXX This really is not the way to do it, the "right way"
* XXX is to have drivers set SA_SBUS or something like that
@@ -616,11 +992,11 @@ int request_fast_irq(unsigned int irq,
*/
if(irq == 14)
return -EINVAL;
- cpu_irq = ino_to_pil[irq];
+ cpu_irq = sysio_ino_to_pil[irq];
if(!handler)
return -EINVAL;
- imap = irq_to_imap(irq);
+ imap = sysio_irq_to_imap(irq);
action = *(cpu_irq + irq_action);
if(action) {
if(action->flags & SA_SHIRQ)
@@ -648,12 +1024,12 @@ int request_fast_irq(unsigned int irq,
install_fast_irq(cpu_irq, handler);
if(imap) {
- int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
-
+ ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
ivector_to_mask[ivindex] = (1 << cpu_irq);
- iclr = imap_to_iclr(imap);
+ iclr = sysio_imap_to_iclr(imap);
action->mask = (unsigned long) iclr;
- irqflags |= SA_SYSIO_MASKED;
+ irqflags |= SA_IMAP_MASKED;
+ add_ino_hash(ivindex, imap, iclr, irqflags);
} else
action->mask = 0;
@@ -665,7 +1041,9 @@ int request_fast_irq(unsigned int irq,
*(cpu_irq + irq_action) = action;
- enable_irq(irq);
+ if(ivindex != -1)
+ enable_irq(ivindex);
+
restore_flags(flags);
return 0;
}
@@ -675,31 +1053,27 @@ int request_fast_irq(unsigned int irq,
*/
unsigned long probe_irq_on(void)
{
- return 0;
+ return 0;
}
int probe_irq_off(unsigned long mask)
{
- return 0;
+ return 0;
}
struct sun5_timer *linux_timers = NULL;
-/* This is called from sbus_init() to get the jiffies timer going.
- * We need to call this after there exists a valid SBus_chain so
- * that the IMAP/ICLR registers can be accessed.
- *
- * XXX That is because the whole startup sequence is broken. I will
- * XXX fix it all up very soon. -DaveM
- */
+/* This is gets the master level10 timer going. */
void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
{
struct linux_prom64_registers pregs[3];
+ struct devid_cookie dcookie;
+ unsigned int *imap, *iclr;
u32 pirqs[2];
int node, err;
node = prom_finddevice("/counter-timer");
- if(node == 0) {
+ if(node == 0 || node == -1) {
prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
prom_halt();
}
@@ -715,13 +1089,22 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
prom_halt();
}
linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
+ iclr = (((unsigned int *)__va(pregs[1].phys_addr))+1);
+ imap = (((unsigned int *)__va(pregs[2].phys_addr))+1);
/* Shut it up first. */
linux_timers->limit0 = 0;
/* Register IRQ handler. */
- err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
- cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
+ dcookie.real_dev_id = NULL;
+ dcookie.imap = imap;
+ dcookie.iclr = iclr;
+ dcookie.pil = 10;
+ dcookie.bus_cookie = NULL;
+
+ err = request_irq(pirqs[0], cfunc,
+ (SA_DCOOKIE | SA_INTERRUPT | SA_STATIC_ALLOC),
+ "timer", &dcookie);
if(err) {
prom_printf("Serious problem, cannot register timer interrupt\n");
@@ -825,6 +1208,52 @@ void enable_prom_timer(void)
prom_timers->count0 = 0;
}
+#ifdef __SMP__
+/* Called from smp_commence, when we know how many cpus are in the system
+ * and can have device IRQ's directed at them.
+ */
+void distribute_irqs(void)
+{
+ unsigned long flags;
+ int cpu, level;
+
+ printk("SMP: redistributing interrupts...\n");
+ save_and_cli(flags);
+ cpu = 0;
+ for(level = 0; level < NR_IRQS; level++) {
+ struct irqaction *p = irq_action[level];
+
+ while(p) {
+ if(p->flags & SA_IMAP_MASKED) {
+ struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
+ unsigned int *imap = bucket->imap;
+ unsigned int val;
+ unsigned long tid = linux_cpus[cpu].mid << 9;
+
+ val = *imap;
+ *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+
+ printk("SMP: Redirecting IGN[%x] INO[%x] "
+ "to cpu %d [%s]\n",
+ (val & SYSIO_IMAP_IGN) >> 6,
+ (val & SYSIO_IMAP_INO), cpu,
+ p->name);
+
+ cpu += 1;
+ while(!(cpu_present_map & (1UL << cpu))) {
+ cpu += 1;
+ if(cpu >= smp_num_cpus)
+ cpu = 0;
+ }
+ }
+ p = p->next;
+ }
+ }
+ restore_flags(flags);
+ irqs_have_been_distributed = 1;
+}
+#endif
+
__initfunc(void init_IRQ(void))
{
int i;
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index afd5af8d0..35d4d606d 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
+/* $Id: process.c,v 1.42 1997/08/19 14:17:55 jj Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -27,18 +27,21 @@
#include <linux/a.out.h>
#include <linux/config.h>
#include <linux/reboot.h>
+#include <linux/delay.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/delay.h>
#include <asm/processor.h>
#include <asm/pstate.h>
#include <asm/elf.h>
#include <asm/fpumacro.h>
+#define PGTCACHE_HIGH_WATER 50
+#define PGTCACHE_LOW_WATER 25
+
#ifndef __SMP__
/*
@@ -53,6 +56,16 @@ asmlinkage int sys_idle(void)
current->priority = -100;
current->counter = -100;
for (;;) {
+ if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+ do {
+ if(pgd_quicklist)
+ free_page((unsigned long) get_pgd_fast());
+ if(pmd_quicklist)
+ free_page((unsigned long) get_pmd_fast());
+ if(pte_quicklist)
+ free_page((unsigned long) get_pte_fast());
+ } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+ }
run_task_queue(&tq_scheduler);
schedule();
}
@@ -68,13 +81,26 @@ asmlinkage int cpu_idle(void)
{
current->priority = -100;
while(1) {
+ if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+ do {
+ if(pgd_quicklist)
+ free_page((unsigned long) get_pgd_fast());
+ if(pmd_quicklist)
+ free_page((unsigned long) get_pmd_fast());
+ if(pte_quicklist)
+ free_page((unsigned long) get_pte_fast());
+ } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+ }
if(tq_scheduler) {
lock_kernel();
run_task_queue(&tq_scheduler);
unlock_kernel();
}
+ barrier();
current->counter = -100;
- schedule();
+ if(resched_needed())
+ schedule();
+ barrier();
}
}
@@ -251,8 +277,20 @@ void show_stackframe32(struct sparc_stackf32 *sf)
} while ((size -= sizeof(unsigned)));
}
-void show_regs(struct pt_regs * regs)
+#ifdef __SMP__
+static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+void __show_regs(struct pt_regs * regs)
{
+#ifdef __SMP__
+ unsigned long flags;
+
+ spin_lock_irqsave(&regdump_lock, flags);
+ printk("CPU[%d]: local_irq_count[%ld] global_irq_count[%d]\n",
+ smp_processor_id(), local_irq_count,
+ atomic_read(&global_irq_count));
+#endif
printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
regs->tpc, regs->tnpc, regs->y);
printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
@@ -268,6 +306,21 @@ void show_regs(struct pt_regs * regs)
regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
regs->u_regs[15]);
show_regwindow(regs);
+#ifdef __SMP__
+ spin_unlock_irqrestore(&regdump_lock, flags);
+#endif
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ __show_regs(regs);
+#ifdef __SMP__
+ {
+ extern void smp_report_regs(void);
+
+ smp_report_regs();
+ }
+#endif
}
void show_regs32(struct pt_regs32 *regs)
@@ -332,17 +385,22 @@ void flush_thread(void)
/* No new signal delivery by default. */
current->tss.new_signal = 0;
- current->flags &= ~PF_USEDFPU;
+ current->tss.flags &= ~(SPARC_FLAG_USEDFPU | SPARC_FLAG_USEDFPUL |
+ SPARC_FLAG_USEDFPUU);
/* Now, this task is no longer a kernel thread. */
current->tss.current_ds = USER_DS;
if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+ extern spinlock_t scheduler_lock;
+
current->tss.flags &= ~SPARC_FLAG_KTHREAD;
/* exec_mmap() set context to NO_CONTEXT, here is
* where we grab a new one.
*/
+ spin_lock(&scheduler_lock);
get_mmu_context(current);
+ spin_unlock(&scheduler_lock);
}
current->tss.ctx = current->mm->context & 0x1fff;
spitfire_set_secondary_context (current->tss.ctx);
@@ -437,10 +495,14 @@ void fault_in_user_windows(struct pt_regs *regs)
struct reg_window *rwin = &tp->reg_window[window];
if(copy_to_user((char *)sp, rwin, winsize))
- do_exit(SIGILL);
+ goto barf;
} while(window--);
}
current->tss.w_saved = 0;
+ return;
+barf:
+ lock_kernel();
+ do_exit(SIGILL);
}
/* Copy a Sparc thread. The fork() return value conventions
@@ -483,7 +545,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
#endif
p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
- p->tss.cwp = regs->u_regs[UREG_G0];
+ p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
if(regs->tstate & TSTATE_PRIV) {
p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
p->tss.flags |= SPARC_FLAG_KTHREAD;
@@ -581,6 +643,7 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
if(!error) {
fprs_write(0);
regs->fprs = 0;
+ regs->tstate &= ~TSTATE_PEF;
}
out:
unlock_kernel();
diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c
new file mode 100644
index 000000000..8aa1c342b
--- /dev/null
+++ b/arch/sparc64/kernel/psycho.c
@@ -0,0 +1,1417 @@
+/* $Id: psycho.c,v 1.22 1997/08/31 03:51:40 davem Exp $
+ * psycho.c: Ultra/AX U2P PCI controller support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/ebus.h>
+#include <asm/sbus.h> /* for sanity check... */
+
+#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
+
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/oplib.h>
+#include <asm/pbm.h>
+#include <asm/uaccess.h>
+
+struct linux_psycho *psycho_root = NULL;
+
+/* This is used to make the scan_bus in the generic PCI code be
+ * a nop, as we need to control the actual bus probing sequence.
+ * After that we leave it on of course.
+ */
+static int pci_probe_enable = 0;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+ return ((addr + (sizeof(unsigned long) - 1)) &
+ ~(sizeof(unsigned long) - 1));
+}
+
+static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
+ unsigned long memory_start)
+{
+ unsigned long tsbbase = PAGE_ALIGN(memory_start);
+ unsigned long control, i;
+ unsigned long *iopte;
+
+ memory_start = (tsbbase + ((32 * 1024) * 8));
+ iopte = (unsigned long *)tsbbase;
+
+ for(i = 0; i < (65536 / 2); i++) {
+ *iopte = (IOPTE_VALID | IOPTE_64K |
+ IOPTE_CACHE | IOPTE_WRITE);
+ *iopte |= (i << 16);
+ iopte++;
+ }
+
+ psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase);
+
+ control = psycho->psycho_regs->iommu_control;
+ control &= ~(IOMMU_CTRL_TSBSZ);
+ control |= (IOMMU_TSBSZ_32K | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+ psycho->psycho_regs->iommu_control = control;
+
+ return memory_start;
+}
+
+extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
+
+unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+{
+ struct linux_prom64_registers pr_regs[3];
+ char namebuf[128];
+ u32 portid;
+ int node;
+
+ printk("PSYCHO: Probing for controllers.\n");
+
+ memory_start = long_align(memory_start);
+ node = prom_getchild(prom_root_node);
+ while((node = prom_searchsiblings(node, "pci")) != 0) {
+ struct linux_psycho *psycho = (struct linux_psycho *)memory_start;
+ struct linux_psycho *search;
+ struct linux_pbm_info *pbm = NULL;
+ u32 busrange[2];
+ int err, is_pbm_a;
+
+ portid = prom_getintdefault(node, "upa-portid", 0xff);
+ for(search = psycho_root; search; search = search->next) {
+ if(search->upa_portid == portid) {
+ psycho = search;
+
+ /* This represents _this_ instance, so it's
+ * which ever one does _not_ have the prom node
+ * info filled in yet.
+ */
+ is_pbm_a = (psycho->pbm_A.prom_node == 0);
+ goto other_pbm;
+ }
+ }
+
+ memory_start = long_align(memory_start + sizeof(struct linux_psycho));
+
+ memset(psycho, 0, sizeof(*psycho));
+
+ psycho->next = psycho_root;
+ psycho_root = psycho;
+
+ psycho->upa_portid = portid;
+
+ /* Map in PSYCHO register set and report the presence of this PSYCHO. */
+ err = prom_getproperty(node, "reg",
+ (char *)&pr_regs[0], sizeof(pr_regs));
+ if(err == 0 || err == -1) {
+ prom_printf("PSYCHO: Error, cannot get U2P registers "
+ "from PROM.\n");
+ prom_halt();
+ }
+
+ /* Third REG in property is base of entire PSYCHO register space. */
+ psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
+ NULL, sizeof(struct psycho_regs),
+ "PSYCHO Registers",
+ (pr_regs[2].phys_addr >> 32), 0);
+ if(psycho->psycho_regs == NULL) {
+ prom_printf("PSYCHO: Error, cannot map PSYCHO "
+ "main registers.\n");
+ prom_halt();
+ }
+
+ printk("PSYCHO: Found controller, main regs at %p\n",
+ psycho->psycho_regs);
+#if 0
+ printk("PSYCHO: Interrupt retry [%016lx]\n",
+ psycho->psycho_regs->irq_retry);
+#endif
+ psycho->psycho_regs->irq_retry = 0xff;
+
+ /* Now map in PCI config space for entire PSYCHO. */
+ psycho->pci_config_space =
+ sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000),
+ NULL, 0x01000000,
+ "PCI Config Space",
+ (pr_regs[2].phys_addr >> 32), 0);
+ if(psycho->pci_config_space == NULL) {
+ prom_printf("PSYCHO: Error, cannot map PCI config space.\n");
+ prom_halt();
+ }
+
+ /* Report some more info. */
+ printk("PSYCHO: PCI config space at %p\n", psycho->pci_config_space);
+
+ memory_start = psycho_iommu_init(psycho, memory_start);
+
+ is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
+
+ /* Enable arbitration for all PCI slots. */
+ psycho->psycho_regs->pci_a_control |= 0x3f;
+ psycho->psycho_regs->pci_b_control |= 0x3f;
+
+ other_pbm:
+ if(is_pbm_a)
+ pbm = &psycho->pbm_A;
+ else
+ pbm = &psycho->pbm_B;
+
+ pbm->parent = psycho;
+ pbm->IO_assignments = NULL;
+ pbm->MEM_assignments = NULL;
+ pbm->prom_node = node;
+
+ prom_getstring(node, "name", namebuf, sizeof(namebuf));
+ strcpy(pbm->prom_name, namebuf);
+
+ /* Now the ranges. */
+ prom_pbm_ranges_init(node, pbm);
+
+ /* Finally grab the pci bus root array for this pbm after
+ * having found the bus range existing under it.
+ */
+ err = prom_getproperty(node, "bus-range",
+ (char *)&busrange[0], sizeof(busrange));
+ if(err == 0 || err == -1) {
+ prom_printf("PSYCHO: Error, cannot get PCI bus range.\n");
+ prom_halt();
+ }
+ pbm->pci_first_busno = busrange[0];
+ pbm->pci_last_busno = busrange[1];
+ memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
+
+ node = prom_getsibling(node);
+ if(!node)
+ break;
+ }
+
+ /* Last minute sanity check. */
+ if(psycho_root == NULL && SBus_chain == NULL) {
+ prom_printf("Fatal error, neither SBUS nor PCI bus found.\n");
+ prom_halt();
+ }
+
+ return memory_start;
+}
+
+int pcibios_present(void)
+{
+ return psycho_root != NULL;
+}
+
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->vendor == vendor && dev->device == device_id) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pcibios_find_class (unsigned int class_code, unsigned short index,
+ unsigned char *bus, unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->class == class_code) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static inline struct pci_vma *pci_find_vma(struct linux_pbm_info *pbm,
+ unsigned long start,
+ int io)
+{
+ struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
+
+ while(vp) {
+ if(vp->end > start)
+ break;
+ vp = vp->next;
+ }
+ return vp;
+}
+
+static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new, int io)
+{
+ struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
+
+ if(!vp) {
+ new->next = NULL;
+ if(io)
+ pbm->IO_assignments = new;
+ else
+ pbm->MEM_assignments = new;
+ } else {
+ struct pci_vma *prev = NULL;
+
+ while(vp && (vp->end < new->end)) {
+ prev = vp;
+ vp = vp->next;
+ }
+ new->next = vp;
+ if(!prev) {
+ if(io)
+ pbm->IO_assignments = new;
+ else
+ pbm->MEM_assignments = new;
+ } else {
+ prev->next = new;
+ }
+
+ /* Check for programming errors. */
+ if(vp &&
+ ((vp->start >= new->start && vp->start < new->end) ||
+ ((vp->end - 1) >= new->start && (vp->end - 1) < new->end))) {
+ prom_printf("pci_add_vma: Wheee, overlapping %s PCI vma's\n",
+ io ? "IO" : "MEM");
+ prom_printf("pci_add_vma: vp[%016lx:%016lx] "
+ "new[%016lx:%016lx]\n",
+ vp->start, vp->end,
+ new->start, new->end);
+ }
+ }
+}
+
+static unsigned long *pci_alloc_arena = NULL;
+
+static inline void pci_init_alloc_init(unsigned long *mstart)
+{
+ pci_alloc_arena = mstart;
+}
+
+static inline void pci_init_alloc_fini(void)
+{
+ pci_alloc_arena = NULL;
+}
+
+static void *pci_init_alloc(int size)
+{
+ unsigned long start = long_align(*pci_alloc_arena);
+ void *mp = (void *)start;
+
+ if(!pci_alloc_arena) {
+ prom_printf("pci_init_alloc: pci_vma arena not init'd\n");
+ prom_halt();
+ }
+ start += size;
+ *pci_alloc_arena = start;
+ return mp;
+}
+
+static inline struct pci_vma *pci_vma_alloc(void)
+{
+ return pci_init_alloc(sizeof(struct pci_vma));
+}
+
+static inline struct pcidev_cookie *pci_devcookie_alloc(void)
+{
+ return pci_init_alloc(sizeof(struct pcidev_cookie));
+}
+
+static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
+{
+ struct pci_bus *pbus = &pbm->pci_bus;
+
+ /* PSYCHO PBM's include child PCI bridges in bus-range property,
+ * but we don't scan each of those ourselves, Linux generic PCI
+ * probing code will find child bridges and link them into this
+ * pbm's root PCI device hierarchy.
+ */
+ pbus->number = pbm->pci_first_busno;
+ pbus->sysdata = pbm;
+ pbus->subordinate = pci_scan_bus(pbus, mstart);
+}
+
+static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev,
+ int node)
+{
+ struct linux_prom_pci_registers pregs[PROMREG_MAX];
+ int err;
+
+ while(node) {
+ int child;
+
+ child = prom_getchild(node);
+ if(child != 0 && child != -1) {
+ int res;
+
+ res = pdev_to_pnode_sibtraverse(pbm, pdev, child);
+ if(res != 0 && res != -1)
+ return res;
+ }
+ err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+ if(err != 0 && err != -1) {
+ u32 devfn = (pregs[0].phys_hi >> 8) & 0xff;
+
+ if(devfn == pdev->devfn)
+ return node; /* Match */
+ }
+
+ node = prom_getsibling(node);
+ }
+ return 0;
+}
+
+static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev)
+{
+ struct pcidev_cookie *pcp;
+ int node = prom_getchild(pbm->prom_node);
+
+ node = pdev_to_pnode_sibtraverse(pbm, pdev, node);
+ if(node == 0)
+ node = -1;
+ pcp = pci_devcookie_alloc();
+ pcp->pbm = pbm;
+ pcp->prom_node = node;
+ pdev->sysdata = pcp;
+}
+
+static void fill_in_pbm_cookies(struct linux_pbm_info *pbm)
+{
+ struct pci_bus *pbtmp, *pbus = &pbm->pci_bus;
+ struct pci_dev *pdev;
+
+ for(pbtmp = pbus->children; pbtmp; pbtmp = pbtmp->children)
+ pbtmp->sysdata = pbm;
+
+ for( ; pbus; pbus = pbus->children)
+ for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ pdev_cookie_fillin(pbm, pdev);
+}
+
+/* #define RECORD_ASSIGNMENTS_DEBUG */
+
+/* Walk PROM device tree under PBM, looking for 'assigned-address'
+ * properties, and recording them in pci_vma's linked in via
+ * PBM->assignments.
+ */
+static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs)
+{
+ struct linux_prom_ebus_ranges erng[PROMREG_MAX];
+ int err, iter;
+
+ err = prom_getproperty(node, "ranges", (char *)&erng[0], sizeof(erng));
+ if(err == 0 || err == -1) {
+ prom_printf("EBUS: fatal error, no range property.\n");
+ prom_halt();
+ }
+ err = (err / sizeof(struct linux_prom_ebus_ranges));
+ for(iter = 0; iter < err; iter++) {
+ struct linux_prom_ebus_ranges *ep = &erng[iter];
+ struct linux_prom_pci_registers *ap = &aregs[iter];
+
+ ap->phys_hi = ep->parent_phys_hi;
+ ap->phys_mid = ep->parent_phys_mid;
+ ap->phys_lo = ep->parent_phys_lo;
+ }
+ return err;
+}
+
+static void assignment_process(struct linux_pbm_info *pbm, int node)
+{
+ struct linux_prom_pci_registers aregs[PROMREG_MAX];
+ char pname[256];
+ int err, iter, numa;
+
+ err = prom_getproperty(node, "name", (char *)&pname[0], sizeof(pname));
+ if(strncmp(pname, "ebus", 4) == 0) {
+ numa = gimme_ebus_assignments(node, &aregs[0]);
+ } else {
+ err = prom_getproperty(node, "assigned-addresses",
+ (char *)&aregs[0], sizeof(aregs));
+
+ /* No assignments, nothing to do. */
+ if(err == 0 || err == -1)
+ return;
+
+ numa = (err / sizeof(struct linux_prom_pci_ranges));
+ }
+
+ for(iter = 0; iter < numa; iter++) {
+ struct linux_prom_pci_registers *ap = &aregs[iter];
+ struct pci_vma *vp;
+ int space, breg, io;
+
+ space = (ap->phys_hi >> 24) & 3;
+ if(space != 1 && space != 2)
+ continue;
+ io = (space == 1);
+
+ breg = (ap->phys_hi & 0xff);
+ if(breg == PCI_ROM_ADDRESS)
+ continue;
+
+ vp = pci_vma_alloc();
+
+ /* XXX Means we don't support > 32-bit range of
+ * XXX PCI MEM space, PSYCHO/PBM does not support it
+ * XXX either due to it's layout so...
+ */
+ vp->start = ap->phys_lo;
+ vp->end = vp->start + ap->size_lo;
+ vp->base_reg = breg;
+
+ /* Sanity */
+ if(io && (vp->end & ~(0xffff))) {
+ prom_printf("assignment_process: Out of range PCI I/O "
+ "[%08lx:%08lx]\n", vp->start, vp->end);
+ prom_halt();
+ }
+
+ pci_add_vma(pbm, vp, io);
+ }
+}
+
+static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node)
+{
+ while(node) {
+ int child = prom_getchild(node);
+ if(child)
+ assignment_walk_siblings(pbm, child);
+
+ assignment_process(pbm, node);
+
+ node = prom_getsibling(node);
+ }
+}
+
+static void record_assignments(struct linux_pbm_info *pbm)
+{
+ assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node));
+}
+
+/* #define FIXUP_REGS_DEBUG */
+
+static void fixup_regs(struct pci_dev *pdev,
+ struct linux_pbm_info *pbm,
+ struct linux_prom_pci_registers *pregs,
+ int nregs,
+ struct linux_prom_pci_registers *assigned,
+ int numaa)
+{
+ int preg, rng;
+ int IO_seen = 0;
+ int MEM_seen = 0;
+
+ for(preg = 0; preg < nregs; preg++) {
+ struct linux_prom_pci_registers *ap = NULL;
+ int bustype = (pregs[preg].phys_hi >> 24) & 0x3;
+ int bsreg, brindex;
+ u64 pci_addr;
+
+ if(bustype == 0) {
+ /* Config space cookie, nothing to do. */
+ if(preg != 0)
+ prom_printf("fixup_doit: strange, config space not 0\n");
+ continue;
+ } else if(bustype == 3) {
+ /* XXX add support for this... */
+ prom_printf("fixup_doit: Warning, ignoring 64-bit PCI "
+ "memory space, tell DaveM.\n");
+ continue;
+ }
+ bsreg = (pregs[preg].phys_hi & 0xff);
+
+ /* We can safely ignore these. */
+ if(bsreg == PCI_ROM_ADDRESS)
+ continue;
+
+ /* Sanity */
+ if((bsreg < PCI_BASE_ADDRESS_0) ||
+ (bsreg > (PCI_BASE_ADDRESS_5 + 4)) ||
+ (bsreg & 3)) {
+ prom_printf("fixup_doit: Warning, ignoring bogus basereg [%x]\n",
+ bsreg);
+ continue;
+ }
+
+ brindex = (bsreg - PCI_BASE_ADDRESS_0) >> 2;
+ if(numaa) {
+ int r;
+
+ for(r = 0; r < numaa; r++) {
+ int abreg;
+
+ abreg = (assigned[r].phys_hi & 0xff);
+ if(abreg == bsreg) {
+ ap = &assigned[r];
+ break;
+ }
+ }
+ }
+
+ /* Now construct UPA physical address. */
+ pci_addr = (((u64)pregs[preg].phys_mid) << 32UL);
+ pci_addr |= (((u64)pregs[preg].phys_lo));
+
+ if(ap) {
+ pci_addr += ((u64)ap->phys_lo);
+ pci_addr += (((u64)ap->phys_mid) << 32UL);
+ }
+
+ /* Final step, apply PBM range. */
+ for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
+ struct linux_prom_pci_ranges *rp = &pbm->pbm_ranges[rng];
+ int space = (rp->child_phys_hi >> 24) & 3;
+
+ if(space == bustype) {
+ pci_addr += ((u64)rp->parent_phys_lo);
+ pci_addr += (((u64)rp->parent_phys_hi) << 32UL);
+ break;
+ }
+ }
+ if(rng == pbm->num_pbm_ranges) {
+ /* AIEEE */
+ prom_printf("fixup_doit: YIEEE, cannot find PBM ranges\n");
+ }
+ pdev->base_address[brindex] = (unsigned long)__va(pci_addr);
+
+ /* Preserve I/O space bit. */
+ if(bustype == 0x1) {
+ pdev->base_address[brindex] |= 1;
+ IO_seen = 1;
+ } else {
+ MEM_seen = 1;
+ }
+ }
+
+ /* Now handle assignments PROM did not take care of. */
+ if(nregs) {
+ int breg;
+
+ for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) {
+ unsigned int rtmp, ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2);
+ unsigned int base = (unsigned int)pdev->base_address[ridx];
+ struct pci_vma *vp;
+ u64 pci_addr;
+ int io;
+
+ if(pdev->base_address[ridx] > PAGE_OFFSET)
+ continue;
+
+ io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+ base &= ~((io ?
+ PCI_BASE_ADDRESS_IO_MASK :
+ PCI_BASE_ADDRESS_MEM_MASK));
+ vp = pci_find_vma(pbm, base, io);
+ if(!vp || vp->start > base) {
+ unsigned int size, new_base;
+
+ pcibios_read_config_dword(pdev->bus->number,
+ pdev->devfn,
+ breg, &rtmp);
+ pcibios_write_config_dword(pdev->bus->number,
+ pdev->devfn,
+ breg, 0xffffffff);
+ pcibios_read_config_dword(pdev->bus->number,
+ pdev->devfn,
+ breg, &size);
+ if(io)
+ size &= ~1;
+ size = (~(size) + 1);
+ if(!size)
+ continue;
+
+ new_base = 0;
+ for(vp=pci_find_vma(pbm,new_base,io); ; vp=vp->next) {
+ if(!vp || new_base + size <= vp->start)
+ break;
+ new_base = (vp->end + (size - 1)) & ~(size-1);
+ }
+ if(vp && (new_base + size > vp->start)) {
+ prom_printf("PCI: Impossible full %s space.\n",
+ (io ? "IO" : "MEM"));
+ prom_halt();
+ }
+ vp = pci_vma_alloc();
+ vp->start = new_base;
+ vp->end = vp->start + size;
+ vp->base_reg = breg;
+
+ /* Sanity */
+ if(io && vp->end & ~(0xffff)) {
+ prom_printf("PCI: Out of range PCI I/O "
+ "[%08lx:%08lx] during fixup\n",
+ vp->start, vp->end);
+ prom_halt();
+ }
+ pci_add_vma(pbm, vp, io);
+
+ rtmp = new_base;
+ if(io)
+ rtmp |= (rtmp & PCI_BASE_ADDRESS_IO_MASK);
+ else
+ rtmp |= (rtmp & PCI_BASE_ADDRESS_MEM_MASK);
+ pcibios_write_config_dword(pdev->bus->number,
+ pdev->devfn,
+ breg, rtmp);
+
+ /* Apply PBM ranges and update pci_dev. */
+ pci_addr = new_base;
+ for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
+ struct linux_prom_pci_ranges *rp;
+ int rspace;
+
+ rp = &pbm->pbm_ranges[rng];
+ rspace = (rp->child_phys_hi >> 24) & 3;
+ if(io && rspace != 1)
+ continue;
+ else if(!io && rspace != 2)
+ continue;
+ pci_addr += ((u64)rp->parent_phys_lo);
+ pci_addr += (((u64)rp->parent_phys_hi)<<32UL);
+ break;
+ }
+ if(rng == pbm->num_pbm_ranges) {
+ /* AIEEE */
+ prom_printf("fixup_doit: YIEEE, cannot find "
+ "PBM ranges\n");
+ }
+ pdev->base_address[ridx] = (unsigned long)__va(pci_addr);
+
+ /* Preserve I/O space bit. */
+ if(io) {
+ pdev->base_address[ridx] |= 1;
+ IO_seen = 1;
+ } else {
+ MEM_seen = 1;
+ }
+ }
+ }
+ }
+ if(IO_seen || MEM_seen) {
+ unsigned int l;
+
+ pcibios_read_config_dword(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, &l);
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("[");
+#endif
+ if(IO_seen) {
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("IO ");
+#endif
+ l |= PCI_COMMAND_IO;
+ }
+ if(MEM_seen) {
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("MEM");
+#endif
+ l |= PCI_COMMAND_MEMORY;
+ }
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("]");
+#endif
+ pcibios_write_config_dword(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, l);
+ }
+
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("REG_FIXUP[%s]: ", pci_strdev(pdev->vendor, pdev->device));
+ for(preg = 0; preg < 6; preg++) {
+ if(pdev->base_address[preg] != 0)
+ prom_printf("%d[%016lx] ", preg, pdev->base_address[preg]);
+ }
+ prom_printf("\n");
+#endif
+}
+
+#define imap_offset(__member) \
+ ((unsigned long)(&(((struct psycho_regs *)0)->__member)))
+
+static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
+{
+ unsigned int bus, slot;
+
+ bus = (ino & 0x10) >> 4;
+ slot = (ino & 0x0c) >> 2;
+
+ if(bus == 0) {
+ /* Perform a sanity check, we might as well.
+ * PBM A only has 2 PCI slots.
+ */
+ if(slot > 1) {
+ prom_printf("pcislot_imap: Bogus slot on PBM A (%ld)\n", slot);
+ prom_halt();
+ }
+ if(slot == 0)
+ return imap_offset(imap_a_slot0);
+ else
+ return imap_offset(imap_a_slot1);
+ } else {
+ switch(slot) {
+ case 0:
+ return imap_offset(imap_b_slot0);
+ case 1:
+ return imap_offset(imap_b_slot1);
+ case 2:
+ return imap_offset(imap_b_slot2);
+ case 3:
+ return imap_offset(imap_b_slot3);
+ default:
+ prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n",
+ bus, slot);
+ prom_halt();
+ return 0; /* Make gcc happy */
+ };
+ }
+}
+
+/* Exported for EBUS probing layer. */
+unsigned int psycho_irq_build(unsigned int full_ino)
+{
+ unsigned long imap_off, ign, ino;
+
+ ign = (full_ino & PSYCHO_IMAP_IGN) >> 6;
+ ino = (full_ino & PSYCHO_IMAP_INO);
+
+ /* Compute IMAP register offset, generic IRQ layer figures out
+ * the ICLR register address as this is simple given the 32-bit
+ * irq number and IMAP register address.
+ */
+ if((ino & 0x20) == 0)
+ imap_off = psycho_pcislot_imap_offset(ino);
+ else {
+ switch(ino) {
+ case 0x20:
+ /* Onboard SCSI. */
+ imap_off = imap_offset(imap_scsi);
+ break;
+
+ case 0x21:
+ /* Onboard Ethernet (ie. CheerIO/HME) */
+ imap_off = imap_offset(imap_eth);
+ break;
+
+ case 0x22:
+ /* Onboard Parallel Port */
+ imap_off = imap_offset(imap_bpp);
+ break;
+
+ case 0x23:
+ /* Audio Record */
+ imap_off = imap_offset(imap_au_rec);
+ break;
+
+ case 0x24:
+ /* Audio Play */
+ imap_off = imap_offset(imap_au_play);
+ break;
+
+ case 0x25:
+ /* Power Fail */
+ imap_off = imap_offset(imap_pfail);
+ break;
+
+ case 0x26:
+ /* Onboard KBD/MOUSE/SERIAL */
+ imap_off = imap_offset(imap_kms);
+ break;
+
+ case 0x27:
+ /* Floppy (ie. fdthree) */
+ imap_off = imap_offset(imap_flpy);
+ break;
+
+ case 0x28:
+ /* Spare HW INT */
+ imap_off = imap_offset(imap_shw);
+ break;
+
+ case 0x29:
+ /* Onboard Keyboard (only) */
+ imap_off = imap_offset(imap_kbd);
+ break;
+
+ case 0x2a:
+ /* Onboard Mouse (only) */
+ imap_off = imap_offset(imap_ms);
+ break;
+
+ case 0x2b:
+ /* Onboard Serial (only) */
+ imap_off = imap_offset(imap_ser);
+ break;
+
+ case 0x32:
+ /* Power Management */
+ imap_off = imap_offset(imap_pmgmt);
+ break;
+
+ default:
+ /* We don't expect anything else. The other possible
+ * values are not found in PCI device nodes, and are
+ * so hardware specific that they should use DCOOKIE's
+ * anyways.
+ */
+ prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino);
+ prom_halt();
+ };
+ }
+ imap_off -= imap_offset(imap_a_slot0);
+
+ return pci_irq_encode(imap_off, 0 /* XXX */, ign, ino);
+}
+
+/* #define FIXUP_IRQ_DEBUG */
+
+static void fixup_irq(struct pci_dev *pdev,
+ struct linux_pbm_info *pbm,
+ int node)
+{
+ unsigned int prom_irq, portid = pbm->parent->upa_portid;
+ unsigned char pci_irq_line = pdev->irq;
+ int err;
+
+#ifdef FIXUP_IRQ_DEBUG
+ printk("fixup_irq[%s:%s]: ",
+ pci_strvendor(pdev->vendor),
+ pci_strdev(pdev->vendor, pdev->device));
+#endif
+ err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq));
+ if(err == 0 || err == -1) {
+ prom_printf("fixup_irq: No interrupts property for dev[%s:%s]\n",
+ pci_strvendor(pdev->vendor),
+ pci_strdev(pdev->vendor, pdev->device));
+ prom_halt();
+ }
+
+ /* See if fully specified already (ie. for onboard devices like hme) */
+ if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
+ pdev->irq = psycho_irq_build(prom_irq);
+#ifdef FIXUP_IRQ_DEBUG
+ printk("fully specified prom_irq[%x] pdev->irq[%x]",
+ prom_irq, pdev->irq);
+#endif
+ } else {
+ unsigned int bus, slot, line;
+
+ bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0;
+ line = (pci_irq_line) & 3;
+
+ /* Slot determination is only slightly complex. Handle
+ * the easy case first.
+ */
+ if(pdev->bus->number == pbm->pci_first_busno) {
+ if(pbm == &pbm->parent->pbm_A)
+ slot = (pdev->devfn >> 3) - 1;
+ else
+ slot = ((pdev->devfn >> 3) >> 1) - 1;
+ } else {
+ /* Underneath a bridge, use slot number of parent
+ * bridge.
+ */
+ slot = (pdev->bus->self->devfn >> 3) - 1;
+
+ /* Use low slot number bits of child as IRQ line. */
+ line = ((pdev->devfn >> 3) & 3);
+ }
+ slot = (slot << 2);
+
+ pdev->irq = psycho_irq_build((((portid << 6) & PSYCHO_IMAP_IGN) |
+ (bus | slot | line)));
+#ifdef FIXUP_IRQ_DEBUG
+ do {
+ unsigned char iline, ipin;
+
+ (void)pcibios_read_config_byte(pdev->bus->number,
+ pdev->devfn,
+ PCI_INTERRUPT_PIN,
+ &ipin);
+ (void)pcibios_read_config_byte(pdev->bus->number,
+ pdev->devfn,
+ PCI_INTERRUPT_LINE,
+ &iline);
+ printk("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] "
+ "iline[%x] ipin[%x] prom_irq[%x]",
+ portid, bus>>4, slot>>2, line, pdev->irq,
+ iline, ipin, prom_irq);
+ } while(0);
+#endif
+ }
+#ifdef FIXUP_IRQ_DEBUG
+ printk("\n");
+#endif
+}
+
+static void fixup_doit(struct pci_dev *pdev,
+ struct linux_pbm_info *pbm,
+ struct linux_prom_pci_registers *pregs,
+ int nregs,
+ int node)
+{
+ struct linux_prom_pci_registers assigned[PROMREG_MAX];
+ int numaa, err;
+
+ /* Get assigned addresses, if any. */
+ err = prom_getproperty(node, "assigned-addresses",
+ (char *)&assigned[0], sizeof(assigned));
+ if(err == 0 || err == -1)
+ numaa = 0;
+ else
+ numaa = (err / sizeof(struct linux_prom_pci_registers));
+
+ /* First, scan and fixup base registers. */
+ fixup_regs(pdev, pbm, pregs, nregs, &assigned[0], numaa);
+
+ /* Next, fixup interrupt numbers. */
+ fixup_irq(pdev, pbm, node);
+}
+
+static void fixup_pci_dev(struct pci_dev *pdev,
+ struct pci_bus *pbus,
+ struct linux_pbm_info *pbm)
+{
+ struct linux_prom_pci_registers pregs[PROMREG_MAX];
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ int node, nregs, err;
+
+ /* If this is a PCI bridge, we must program it. */
+ if(pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) {
+ unsigned short cmd;
+
+ /* First, enable bus mastering. */
+ pcibios_read_config_word(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, cmd);
+
+ /* Now, set cache line size to 64-bytes. */
+ pcibios_write_config_byte(pdev->bus->number,
+ pdev->devfn,
+ PCI_CACHE_LINE_SIZE, 64);
+ }
+
+ /* Ignore if this is one of the PBM's, EBUS, or a
+ * sub-bridge underneath the PBM. We only need to fixup
+ * true devices.
+ */
+ if((pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) ||
+ (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) ||
+ (pdev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) ||
+ (pcp == NULL))
+ return;
+
+ node = pcp->prom_node;
+
+ err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+ if(err == 0 || err == -1) {
+ prom_printf("Cannot find REG for pci_dev\n");
+ prom_halt();
+ }
+
+ nregs = (err / sizeof(pregs[0]));
+
+ fixup_doit(pdev, pbm, &pregs[0], nregs, node);
+}
+
+static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
+{
+ struct pci_dev *pdev;
+
+ for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ fixup_pci_dev(pdev, pbus, pbm);
+
+ for(pbus = pbus->children; pbus; pbus = pbus->children)
+ fixup_pci_bus(pbus, pbm);
+}
+
+static void fixup_addr_irq(struct linux_pbm_info *pbm)
+{
+ struct pci_bus *pbus = &pbm->pci_bus;
+
+ /* Work through top level devices (not bridges, those and their
+ * devices are handled specially in the next loop).
+ */
+ fixup_pci_bus(pbus, pbm);
+}
+
+/* Walk all PCI devices probes, fixing up base registers and IRQ registers.
+ * We use OBP for most of this work.
+ */
+static void psycho_final_fixup(struct linux_psycho *psycho)
+{
+ /* Second, fixup base address registers and IRQ lines... */
+ fixup_addr_irq(&psycho->pbm_A);
+ fixup_addr_irq(&psycho->pbm_B);
+
+#if 0
+ prom_halt();
+#endif
+}
+
+unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end)
+{
+ struct linux_psycho *psycho = psycho_root;
+
+ pci_probe_enable = 1;
+
+ /* XXX Really this should be per-PSYCHO, but the config space
+ * XXX reads and writes give us no way to know which PSYCHO
+ * XXX in which the config space reads should occur.
+ * XXX
+ * XXX Further thought says that we cannot change this generic
+ * XXX interface, else we'd break xfree86 and other parts of the
+ * XXX kernel (but whats more important is breaking userland for
+ * XXX the ix86/Alpha/etc. people). So we should define our own
+ * XXX internal extension initially, we can compile our own user
+ * XXX apps that need to get at PCI configuration space.
+ */
+
+ /* Probe busses under PBM A. */
+ pbm_probe(&psycho->pbm_A, &memory_start);
+
+ /* Probe busses under PBM B. */
+ pbm_probe(&psycho->pbm_B, &memory_start);
+
+ pci_init_alloc_init(&memory_start);
+
+ /* Walk all PCI devices found. For each device, and
+ * PCI bridge which is not one of the PSYCHO PBM's, fill in the
+ * sysdata with a pointer to the PBM (for pci_bus's) or
+ * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's).
+ */
+ fill_in_pbm_cookies(&psycho->pbm_A);
+ fill_in_pbm_cookies(&psycho->pbm_B);
+
+ /* See what OBP has taken care of already. */
+ record_assignments(&psycho->pbm_A);
+ record_assignments(&psycho->pbm_B);
+
+ /* Now, fix it all up. */
+ psycho_final_fixup(psycho);
+
+ pci_init_alloc_fini();
+
+ return ebus_init(memory_start, memory_end);
+}
+
+/* "PCI: The emerging standard..." 8-( */
+volatile int pci_poke_in_progress = 0;
+volatile int pci_poke_faulted = 0;
+
+/* XXX Current PCI support code is broken, it assumes one master PCI config
+ * XXX space exists, on Ultra we can have many of them, especially with
+ * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire.
+ */
+static char *pci_mkaddr(unsigned char bus, unsigned char device_fn,
+ unsigned char where)
+{
+ unsigned long ret = (unsigned long) psycho_root->pci_config_space;
+
+ ret |= (1 << 24);
+ ret |= ((bus & 0xff) << 16);
+ ret |= ((device_fn & 0xff) << 8);
+ ret |= (where & 0xfc);
+ return (unsigned char *)ret;
+}
+
+static inline int out_of_range(unsigned char bus, unsigned char device_fn)
+{
+ return ((bus == 0 && PCI_SLOT(device_fn) > 4) ||
+ (bus == 1 && PCI_SLOT(device_fn) > 6) ||
+ (pci_probe_enable == 0));
+}
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char *value)
+{
+ unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+ unsigned int word, trapped;
+
+ *value = 0xff;
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ trapped = pci_poke_faulted;
+ pci_poke_faulted = 0;
+ if(!trapped) {
+ switch(where & 3) {
+ case 0:
+ *value = word & 0xff;
+ break;
+ case 1:
+ *value = (word >> 8) & 0xff;
+ break;
+ case 2:
+ *value = (word >> 16) & 0xff;
+ break;
+ case 3:
+ *value = (word >> 24) & 0xff;
+ break;
+ };
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short *value)
+{
+ unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+ unsigned int word, trapped;
+
+ *value = 0xffff;
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ trapped = pci_poke_faulted;
+ pci_poke_faulted = 0;
+ if(!trapped) {
+ switch(where & 3) {
+ case 0:
+ *value = word & 0xffff;
+ break;
+ case 2:
+ *value = (word >> 16) & 0xffff;
+ break;
+ default:
+ printk("pcibios_read_config_word: misaligned "
+ "reg [%x]\n", where);
+ break;
+ };
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int *value)
+{
+ unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+ unsigned int word, trapped;
+
+ *value = 0xffffffff;
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ trapped = pci_poke_faulted;
+ pci_poke_faulted = 0;
+ if(!trapped)
+ *value = word;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char value)
+{
+ unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+
+ /* Endianness doesn't matter but we have to get the memory
+ * barriers in there so...
+ */
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stba %0, [%1] %2\n\t"
+ "membar #Sync\n\t"
+ : /* no outputs */
+ : "r" (value), "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short value)
+{
+ unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stha %0, [%1] %2\n\t"
+ "membar #Sync\n\t"
+ : /* no outputs */
+ : "r" (value), "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int value)
+{
+ unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stwa %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (value), "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+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;
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ pcibios_read_config_byte(bus, dfn, off, &ubyte);
+ put_user(ubyte, buf);
+ break;
+ case 2:
+ pcibios_read_config_word(bus, dfn, off, &ushort);
+ put_user(ushort, buf);
+ break;
+ case 4:
+ pcibios_read_config_dword(bus, dfn, off, &uint);
+ put_user(uint, 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;
+
+ 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;
+}
+
+#endif
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index ac91df894..3df35ef14 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -609,10 +609,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long tmp;
int res;
-#if 0
- /* XXX Find out what is really going on. */
- flush_cache_all();
-#endif
/* Non-word alignment _not_ allowed on Sparc. */
if (current->tss.flags & SPARC_FLAG_32BIT) {
unsigned int x;
@@ -1055,7 +1051,7 @@ asmlinkage void syscall_trace(void)
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
current->tss.flags ^= MAGIC_CONSTANT;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
@@ -1067,9 +1063,9 @@ asmlinkage void syscall_trace(void)
current->pid, current->exit_code);
#endif
if (current->exit_code) {
- /* spin_lock_irq(&current->sigmask_lock); */
+ spin_lock_irq(&current->sigmask_lock);
current->signal |= (1 << (current->exit_code - 1));
- /* spin_unlock_irq(&current->sigmask_lock); */
+ spin_unlock_irq(&current->sigmask_lock);
}
current->exit_code = 0;
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 9f087a969..a3ac093f3 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.28 1997/06/30 10:31:39 jj Exp $
+/* $Id: rtrap.S,v 1.33 1997/08/21 09:13:22 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -36,13 +36,29 @@ rtrap: sethi %hi(bh_active), %l2
andn %l1, %l4, %l1
be,pt %icc, to_user
andn %l7, PSTATE_IE, %l7
-rt_continue: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
- ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
- ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
- brnz,pn %l2, rt_fpu_restore
- ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2
-rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
+ ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
+ andcc %l2, FPRS_FEF, %g0
+ be,pt %icc, rt_continue
+ and %l2, FPRS_DL, %l6
+ wr %g0, FPRS_FEF, %fprs
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %g5
+ membar #StoreLoad | #LoadLoad
+ brz,pn %l6, 1f
+ wr %g0, ASI_BLK_P, %asi
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16
+1: andcc %l2, FPRS_DU, %g0
+ be,pn %icc, 1f
+ wr %g5, 0, %gsr
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
+1: membar #Sync
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
+ ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
+ ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2
+ ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
mov %g6, %l6
ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4
ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5
@@ -69,10 +85,12 @@ rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
wrpr %l1, %g0, %tstate
wrpr %l2, %g0, %tpc
+ wrpr %o2, %g0, %tnpc
mov PRIMARY_CONTEXT, %l7
brnz,pn %l3, kern_rtt
- wrpr %o2, %g0, %tnpc
+ mov SECONDARY_CONTEXT, %l5
stxa %l0, [%l7] ASI_DMMU
+ stxa %l0, [%l5] ASI_DMMU
flush %l6
rdpr %wstate, %l1
@@ -88,10 +106,14 @@ rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
retry
kern_rtt: restore
retry
-to_user: sethi %hi(need_resched), %l0
- ld [%l0 + %lo(need_resched)], %l0
+to_user: lduw [%g6 + AOFF_task_processor], %o0
+ mov 1, %o1
+ sethi %hi(need_resched), %l0
+ ldx [%l0 + %lo(need_resched)], %l0
+ sllx %o1, %o0, %o1
wrpr %l7, PSTATE_IE, %pstate
- brz,pt %l0, check_signal
+ andcc %o1, %l0, %g0
+ be,pt %xcc, check_signal
ldx [%g6 + AOFF_task_signal], %l0
call schedule
@@ -99,36 +121,123 @@ to_user: sethi %hi(need_resched), %l0
ldx [%g6 + AOFF_task_signal], %l0
nop
check_signal: ldx [%g6 + AOFF_task_blocked], %o0
+ ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
andncc %l0, %o0, %g0
be,pt %xcc, check_user_wins
ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
-
mov %l5, %o2
mov %l6, %o3
call do_signal
add %sp, STACK_BIAS + REGWIN_SZ, %o1
ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
clr %l6
-check_user_wins:
- brz,pt %o2, rt_continue
- nop
+check_user_wins:brz,pt %o2, 1f
+ sethi %hi(TSTATE_PEF), %o3
call fault_in_user_windows
add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ba,a,pt %xcc, rt_continue
-rt_fpu_restore: wr %g0, FPRS_FEF, %fprs
- add %sp, PTREGS_OFF + TRACEREG_SZ, %g4
- wr %g0, ASI_BLK_P, %asi
+ sethi %hi(TSTATE_PEF), %o3
+1: andcc %l2, FPRS_FEF, %g0
+ be,a,pt %icc, rt_continue
+ andn %l1, %o3, %l1 ! If fprs.FEF is not set, disable tstate.PEF
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %o3
+ ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2
+ wr %g0, FPRS_FEF, %fprs
+ wr %o3, 0, %gsr
+ andcc %l2, SPARC_FLAG_USEDFPUL, %g0
+ bne,pn %icc, 2f
+ andcc %l2, SPARC_FLAG_USEDFPUU, %g0
+ fzero %f0
+ bne,pn %icc, 1f
+ fzero %f2
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
+ faddd %f0, %f2, %f32
+ fmuld %f0, %f2, %f34
+ faddd %f0, %f2, %f36
+ fmuld %f0, %f2, %f38
+ faddd %f0, %f2, %f40
+ fmuld %f0, %f2, %f42
+ faddd %f0, %f2, %f44
+ fmuld %f0, %f2, %f46
+ faddd %f0, %f2, %f48
+ fmuld %f0, %f2, %f50
+ faddd %f0, %f2, %f52
+ fmuld %f0, %f2, %f54
+ faddd %f0, %f2, %f56
+ fmuld %f0, %f2, %f58
+ faddd %f0, %f2, %f60
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+ ba,pt %xcc, rt_continue
+ wr %g0, FPRS_FEF, %fprs
+1: wr %g0, ASI_BLK_P, %asi
membar #StoreLoad | #LoadLoad
- ldda [%g4 + 0x000] %asi, %f0
- ldda [%g4 + 0x040] %asi, %f16
- ldda [%g4 + 0x080] %asi, %f32
- ldda [%g4 + 0x0c0] %asi, %f48
- ldx [%g4 + 0x100], %fsr
- ldx [%g4 + 0x108], %g3
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
+ membar #Sync
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+ ba,pt %xcc, rt_continue
+ wr %g0, FPRS_FEF, %fprs
+2: membar #StoreLoad | #LoadLoad
+ andcc %l2, SPARC_FLAG_USEDFPUU, %g0
+ bne,pt %icc, 3f
+ wr %g0, ASI_BLK_P, %asi
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16
+ fzero %f32
+ fzero %f34
+ faddd %f32, %f34, %f36
+ fmuld %f32, %f34, %f38
+ faddd %f32, %f34, %f40
+ fmuld %f32, %f34, %f42
+ faddd %f32, %f34, %f44
+ fmuld %f32, %f34, %f46
+ faddd %f32, %f34, %f48
+ fmuld %f32, %f34, %f50
+ faddd %f32, %f34, %f52
+ fmuld %f32, %f34, %f54
+ faddd %f32, %f34, %f56
+ fmuld %f32, %f34, %f58
+ faddd %f32, %f34, %f60
+ fmuld %f32, %f34, %f62
+ membar #Sync
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+ ba,pt %xcc, rt_continue
+ wr %g0, FPRS_FEF, %fprs
+3: ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
membar #Sync
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+ ba,pt %xcc, rt_continue
+ wr %g0, FPRS_FEF, %fprs
- b,pt %xcc, rt_after_fpu
- wr %g3, 0, %gsr
#undef PTREGS_OFF
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 7eb47e976..147c6e55d 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.11 1997/07/24 12:15:05 davem Exp $
+/* $Id: setup.c,v 1.12 1997/08/28 02:23:19 ecd Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -233,8 +233,6 @@ extern unsigned ramdisk_size;
extern int root_mountflags;
-extern void register_console(void (*proc)(const char *));
-
char saved_command_line[256];
char reboot_command[256];
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index cfc55fc2e..87241f8e3 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $
+/* $Id: signal.c,v 1.24 1997/09/02 20:53:03 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -54,12 +54,12 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
if(tp->w_saved ||
(((unsigned long)ucp) & (sizeof(unsigned long)-1)) ||
(!__access_ok((unsigned long)ucp, sizeof(*ucp))))
- do_exit(SIGSEGV);
+ goto do_sigsegv;
grp = &ucp->uc_mcontext.mc_gregs;
__get_user(pc, &((*grp)[MC_PC]));
__get_user(npc, &((*grp)[MC_NPC]));
if((pc | npc) & 3)
- do_exit(SIGSEGV);
+ goto do_sigsegv;
if(regs->u_regs[UREG_I1]) {
__get_user(current->blocked, &ucp->uc_sigmask);
current->blocked &= _BLOCKABLE;
@@ -67,7 +67,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
regs->tpc = pc;
regs->tnpc = npc;
__get_user(regs->y, &((*grp)[MC_Y]));
- __get_user(tstate, &((*grp)[MC_Y]));
+ __get_user(tstate, &((*grp)[MC_TSTATE]));
regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC));
__get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1]));
@@ -94,12 +94,23 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
__get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
if(fenab) {
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs),
- (sizeof(unsigned long) * 32));
+ unsigned long fprs;
+ __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
+ if (fprs & FPRS_DL)
+ copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs),
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16,
+ (sizeof(unsigned int) * 32));
__get_user(fpregs[32], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
__get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
- regs->fprs = FPRS_FEF;
+ regs->fprs = fprs;
+ regs->tstate |= TSTATE_PEF;
}
+ return;
+do_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
asmlinkage void sparc64_get_context(struct pt_regs *regs)
@@ -109,11 +120,11 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
mc_gregset_t *grp;
mcontext_t *mcp;
unsigned long fp, i7;
- unsigned char fenab = (current->flags & PF_USEDFPU);
+ unsigned char fenab = (current->tss.flags & SPARC_FLAG_USEDFPU);
synchronize_user_stack();
if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
- do_exit(SIGSEGV);
+ goto do_sigsegv;
mcp = &ucp->uc_mcontext;
grp = &mcp->mc_gregs;
@@ -150,12 +161,30 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
__put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab));
if(fenab) {
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
- (sizeof(unsigned long) * 32));
+ unsigned long fprs;
+
+ fprs = (regs->fprs & FPRS_FEF) |
+ (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ if (fprs & FPRS_DL)
+ copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(&(mcp->mc_fpregs.mcfpu_fregs),
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_to_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16,
+ (sizeof(unsigned int) * 32));
__put_user(fpregs[32], &(mcp->mc_fpregs.mcfpu_fsr));
__put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr));
- __put_user(FPRS_FEF, &(mcp->mc_fpregs.mcfpu_fprs));
+ __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs));
}
+ return;
+do_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
/*
@@ -233,11 +262,19 @@ static inline void
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_from_user(fpregs, &fpu->si_float_regs[0],
- (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ __get_user(fprs, &fpu->si_fprs);
+ if (fprs & FPRS_DL)
+ copy_from_user(fpregs, &fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_from_user(fpregs+16, &fpu->si_float_regs[32],
+ (sizeof(unsigned int) * 32));
__get_user(fpregs[32], &fpu->si_fsr);
__get_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = FPRS_FEF;
+ regs->fprs = fprs;
+ regs->tstate |= TSTATE_PEF;
}
void do_sigreturn(struct pt_regs *regs)
@@ -304,11 +341,26 @@ static inline void
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_to_user(&fpu->si_float_regs[0], fpregs,
- (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ fprs = (regs->fprs & FPRS_FEF) |
+ (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ if (fprs & FPRS_DL)
+ copy_to_user(&fpu->si_float_regs[0], fpregs,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_to_user(&fpu->si_float_regs[32], fpregs+16,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[32],
+ (sizeof(unsigned int) * 32));
__put_user(fpregs[32], &fpu->si_fsr);
__put_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = 0;
+ __put_user(fprs, &fpu->si_fprs);
+ regs->tstate &= ~TSTATE_PEF;
}
static inline void
@@ -321,7 +373,7 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
/* 1. Make sure everything is clean */
synchronize_user_stack();
sigframe_size = NF_ALIGNEDSZ;
- if (!(current->flags & PF_USEDFPU))
+ if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
sigframe_size -= sizeof(__siginfo_fpu_t);
sf = (struct new_signal_frame *)
@@ -339,7 +391,7 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
/* 2. Save the current process state */
copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
- if (current->flags & PF_USEDFPU) {
+ if (current->tss.flags & SPARC_FLAG_USEDFPU) {
save_fpu_state(regs, &sf->fpu_state);
__put_user((u64)&sf->fpu_state, &sf->fpu_save);
} else {
@@ -452,7 +504,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -498,7 +550,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
current->exit_code = signr;
if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 5135c2ae5..16cec2a72 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.26 1997/07/14 03:10:31 davem Exp $
+/* $Id: signal32.c,v 1.30 1997/08/29 15:51:33 jj Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -117,9 +117,17 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs)
static inline void restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs + 1);
- copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ __get_user(fprs, &fpu->si_fprs);
+ if (fprs & FPRS_DL)
+ copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
__get_user(fpregs[32], &fpu->si_fsr);
__get_user(fpregs[33], &fpu->si_gsr);
+ regs->fprs = fprs;
+ regs->tstate |= TSTATE_PEF;
}
void do_new_sigreturn32(struct pt_regs *regs)
@@ -169,8 +177,10 @@ void do_new_sigreturn32(struct pt_regs *regs)
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= psr_to_tstate_icc(psr);
+#if 0
if (psr & PSR_EF)
- regs->fprs = FPRS_FEF;
+ regs->tstate |= TSTATE_PEF;
+#endif
__get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
@@ -273,7 +283,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
__put_user(pc, &sc->sigc_pc);
__put_user(npc, &sc->sigc_npc);
psr = tstate_to_psr (regs->tstate);
- if(current->flags & PF_USEDFPU)
+ if(current->tss.flags & SPARC_FLAG_USEDFPU)
psr |= PSR_EF;
__put_user(psr, &sc->sigc_psr);
__put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
@@ -318,10 +328,22 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ fprs = (regs->fprs & FPRS_FEF) |
+ (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ if (fprs & FPRS_DL)
+ copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
__put_user(fpregs[32], &fpu->si_fsr);
__put_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = 0;
+ __put_user(fprs, &fpu->si_fprs);
+ regs->tstate &= ~TSTATE_PEF;
}
static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
@@ -335,7 +357,7 @@ static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
/* 1. Make sure everything is clean */
synchronize_user_stack();
sigframe_size = NF_ALIGNEDSZ;
- if (!(current->flags & PF_USEDFPU))
+ if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
sigframe_size -= sizeof(__siginfo_fpu_t);
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
@@ -362,7 +384,7 @@ static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
__put_user(regs->tnpc, &sf->info.si_regs.npc);
__put_user(regs->y, &sf->info.si_regs.y);
psr = tstate_to_psr (regs->tstate);
- if(current->flags & PF_USEDFPU)
+ if(current->tss.flags & SPARC_FLAG_USEDFPU)
psr |= PSR_EF;
__put_user(psr, &sf->info.si_regs.psr);
for (i = 0; i < 16; i++)
@@ -469,7 +491,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
__put_user(regs->tpc, &((*gr) [SVR4_PC]));
__put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
psr = tstate_to_psr (regs->tstate);
- if(current->flags & PF_USEDFPU)
+ if(current->tss.flags & SPARC_FLAG_USEDFPU)
psr |= PSR_EF;
__put_user(psr, &((*gr) [SVR4_PSR]));
__put_user(regs->y, &((*gr) [SVR4_Y]));
@@ -488,7 +510,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
/* Save the currently window file: */
/* 1. Link sfp->uc->gwins to our windows */
- __put_user(gw, &mc->gwin);
+ __put_user((u32)(long)gw, &mc->gwin);
/* 2. Number of windows to restore at setcontext (): */
__put_user(current->tss.w_saved, &gw->count);
@@ -506,9 +528,9 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
*/
#if 0
for(window = 0; window < current->tss.w_saved; window++) {
- __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
+ __put_user((int *) &(gw->win [window]), (int **)gw->winptr +window );
copy_to_user(&gw->win [window], &current->tss.reg_window [window], sizeof (svr4_rwindow_t));
- __put_user(0, gw->winptr [window]);
+ __put_user(0, (int *)gw->winptr + window);
}
#endif
@@ -546,7 +568,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
}
asmlinkage int
-svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
+svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
{
svr4_gregset_t *gr;
svr4_mcontext_t *mc;
@@ -555,6 +577,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
synchronize_user_stack();
if (current->tss.w_saved){
printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved);
+ lock_kernel();
do_exit (SIGSEGV);
}
if(clear_user(uc, sizeof (*uc)))
@@ -571,7 +594,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
__put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]);
__put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]);
__put_user((tstate_to_psr(regs->tstate) |
- ((current->flags & PF_USEDFPU) ? PSR_EF : 0)),
+ ((current->tss.flags & SPARC_FLAG_USEDFPU) ? PSR_EF : 0)),
&uc->mcontext.greg [SVR4_PSR]);
__put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
@@ -594,7 +617,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
/* Set the context for a svr4 application, this is Solaris way to sigreturn */
-asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs)
+asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
{
struct thread_struct *tp = &current->tss;
svr4_gregset_t *gr;
@@ -639,9 +662,10 @@ asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs)
__get_user(psr, &((*gr) [SVR4_PSR]));
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= psr_to_tstate_icc(psr);
+#if 0
if(psr & PSR_EF)
- regs->fprs = FPRS_FEF;
-
+ regs->tstate |= TSTATE_PEF;
+#endif
/* Restore g[1..7] and o[0..7] registers */
for (i = 0; i < 7; i++)
__get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
@@ -718,7 +742,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -764,7 +788,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
current->exit_code = signr;
if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 77ccf40a0..8dd471be6 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -10,11 +10,12 @@
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <asm/head.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
-#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -33,9 +34,9 @@ volatile int smp_processors_ready = 0;
unsigned long cpu_present_map = 0;
int smp_num_cpus = 1;
int smp_threads_ready = 0;
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-struct cpuinfo_sparc cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
+
static unsigned char boot_cpu_id = 0;
static int smp_activated = 0;
@@ -44,8 +45,6 @@ volatile int cpu_logical_map[NR_CPUS];
struct klock_info klock_info = { KLOCK_CLEAR, 0 };
-static volatile int smp_commenced = 0;
-
void smp_setup(char *str, int *ints)
{
/* XXX implement me XXX */
@@ -68,45 +67,64 @@ char *smp_info(void)
void smp_store_cpu_info(int id)
{
- cpu_data[id].udelay_val = loops_per_sec;
+ cpu_data[id].udelay_val = loops_per_sec;
+ cpu_data[id].irq_count = 0;
+ cpu_data[id].last_tlbversion_seen = tlb_context_cache & CTX_VERSION_MASK;
+ cpu_data[id].pgcache_size = 0;
+ cpu_data[id].pgd_cache = NULL;
+ cpu_data[id].pmd_cache = NULL;
+ cpu_data[id].pte_cache = NULL;
}
+extern void distribute_irqs(void);
+
void smp_commence(void)
{
- flush_cache_all();
- flush_tlb_all();
- smp_commenced = 1;
- flush_cache_all();
- flush_tlb_all();
+ distribute_irqs();
}
static void smp_setup_percpu_timer(void);
static volatile unsigned long callin_flag = 0;
+extern void inherit_locked_prom_mappings(int save_p);
+extern void cpu_probe(void);
+
void smp_callin(void)
{
int cpuid = hard_smp_processor_id();
- flush_cache_all();
- flush_tlb_all();
+ inherit_locked_prom_mappings(0);
+
+ __flush_cache_all();
+ __flush_tlb_all();
+
+ cpu_probe();
+
+ /* Master did this already, now is the time for us to do it. */
+ __asm__ __volatile__("
+ sethi %%hi(0x80000000), %%g1
+ sllx %%g1, 32, %%g1
+ rd %%tick, %%g2
+ add %%g2, 6, %%g2
+ andn %%g2, %%g1, %%g2
+ wrpr %%g2, 0, %%tick
+" : /* no outputs */
+ : /* no inputs */
+ : "g1", "g2");
smp_setup_percpu_timer();
+ __sti();
+
calibrate_delay();
smp_store_cpu_info(cpuid);
callin_flag = 1;
__asm__ __volatile__("membar #Sync\n\t"
"flush %%g6" : : : "memory");
- while(!task[cpuid])
- barrier();
- current = task[cpuid];
-
- while(!smp_commenced)
- barrier();
-
- __sti();
+ while(!smp_processors_ready)
+ membar("#LoadLoad");
}
extern int cpu_idle(void *unused);
@@ -130,18 +148,22 @@ void cpu_panic(void)
panic("SMP bolixed\n");
}
+static void smp_tickoffset_init(void);
+
extern struct prom_cpuinfo linux_cpus[NR_CPUS];
-extern unsigned long sparc64_cpu_startup;
+
+extern unsigned long smp_trampoline;
void smp_boot_cpus(void)
{
int cpucount = 0, i;
printk("Entering UltraSMPenguin Mode...\n");
+ smp_tickoffset_init();
__sti();
cpu_present_map = 0;
for(i = 0; i < linux_num_cpus; i++)
- cpu_present_map |= (1 << i);
+ cpu_present_map |= (1UL << i);
for(i = 0; i < NR_CPUS; i++) {
cpu_number_map[i] = -1;
cpu_logical_map[i] = -1;
@@ -160,23 +182,24 @@ void smp_boot_cpus(void)
if(i == boot_cpu_id)
continue;
- if(cpu_present_map & (1 << i)) {
+ if(cpu_present_map & (1UL << i)) {
+ unsigned long entry = (unsigned long)(&smp_trampoline);
struct task_struct *p;
int timeout;
+ entry -= KERNBASE;
kernel_thread(start_secondary, NULL, CLONE_PID);
p = task[++cpucount];
p->processor = i;
+ callin_flag = 0;
prom_startcpu(linux_cpus[i].prom_node,
- ((unsigned long)&sparc64_cpu_startup),
- ((unsigned long)p));
+ entry, ((unsigned long)p));
for(timeout = 0; timeout < 5000000; timeout++) {
- if(cpu_callin_map[i])
+ if(callin_flag)
break;
udelay(100);
}
- if(cpu_callin_map[i]) {
- /* XXX fix this */
+ if(callin_flag) {
cpu_number_map[i] = i;
cpu_logical_map[i] = i;
} else {
@@ -184,19 +207,19 @@ void smp_boot_cpus(void)
printk("Processor %d is stuck.\n", i);
}
}
- if(!(cpu_callin_map[i])) {
- cpu_present_map &= ~(1 << i);
+ if(!callin_flag) {
+ cpu_present_map &= ~(1UL << i);
cpu_number_map[i] = -1;
}
}
if(cpucount == 0) {
printk("Error: only one processor found.\n");
- cpu_present_map = (1 << smp_processor_id());
+ cpu_present_map = (1UL << smp_processor_id());
} else {
unsigned long bogosum = 0;
for(i = 0; i < NR_CPUS; i++) {
- if(cpu_present_map & (1 << i))
+ if(cpu_present_map & (1UL << i))
bogosum += cpu_data[i].udelay_val;
}
printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
@@ -207,27 +230,39 @@ void smp_boot_cpus(void)
smp_num_cpus = cpucount + 1;
}
smp_processors_ready = 1;
+ membar("#StoreStore | #StoreLoad");
}
-/* XXX deprecated interface... */
+/* We don't even need to do anything, the only generic message pass done
+ * anymore is to stop all cpus during a panic(). When the user drops to
+ * the PROM prompt, the firmware will send the other cpu's it's MONDO
+ * vector anyways, so doing anything special here is pointless.
+ *
+ * This whole thing should go away anyways...
+ */
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
- printk("smp_message_pass() called, this is bad, spinning.\n");
- __sti();
- while(1)
- barrier();
}
+/* #define XCALL_DEBUG */
+
static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
{
- u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
-
+ u64 result, target = (((unsigned long)linux_cpus[cpu].mid) << 14) | 0x70;
+ int stuck;
+
+#ifdef XCALL_DEBUG
+ printk("CPU[%d]: xcall(data[%016lx:%016lx:%016lx],tgt[%016lx])\n",
+ smp_processor_id(), data0, data1, data2, target);
+#endif
+again:
__asm__ __volatile__("
wrpr %0, %1, %%pstate
wr %%g0, %2, %%asi
stxa %3, [0x40] %%asi
stxa %4, [0x50] %%asi
stxa %5, [0x60] %%asi
+ membar #Sync
stxa %%g0, [%6] %%asi
membar #Sync"
: /* No outputs */
@@ -235,27 +270,46 @@ static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, in
"r" (data0), "r" (data1), "r" (data2), "r" (target));
/* NOTE: PSTATE_IE is still clear. */
+ stuck = 100000;
do {
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (result)
: "i" (ASI_INTR_DISPATCH_STAT));
+ if(result == 0) {
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+ : : "r" (pstate));
+ return;
+ }
+ stuck -= 1;
+ if(stuck == 0)
+ break;
} while(result & 0x1);
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate));
- if(result & 0x2)
- panic("Penguin NACK's master!");
+ if(stuck == 0) {
+#ifdef XCALL_DEBUG
+ printk("CPU[%d]: mondo stuckage result[%016lx]\n",
+ smp_processor_id(), result);
+#endif
+ } else {
+#ifdef XCALL_DEBUG
+ printk("CPU[%d]: Penguin %d NACK's master.\n", smp_processor_id(), cpu);
+#endif
+ udelay(2);
+ goto again;
+ }
}
void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
{
if(smp_processors_ready) {
- unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+ unsigned long mask = (cpu_present_map & ~(1UL<<smp_processor_id()));
u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
int i, ncpus = smp_num_cpus;
__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
for(i = 0; i < ncpus; i++) {
- if(mask & (1 << i))
+ if(mask & (1UL << i))
xcall_deliver(data0, data1, data2, pstate, i);
}
/* NOTE: Caller runs local copy on master. */
@@ -266,7 +320,14 @@ extern unsigned long xcall_flush_tlb_page;
extern unsigned long xcall_flush_tlb_mm;
extern unsigned long xcall_flush_tlb_range;
extern unsigned long xcall_flush_tlb_all;
+extern unsigned long xcall_tlbcachesync;
extern unsigned long xcall_flush_cache_all;
+extern unsigned long xcall_report_regs;
+
+void smp_report_regs(void)
+{
+ smp_cross_call(&xcall_report_regs, 0, 0, 0);
+}
void smp_flush_cache_all(void)
{
@@ -280,11 +341,33 @@ void smp_flush_tlb_all(void)
__flush_tlb_all();
}
+static void smp_cross_call_avoidance(struct mm_struct *mm)
+{
+ spin_lock(&scheduler_lock);
+ get_new_mmu_context(mm, &tlb_context_cache);
+ mm->cpu_vm_mask = (1UL << smp_processor_id());
+ if(current->tss.current_ds) {
+ u32 ctx = mm->context & 0x1fff;
+
+ current->tss.ctx = ctx;
+ spitfire_set_secondary_context(ctx);
+ __asm__ __volatile__("flush %g6");
+ }
+ spin_unlock(&scheduler_lock);
+}
+
void smp_flush_tlb_mm(struct mm_struct *mm)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+ if(mm == current->mm && mm->count == 1) {
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ return smp_cross_call_avoidance(mm);
+ }
+ smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+local_flush_and_out:
__flush_tlb_mm(ctx);
}
@@ -292,22 +375,101 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+ if(mm == current->mm && mm->count == 1) {
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ return smp_cross_call_avoidance(mm);
+ }
+ smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+local_flush_and_out:
__flush_tlb_range(ctx, start, end);
}
-void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
{
- struct mm_struct *mm = vma->vm_mm;
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+ if(mm == current->mm && mm->count == 1) {
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ return smp_cross_call_avoidance(mm);
+ }
+#if 0 /* XXX Disabled until further notice... */
+ else if(mm != current->mm && mm->count == 1) {
+ /* Try to handle two special cases to avoid cross calls
+ * in common scenerios where we are swapping process
+ * pages out.
+ */
+ if((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK)
+ return; /* It's dead, nothing to do. */
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ }
+#endif
+ smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+
+local_flush_and_out:
__flush_tlb_page(ctx, page);
}
-static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+/* CPU capture. */
+#define CAPTURE_DEBUG
+extern unsigned long xcall_capture;
+
+static atomic_t smp_capture_depth = ATOMIC_INIT(0);
+static atomic_t smp_capture_registry = ATOMIC_INIT(0);
+static unsigned long penguins_are_doing_time = 0;
+
+void smp_capture(void)
+{
+ int result = atomic_add_return(1, &smp_capture_depth);
+
+ membar("#StoreStore | #LoadStore");
+ if(result == 1) {
+ int ncpus = smp_num_cpus;
+
+#ifdef CAPTURE_DEBUG
+ printk("CPU[%d]: Sending penguins to jail...", smp_processor_id());
+#endif
+ penguins_are_doing_time = 1;
+ membar("#StoreStore | #LoadStore");
+ atomic_inc(&smp_capture_registry);
+ smp_cross_call(&xcall_capture, 0, 0, 0);
+ while(atomic_read(&smp_capture_registry) != ncpus)
+ membar("#LoadLoad");
+#ifdef CAPTURE_DEBUG
+ printk("done\n");
+#endif
+ }
+}
+
+void smp_release(void)
+{
+ if(atomic_dec_and_test(&smp_capture_depth)) {
+#ifdef CAPTURE_DEBUG
+ printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
+ smp_processor_id());
+#endif
+ penguins_are_doing_time = 0;
+ membar("#StoreStore | #StoreLoad");
+ atomic_dec(&smp_capture_registry);
+ }
+}
+
+/* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
+ * can service tlb flush xcalls...
+ */
+void smp_penguin_jailcell(void)
+{
+ flushw_user();
+ atomic_inc(&smp_capture_registry);
+ membar("#StoreLoad | #StoreStore");
+ while(penguins_are_doing_time)
+ membar("#LoadLoad");
+ atomic_dec(&smp_capture_registry);
+}
static inline void sparc64_do_profile(unsigned long pc)
{
@@ -317,59 +479,100 @@ static inline void sparc64_do_profile(unsigned long pc)
pc -= (unsigned long) &_stext;
pc >>= prof_shift;
- spin_lock(&ticker_lock);
- if(pc < prof_len)
- prof_buffer[pc]++;
- else
- prof_buffer[prof_len - 1]++;
- spin_unlock(&ticker_lock);
+ if(pc >= prof_len)
+ pc = prof_len - 1;
+ atomic_inc((atomic_t *)&prof_buffer[pc]);
}
}
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
+static unsigned long real_tick_offset, current_tick_offset;
+
+#define prof_multiplier(__cpu) cpu_data[(__cpu)].multiplier
+#define prof_counter(__cpu) cpu_data[(__cpu)].counter
extern void update_one_process(struct task_struct *p, unsigned long ticks,
unsigned long user, unsigned long system);
void smp_percpu_timer_interrupt(struct pt_regs *regs)
{
+ unsigned long compare, tick;
int cpu = smp_processor_id();
int user = user_mode(regs);
- /* XXX clear_profile_irq(cpu); */
- if(!user)
- sparc64_do_profile(regs->tpc);
- if(!--prof_counter[cpu]) {
- if(current->pid) {
- update_one_process(current, 1, user, !user);
- if(--current->counter < 0) {
- current->counter = 0;
- need_resched = 1;
- }
-
- spin_lock(&ticker_lock);
- if(user) {
- if(current->priority < DEF_PRIORITY)
- kstat.cpu_nice++;
- else
- kstat.cpu_user++;
- } else {
- kstat.cpu_system++;
+ clear_softint((1UL << 0));
+ do {
+ if(!user)
+ sparc64_do_profile(regs->tpc);
+ if(!--prof_counter(cpu)) {
+ if(current->pid) {
+ unsigned int *inc_me;
+
+ update_one_process(current, 1, user, !user);
+ if(--current->counter < 0) {
+ current->counter = 0;
+ resched_force();
+ }
+
+ if(user) {
+ if(current->priority < DEF_PRIORITY)
+ inc_me = &kstat.cpu_nice;
+ else
+ inc_me = &kstat.cpu_user;
+ } else {
+ inc_me = &kstat.cpu_system;
+ }
+ atomic_inc((atomic_t *)inc_me);
}
- spin_unlock(&ticker_lock);
+ prof_counter(cpu) = prof_multiplier(cpu);
}
- prof_counter[cpu] = prof_multiplier[cpu];
- }
+ __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
+ "add %0, %2, %0\n\t"
+ "wr %0, 0x0, %%tick_cmpr\n\t"
+ "rd %%tick, %1"
+ : "=&r" (compare), "=r" (tick)
+ : "r" (current_tick_offset));
+ } while (tick >= compare);
}
static void smp_setup_percpu_timer(void)
{
- /* XXX implement me */
+ int cpu = smp_processor_id();
+
+ prof_counter(cpu) = prof_multiplier(cpu) = 1;
+
+ __asm__ __volatile__("rd %%tick, %%g1\n\t"
+ "add %%g1, %0, %%g1\n\t"
+ "wr %%g1, 0x0, %%tick_cmpr"
+ : /* no outputs */
+ : "r" (current_tick_offset)
+ : "g1");
+}
+
+static void smp_tickoffset_init(void)
+{
+ int node;
+
+ node = linux_cpus[0].prom_node;
+ real_tick_offset = prom_getint(node, "clock-frequency");
+ real_tick_offset = real_tick_offset / HZ;
+ current_tick_offset = real_tick_offset;
}
int setup_profiling_timer(unsigned int multiplier)
{
- /* XXX implement me */
+ unsigned long flags;
+ int i;
+
+ if((!multiplier) || (real_tick_offset / multiplier) < 1000)
+ return -EINVAL;
+
+ save_and_cli(flags);
+ for(i = 0; i < NR_CPUS; i++) {
+ if(cpu_present_map & (1UL << i))
+ prof_multiplier(i) = multiplier;
+ }
+ current_tick_offset = (real_tick_offset / multiplier);
+ restore_flags(flags);
+
return 0;
}
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 990202bac..c1ceacc3f 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.11 1997/07/14 23:58:20 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.21 1997/09/03 12:29:07 jj Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/in6.h>
#include <asm/oplib.h>
#include <asm/delay.h>
@@ -28,11 +29,13 @@
#include <asm/ptrace.h>
#include <asm/user.h>
#include <asm/uaccess.h>
+#include <asm/checksum.h>
#ifdef CONFIG_SBUS
#include <asm/sbus.h>
#include <asm/dma.h>
#endif
#include <asm/a.out.h>
+#include <asm/svr4.h>
struct poll {
int fd;
@@ -45,18 +48,36 @@ extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
void _sigpause_common (unsigned int set, struct pt_regs *);
extern void *__bzero_1page(void *);
extern void *__bzero(void *, size_t);
+extern void *__bzero_noasi(void *, size_t);
extern void *__memscan_zero(void *, size_t);
extern void *__memscan_generic(void *, int, size_t);
extern int __memcmp(const void *, const void *, __kernel_size_t);
extern int __strncmp(const char *, const char *, __kernel_size_t);
-extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
extern char saved_command_line[];
-
+extern char *getname32(u32 name);
+extern void linux_sparc_syscall(void);
+extern void rtrap(void);
+extern void show_regs(struct pt_regs *);
+extern void solaris_syscall(void);
+extern void syscall_trace(void);
+extern u32 sunos_sys_table[], sys_call_table32[];
+extern void tl0_solaris(void);
+extern void sys_sigsuspend(void);
+extern int sys_getppid(void);
+extern int svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
+extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
+extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
+
extern void bcopy (const char *, char *, int);
extern int __ashrdi3(int, int);
extern void dump_thread(struct pt_regs *, struct user *);
+#ifdef __SMP__
+extern spinlock_t scheduler_lock;
+#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:
@@ -70,7 +91,17 @@ __attribute__((section("__ksymtab"))) = \
/* used by various drivers */
#ifdef __SMP__
+EXPORT_SYMBOL(scheduler_lock);
+EXPORT_SYMBOL(global_bh_lock);
EXPORT_SYMBOL(klock_info);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL_PRIVATE(global_cli);
+EXPORT_SYMBOL_PRIVATE(global_sti);
+EXPORT_SYMBOL_PRIVATE(global_restore_flags);
+#else
+EXPORT_SYMBOL(local_irq_count);
#endif
EXPORT_SYMBOL_PRIVATE(_lock_kernel);
EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
@@ -81,12 +112,13 @@ EXPORT_SYMBOL(mstk48t02_regs);
EXPORT_SYMBOL(request_fast_irq);
EXPORT_SYMBOL(sparc_alloc_io);
EXPORT_SYMBOL(sparc_free_io);
-EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(__sparc64_bh_counter);
EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
EXPORT_SYMBOL(mmu_get_scsi_sgl);
EXPORT_SYMBOL(mmu_get_scsi_one);
EXPORT_SYMBOL(sparc_dvma_malloc);
+EXPORT_SYMBOL(mmu_release_scsi_one);
+EXPORT_SYMBOL(mmu_release_scsi_sgl);
#if CONFIG_SBUS
EXPORT_SYMBOL(SBus_chain);
EXPORT_SYMBOL(dma_chain);
@@ -139,6 +171,25 @@ EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strspn);
+#ifdef CONFIG_SOLARIS_EMUL_MODULE
+EXPORT_SYMBOL(getname32);
+EXPORT_SYMBOL(linux_sparc_syscall);
+EXPORT_SYMBOL(rtrap);
+EXPORT_SYMBOL(show_regs);
+EXPORT_SYMBOL(solaris_syscall);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(sunos_sys_table);
+EXPORT_SYMBOL(sys_call_table32);
+EXPORT_SYMBOL(tl0_solaris);
+EXPORT_SYMBOL(sys_sigsuspend);
+EXPORT_SYMBOL(sys_getppid);
+EXPORT_SYMBOL(svr4_getcontext);
+EXPORT_SYMBOL(svr4_setcontext);
+EXPORT_SYMBOL(linux_cpus);
+EXPORT_SYMBOL(sys_ioctl);
+EXPORT_SYMBOL(sys32_ioctl);
+#endif
+
/* Special internal versions of library functions. */
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memset);
@@ -150,12 +201,13 @@ EXPORT_SYMBOL(__memcmp);
EXPORT_SYMBOL(__strncmp);
EXPORT_SYMBOL(__memmove);
-EXPORT_SYMBOL(__csum_partial_copy_sparc_generic);
+EXPORT_SYMBOL(csum_partial_copy_sparc64);
/* Moving data to/from userspace. */
EXPORT_SYMBOL(__copy_to_user);
EXPORT_SYMBOL(__copy_from_user);
EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(__bzero_noasi);
/* No version information on this, heavily used in inline asm,
* and will always be 'void __ret_efault(void)'.
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index ca0faec5d..37c541755 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.2 1997/07/25 01:50:47 ralf Exp $
+/* $Id: sys32.S,v 1.3 1997/08/22 20:11:47 davem Exp $
* sys32.S: I-cache tricks for 32-bit compatability layer simple
* conversions.
*
@@ -73,7 +73,7 @@ sys32_mremap:
.globl sys32_readlink, sys32_unlink, sys32_rmdir, sys32_symlink
.globl sys32_link, sys32_rename, sys32_truncate, sys32_ftruncate
.globl sys32_chroot, sys32_chmod, sys32_chown, sys32_creat
- .globl sys32_mkdir, sys32_mknod, sys32_utimes, sys32_ustat
+ .globl sys32_mkdir, sys32_mknod, sys32_ustat
sys32_read:
srl %o1, 0, %o1
mov %o7, %g1
@@ -202,12 +202,6 @@ sys32_mknod:
srl %o2, 16, %o2
call sys_mknod
mov %g1, %o7
-sys32_utimes:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_utimes
- mov %g1, %o7
sys32_ustat:
srl %o1, 0, %o1
mov %o7, %g1
@@ -285,24 +279,9 @@ sys32_getsockopt:
call sys_setsockopt
mov %g1, %o7
- .align 32
- .globl sys32_gettimeofday, sys32_settimeofday
-sys32_gettimeofday:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_gettimeofday
- mov %g1, %o7
-sys32_settimeofday:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_settimeofday
- mov %g1, %o7
-
.globl sys32_bdflush, sys32_uselib, sys32_umount, sys32_syslog
- .globl sys32_personality, sys32_waitpid, sys32_getitimer
- .globl sys32_setitimer, sys32_sched_setscheduler
+ .globl sys32_personality, sys32_waitpid
+ .globl sys32_sched_setscheduler
.globl sys32_sched_setparam, sys32_sched_getparam, sys32_signal
.globl sys32_reboot, sys32_acct, sys32_newuname, sys32_olduname
.globl sys32_sethostname, sys32_gethostname, sys32_setdomainname
@@ -338,17 +317,6 @@ sys32_waitpid:
mov %o7, %g1
call sys_waitpid
mov %g1, %o7
-sys32_getitimer:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_getitimer
- mov %g1, %o7
-sys32_setitimer:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- call sys_setitimer
- mov %g1, %o7
sys32_sched_setscheduler:
srl %o2, 0, %o2
mov %o7, %g1
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index c827df7a1..0ec6de167 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.2 1997/07/05 09:52:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.5 1997/09/03 12:29:05 jj Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -191,9 +191,12 @@ out:
asmlinkage unsigned long
c_sys_nis_syscall (struct pt_regs *regs)
{
+ static int count=0;
lock_kernel();
- printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
- show_regs (regs);
+ if (++count <= 20) { /* Don't make the system unusable, if someone goes stuck */
+ printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
+ show_regs (regs);
+ }
unlock_kernel();
return -ENOSYS;
}
@@ -220,46 +223,36 @@ asmlinkage int
sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
{
struct sigaction new_sa, *p;
- int err = -EINVAL;
- lock_kernel();
if(signum < 0) {
current->tss.new_signal = 1;
signum = -signum;
}
-
if (signum<1 || signum>32)
- goto out;
+ return -EINVAL;
p = signum - 1 + current->sig->action;
if (action) {
- err = -EINVAL;
if (signum==SIGKILL || signum==SIGSTOP)
- goto out;
- err = -EFAULT;
+ return -EINVAL;
if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
- goto out;
+ return -EFAULT;
if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
- err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
+ int err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
if (err)
- goto out;
+ return err;
}
}
-
if (oldaction) {
- err = -EFAULT;
if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
- goto out;
+ return -EFAULT;
}
-
if (action) {
+ spin_lock_irq(&current->sig->siglock);
*p = new_sa;
check_pending(signum);
+ spin_unlock_irq(&current->sig->siglock);
}
-
- err = 0;
-out:
- unlock_kernel();
- return err;
+ return 0;
}
/* only AP+ systems have sys_aplib */
@@ -267,3 +260,15 @@ asmlinkage int sys_aplib(void)
{
return -ENOSYS;
}
+
+asmlinkage int solaris_syscall(struct pt_regs *regs)
+{
+ lock_kernel();
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+ printk ("For Solaris binary emulation you need solaris module loaded\n");
+ show_regs (regs);
+ send_sig(SIGSEGV, current, 1);
+ unlock_kernel();
+ return 0;
+}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index b6ca9448c..e2c199f60 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.44 1997/07/20 09:18:47 davem Exp $
+/* $Id: sys_sparc32.c,v 1.55 1997/09/04 01:54:51 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -44,6 +44,7 @@
#include <asm/ipc.h>
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
+#include <asm/semaphore.h>
/* As gcc will warn about casting u32 to some ptr, we have to cast it to
* unsigned long first, and that's what is A() for.
@@ -53,6 +54,33 @@
*/
#define A(x) ((unsigned long)x)
+extern char * getname_quicklist;
+extern int getname_quickcount;
+extern struct semaphore getname_quicklock;
+extern int kerneld_msqid;
+
+/* Tuning: increase locality by reusing same pages again...
+ * if getname_quicklist becomes too long on low memory machines, either a limit
+ * should be added or after a number of cycles some pages should
+ * be released again ...
+ */
+static inline char * get_page(void)
+{
+ char * res;
+ down(&getname_quicklock);
+ res = getname_quicklist;
+ if (res) {
+ getname_quicklist = *(char**)res;
+ getname_quickcount--;
+ }
+ else
+ res = (char*)__get_free_page(GFP_KERNEL);
+ up(&getname_quicklock);
+ return res;
+}
+
+#define putname32 putname
+
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
@@ -74,44 +102,67 @@ static inline int do_getname32(u32 filename, char *page)
return retval;
}
-/* This is a single page for faster getname.
- * If the page is available when entering getname, use it.
- * If the page is not available, call __get_free_page instead.
- * This works even though do_getname can block (think about it).
- * -- Michael Chastain, based on idea of Linus Torvalds, 1 Dec 1996.
- * We don't use the common getname/putname from namei.c, so that
- * this still works well, as every routine which calls getname32
- * will then call getname, then putname and then putname32.
- */
-static unsigned long name_page_cache32 = 0;
+char * getname32(u32 filename)
+{
+ char *tmp, *result;
+
+ result = ERR_PTR(-ENOMEM);
+ tmp = get_page();
+ if (tmp) {
+ int retval = do_getname32(filename, tmp);
-void putname32(char * name)
+ result = tmp;
+ if (retval < 0) {
+ putname32(tmp);
+ result = ERR_PTR(retval);
+ }
+ }
+ return result;
+}
+
+/* 32-bit timeval and related flotsam. */
+
+struct timeval32
{
- if (name_page_cache32 == 0)
- name_page_cache32 = (unsigned long) name;
- else
- free_page((unsigned long) name);
+ int tv_sec, tv_usec;
+};
+
+struct itimerval32
+{
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
+
+static inline long get_tv32(struct timeval *o, struct timeval32 *i)
+{
+ return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) ||
+ (__get_user(o->tv_sec, &i->tv_sec) |
+ __get_user(o->tv_usec, &i->tv_usec)));
}
-int getname32(u32 filename, char **result)
+static inline long put_tv32(struct timeval32 *o, struct timeval *i)
{
- unsigned long page;
- int retval;
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+ (__put_user(i->tv_sec, &o->tv_sec) |
+ __put_user(i->tv_usec, &o->tv_usec)));
+}
- page = name_page_cache32;
- name_page_cache32 = 0;
- if (!page) {
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- }
+static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
+{
+ return (!access_ok(VERIFY_READ, i32, sizeof(*i32)) ||
+ (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
+ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
+ __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
+ __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
+}
- retval = do_getname32(filename, (char *) page);
- if (retval < 0)
- putname32( (char *) page );
- else
- *result = (char *) page;
- return retval;
+static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
+{
+ return (!access_ok(VERIFY_WRITE, i32, sizeof(*i32)) ||
+ (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
+ __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
+ __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
+ __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
}
extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
@@ -266,14 +317,25 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
switch (call) {
case MSGSND:
{
- struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+ struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL);
if (!p) err = -ENOMEM;
else {
- if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
- err = -EFAULT;
- else {
+ err = 0;
+ if (first == kerneld_msqid) {
+ *(int *)p->mtext = 0;
+ if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_from_user(&p->mtext[4], &(((struct msgbuf32 *)A(ptr))->mtext[0]), 4) ||
+ __copy_from_user(&p->mtext[8], &(((struct msgbuf32 *)A(ptr))->mtext[4]), second-4))
+ err = -EFAULT;
+ else
+ second += 4;
+ } else {
+ if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
+ err = -EFAULT;
+ }
+ if (!err) {
unsigned long old_fs = get_fs();
set_fs (KERNEL_DS);
err = sys_msgsnd (first, p, second, third);
@@ -287,6 +349,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
{
struct msgbuf *p;
unsigned long old_fs;
+ long msgtyp = fifth;
if (!version) {
struct ipc_kludge tmp;
@@ -297,20 +360,35 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
if(copy_from_user(&tmp,(struct ipc_kludge *)A(ptr), sizeof (tmp)))
goto out;
ptr = tmp.msgp;
- fifth = tmp.msgtyp;
+ msgtyp = tmp.msgtyp;
}
- p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+
+ p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL);
if (!p) {
err = -EFAULT;
goto out;
}
+
old_fs = get_fs();
set_fs (KERNEL_DS);
- err = sys_msgrcv (first, p, second, fifth, third);
+ err = sys_msgrcv (first, p, second + 4, msgtyp, third);
set_fs (old_fs);
- if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, second))
- err = -EFAULT;
+
+ if (err < 0)
+ goto out;
+
+ if (first == kerneld_msqid) {
+ if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[0]), &p->mtext[4], 4) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[4]), &p->mtext[8], err-8))
+ err = -EFAULT;
+ else
+ err -= 4;
+ } else {
+ if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err))
+ err = -EFAULT;
+ }
kfree (p);
goto out;
}
@@ -472,8 +550,9 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
err = -EINVAL;
goto out;
}
- else
- err = -EINVAL;
+
+ err = -EINVAL;
+
out:
unlock_kernel();
return err;
@@ -565,8 +644,9 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
return sys_quotactl(cmd, (const char *)A(special),
id, (caddr_t)A(addr));
}
- err = getname32 (special, &spec);
- if (err) return err;
+ spec = getname32 (special);
+ err = PTR_ERR(spec);
+ if (IS_ERR(spec)) return err;
old_fs = get_fs ();
set_fs (KERNEL_DS);
err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)A(addr));
@@ -608,8 +688,9 @@ asmlinkage int sys32_statfs(u32 path, u32 buf)
unsigned long old_fs = get_fs();
char *pth;
- ret = getname32 (path, &pth);
- if (!ret) {
+ pth = getname32 (path);
+ ret = PTR_ERR(pth);
+ if (!IS_ERR(pth)) {
set_fs (KERNEL_DS);
ret = sys_statfs((const char *)pth, &s);
set_fs (old_fs);
@@ -651,8 +732,9 @@ asmlinkage int sys32_utime(u32 filename, u32 times)
if (get_user (t.actime, &(((struct utimbuf32 *)A(times))->actime)) ||
__get_user (t.modtime, &(((struct utimbuf32 *)A(times))->modtime)))
return -EFAULT;
- ret = getname32 (filename, &filenam);
- if (!ret) {
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_utime(filenam, &t);
@@ -1010,7 +1092,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
lock_kernel ();
p = (char *)__get_free_page (GFP_KERNEL);
if (!p)
- goto out;
+ goto out_nofree;
q = (u32 *)p;
Inp = (u32 *)A(inp);
@@ -1019,7 +1101,13 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
ret = -EFAULT;
- nn = (n + (8 * sizeof(unsigned long)) - 1) / (8 * sizeof (unsigned long));
+ nn = (n + (8 * sizeof(long)) - 1) / (8 * sizeof(long));
+ if (inp && verify_area(VERIFY_WRITE, Inp, nn*sizeof(long)))
+ goto out;
+ if (outp && verify_area(VERIFY_WRITE, Outp, nn*sizeof(long)))
+ goto out;
+ if (exp && verify_area(VERIFY_WRITE, Exp, nn*sizeof(long)))
+ goto out;
for (i = 0; i < nn; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
if(inp && (__get_user (q[1], Inp) || __get_user (q[0], Inp+1)))
goto out;
@@ -1033,7 +1121,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
ktvp = NULL;
if(tvp) {
- if(copy_from_user(&kern_tv, (struct timeval *)A(tvp), sizeof(*ktvp)))
+ if (get_tv32(&kern_tv, (struct timeval32 *)A(tvp)))
goto out;
ktvp = &kern_tv;
}
@@ -1048,8 +1136,12 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
ktvp);
set_fs (old_fs);
- if(tvp && !(current->personality & STICKY_TIMEOUTS))
- copy_to_user((struct timeval *)A(tvp), &kern_tv, sizeof(*ktvp));
+ if(tvp && !(current->personality & STICKY_TIMEOUTS)) {
+ if (put_tv32((struct timeval32 *)A(tvp), &kern_tv)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
q = (u32 *)p;
Inp = (u32 *)A(inp);
@@ -1079,6 +1171,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
}
out:
free_page ((unsigned long)p);
+out_nofree:
unlock_kernel();
return ret;
}
@@ -1111,8 +1204,9 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
char *filenam;
unsigned long old_fs = get_fs();
- ret = getname32 (filename, &filenam);
- if (!ret) {
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
set_fs (KERNEL_DS);
ret = sys_newstat(filenam, &s);
set_fs (old_fs);
@@ -1132,8 +1226,9 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
char *filenam;
unsigned long old_fs = get_fs();
- ret = getname32 (filename, &filenam);
- if (!ret) {
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
set_fs (KERNEL_DS);
ret = sys_newlstat(filenam, &s);
set_fs (old_fs);
@@ -1239,12 +1334,12 @@ static void *do_smb_super_data_conv(void *raw_data)
struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
- s->dir_mode = s32->dir_mode;
- s->file_mode = s32->file_mode;
- s->gid = s32->gid;
- s->uid = s32->uid;
- memmove (&s->addr, &s32->addr, (((long)&s->uid) - ((long)&s->addr)));
+ s->version = s32->version;
s->mounted_uid = s32->mounted_uid;
+ s->uid = s32->uid;
+ s->gid = s32->gid;
+ s->file_mode = s32->file_mode;
+ s->dir_mode = s32->dir_mode;
return raw_data;
}
@@ -1344,8 +1439,8 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags,
}
struct rusage32 {
- struct timeval ru_utime;
- struct timeval ru_stime;
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
s32 ru_maxrss;
s32 ru_ixrss;
s32 ru_idrss;
@@ -1703,7 +1798,7 @@ struct timex32 {
s32 constant;
s32 precision;
s32 tolerance;
- struct timeval time;
+ struct timeval32 time;
s32 tick;
s32 ppsfreq;
s32 jitter;
@@ -2110,54 +2205,45 @@ asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction)
{
struct sigaction32 new_sa, old_sa;
struct sigaction *p;
- int err = -EINVAL;
- lock_kernel();
if(signum < 0) {
current->tss.new_signal = 1;
signum = -signum;
}
-
if (signum<1 || signum>32)
- goto out;
+ return -EINVAL;
p = signum - 1 + current->sig->action;
if (action) {
- err = -EINVAL;
if (signum==SIGKILL || signum==SIGSTOP)
- goto out;
- err = -EFAULT;
+ return -EINVAL;
if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32)))
- goto out;
+ return -EFAULT;
if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL &&
((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) {
- err = verify_area(VERIFY_READ, (__sighandler_t)A(new_sa.sa_handler), 1);
+ int err = verify_area(VERIFY_READ,
+ (__sighandler_t)A(new_sa.sa_handler), 1);
if (err)
- goto out;
+ return err;
}
}
-
if (oldaction) {
- err = -EFAULT;
old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
old_sa.sa_mask = (sigset_t32)(p->sa_mask);
old_sa.sa_flags = (unsigned)(p->sa_flags);
old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer);
if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32)))
- goto out;
+ return -EFAULT;
}
-
if (action) {
+ spin_lock_irq(&current->sig->siglock);
p->sa_handler = (__sighandler_t)A(new_sa.sa_handler);
p->sa_mask = (sigset_t)(new_sa.sa_mask);
p->sa_flags = new_sa.sa_flags;
p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer);
check_pending(signum);
+ spin_unlock_irq(&current->sig->siglock);
}
-
- err = 0;
-out:
- unlock_kernel();
- return err;
+ return 0;
}
/*
@@ -2298,7 +2384,7 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
base = 1;
lock_kernel();
- filename = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0]);
+ filename = getname((char *)A((u32)regs->u_regs[base + UREG_I0]));
error = PTR_ERR(filename);
if(IS_ERR(filename))
goto out;
@@ -2310,6 +2396,7 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
if(!error) {
fprs_write(0);
regs->fprs = 0;
+ regs->tstate &= ~TSTATE_PEF;
}
out:
unlock_kernel();
@@ -2369,8 +2456,12 @@ asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_si
case QM_MODULES:
case QM_REFS:
case QM_DEPS:
- if (name_user && (ret = getname32 (name_user, &usernam)))
- return ret;
+ if (name_user) {
+ usernam = getname32 (name_user);
+ ret = PTR_ERR(usernam);
+ if (IS_ERR(usernam))
+ return ret;
+ }
buff = kmalloc (bufsiz, GFP_KERNEL);
if (!buff) {
if (name_user) putname32 (usernam);
@@ -2431,8 +2522,12 @@ qmsym_toshort:
if (name_user) putname32 (usernam);
return ret;
case QM_INFO:
- if (name_user && (ret = getname32 (name_user, &usernam)))
- return ret;
+ if (name_user) {
+ usernam = getname32 (name_user);
+ ret = PTR_ERR(usernam);
+ if (IS_ERR(usernam))
+ return ret;
+ }
set_fs (KERNEL_DS);
ret = sys_query_module (usernam, which, (char *)&mi, sizeof (mi), &val);
set_fs (old_fs);
@@ -2720,9 +2815,7 @@ static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res
return 0;
}
-extern asmlinkage int sys_nfsservctl(int cmd,
- struct nfsctl_arg *arg,
- union nfsctl_res *resp);
+extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp);
int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp)
{
@@ -2793,3 +2886,106 @@ done:
kfree(kres);
return err;
}
+
+/* Translations due to time_t size differences. Which affects all
+ sorts of things, like timeval and itimerval. */
+
+extern struct timezone sys_tz;
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
+asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
+{
+ if (tv) {
+ struct timeval ktv;
+ do_gettimeofday(&ktv);
+ if (put_tv32((struct timeval32 *)A(tv), &ktv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_to_user((void*)A(tz), &sys_tz, sizeof(sys_tz)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
+{
+ struct timeval ktv;
+ struct timezone ktz;
+
+ if (tv) {
+ if (get_tv32(&ktv, (struct timeval32 *)A(tv)))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_from_user(&ktz, (void*)A(tz), sizeof(ktz)))
+ return -EFAULT;
+ }
+
+ return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
+}
+
+extern int do_getitimer(int which, struct itimerval *value);
+
+asmlinkage int sys32_getitimer(int which, u32 it)
+{
+ struct itimerval kit;
+ int error;
+
+ error = do_getitimer(which, &kit);
+ if (!error && put_it32((struct itimerval32 *)A(it), &kit))
+ error = -EFAULT;
+
+ return error;
+}
+
+extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+
+asmlinkage int sys32_setitimer(int which, u32 in, u32 out)
+{
+ struct itimerval kin, kout;
+ int error;
+
+ if (in) {
+ if (get_it32(&kin, (struct itimerval32 *)A(in)))
+ return -EFAULT;
+ } else
+ memset(&kin, 0, sizeof(kin));
+
+ error = do_setitimer(which, &kin, out ? &kout : NULL);
+ if (error || !out)
+ return error;
+ if (put_it32((struct itimerval32 *)A(out), &kout))
+ return -EFAULT;
+
+ return 0;
+
+}
+
+asmlinkage int sys_utimes(char *, struct timeval *);
+
+asmlinkage int sys32_utimes(u32 filename, u32 tvs)
+{
+ char *kfilename;
+ struct timeval ktvs[2];
+ unsigned long old_fs;
+ int ret;
+
+ kfilename = getname32(filename);
+ ret = PTR_ERR(kfilename);
+ if (!IS_ERR(kfilename)) {
+ if (tvs) {
+ if (get_tv32(&ktvs[0], (struct timeval32 *)A(tvs)) ||
+ get_tv32(&ktvs[1], 1+(struct timeval32 *)A(tvs)))
+ return -EFAULT;
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_utimes(kfilename, &ktvs[0]);
+ set_fs(old_fs);
+
+ putname32(kfilename);
+ }
+ return ret;
+}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index eda0ff326..9b00175a3 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.21 1997/07/05 07:09:17 davem Exp $
+/* $Id: systbls.S,v 1.24 1997/08/22 20:12:06 davem Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -10,213 +10,214 @@
* Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
*/
- .data
- .align 8
+ .text
+ .align 1024
/* First, the 32-bit Linux native syscall table. */
.globl sys_call_table32
sys_call_table32:
-/*0*/ .xword sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
-/*5*/ .xword sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
-/*10*/ .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
-/*15*/ .xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
-/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .xword sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
- .xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
-/*40*/ .xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
- .xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
-/*50*/ .xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
- .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
-/*60*/ .xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
- .xword sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/ .xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
- .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
-/*80*/ .xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
- .xword sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
-/*90*/ .xword sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
- .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*100*/ .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
-/*120*/ .xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
- .xword sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
-/*130*/ .xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
- .xword sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
-/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
- .xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
-/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
- .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
- .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/ .xword sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
- .xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
-/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
- .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
-/*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
- .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
-/*220*/ .xword sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
- .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
- .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
-/*240*/ .xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
-/*250*/ .xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
- .xword sys_aplib, sys_nis_syscall
+/*0*/ .word sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
+/*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
+/*10*/ .word sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
+/*15*/ .word sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
+/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .word sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .word sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
+ .word sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
+/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
+ .word sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
+/*50*/ .word sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
+ .word sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
+/*60*/ .word sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
+ .word sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
+ .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
+/*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
+ .word sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
+/*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
+ .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/ .word sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
+ .word sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
+/*130*/ .word sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
+ .word sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
+/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
+ .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
+/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
+ .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
+ .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
+/*190*/ .word sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
+ .word sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
+/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
+ .word sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
+/*210*/ .word sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
+ .word sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+/*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
+ .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/ .word sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ .word sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
+/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
+/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+ .word sys_aplib
/* Now the 64-bit native Linux syscall table. */
+ .align 1024
.globl sys_call_table64, sys_call_table
sys_call_table64:
sys_call_table:
-/*0*/ .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
-/*5*/ .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/ .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
-/*15*/ .xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
-/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
- .xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
-/*40*/ .xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
- .xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
-/*50*/ .xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
- .xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
-/*60*/ .xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
- .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/ .xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
- .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
-/*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
- .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
-/*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
- .xword sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
-/*100*/ .xword sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
- .xword sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
- .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
-/*120*/ .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
- .xword sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/ .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
- .xword sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/ .xword sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
- .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/ .xword sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
-/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
- .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
- .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
- .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
-/*190*/ .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
- .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
-/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
-/*210*/ .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
- .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
-/*220*/ .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
- .xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/ .xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
- .xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
-/*240*/ .xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/ .xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
- .xword sys_aplib, sys_nis_syscall
+/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .word sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
+ .word sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
+ .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+ .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+ .word sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+ .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+ .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+ .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
+/*100*/ .word sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
+ .word sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
+ .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
+/*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+ .word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
+ .word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+ .word sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
+ .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
+/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+ .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
+ .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/ .word sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
+ .word sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+ .word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/ .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+ .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/ .word sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+ .word sys_aplib
/* Now the 32-bit SunOS syscall table. */
- .align 8
+ .align 1024
.globl sunos_sys_table
sunos_sys_table:
-/*0*/ .xword sunos_indir, sys_exit, sys_fork
- .xword sunos_read, sunos_write, sunos_open
- .xword sys_close, sunos_wait4, sys32_creat
- .xword sys32_link, sys32_unlink, sunos_execv
- .xword sys32_chdir, sunos_nosys, sys32_mknod
- .xword sys32_chmod, sys32_chown, sunos_brk
- .xword sunos_nosys, sys32_lseek, sunos_getpid
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_getuid, sunos_nosys, sys_ptrace
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sys32_access, sunos_nosys, sunos_nosys
- .xword sys_sync, sys_kill, sys32_newstat
- .xword sunos_nosys, sys32_newlstat, sys_dup
- .xword sys_pipe, sunos_nosys, sys_profil
- .xword sunos_nosys, sunos_nosys, sunos_getgid
- .xword sunos_nosys, sunos_nosys
-/*50*/ .xword sunos_nosys, sys32_acct, sunos_nosys
- .xword sunos_mctl, sunos_ioctl, sys32_reboot
- .xword sunos_nosys, sys32_symlink, sys32_readlink
- .xword sys32_execve, sys_umask, sys32_chroot
- .xword sys32_newfstat, sunos_nosys, sys_getpagesize
- .xword sys32_msync, sys_vfork, sunos_nosys
- .xword sunos_nosys, sunos_sbrk, sunos_sstk
- .xword sunos_mmap, sunos_vadvise, sys32_munmap
- .xword sys32_mprotect, sunos_madvise, sys_vhangup
- .xword sunos_nosys, sunos_mincore, sys32_getgroups
- .xword sys32_setgroups, sys_getpgrp, sunos_setpgrp
- .xword sys32_setitimer, sunos_nosys, sys32_swapon
- .xword sys32_getitimer, sys32_gethostname, sys32_sethostname
- .xword sunos_getdtablesize, sys_dup2, sunos_nop
- .xword sys32_fcntl, sunos_select, sunos_nop
- .xword sys_fsync, sys_setpriority, sys_socket
- .xword sys32_connect, sunos_accept
-/*100*/ .xword sys_getpriority, sunos_send, sunos_recv
- .xword sunos_nosys, sys32_bind, sunos_setsockopt
- .xword sys_listen, sunos_nosys, sunos_sigaction
- .xword sunos_sigblock, sunos_sigsetmask, sys_sigpause
- .xword sys32_sigstack, sys32_recvmsg, sys32_sendmsg
- .xword sunos_nosys, sys_gettimeofday, sys32_getrusage
- .xword sunos_getsockopt, sunos_nosys, sunos_readv
- .xword sunos_writev, sys_settimeofday, sys_fchown
- .xword sys_fchmod, sys32_recvfrom, sys32_setreuid
- .xword sys_setregid, sys32_rename, sys32_truncate
- .xword sys32_ftruncate, sys_flock, sunos_nosys
- .xword sys32_sendto, sys_shutdown, sys_socketpair
- .xword sys32_mkdir, sys32_rmdir, sys32_utimes
- .xword sys_sigreturn, sunos_nosys, sys32_getpeername
- .xword sunos_gethostid, sunos_nosys, sys32_getrlimit
- .xword sys32_setrlimit, sunos_killpg, sunos_nosys
- .xword sunos_nosys, sunos_nosys
-/*150*/ .xword sys32_getsockname, sunos_nosys, sunos_nosys
- .xword sys32_poll, sunos_nosys, sunos_nosys
- .xword sunos_getdirentries, sys32_statfs, sys32_fstatfs
- .xword sys32_umount, sunos_nosys, sunos_nosys
- .xword sunos_getdomainname, sys32_setdomainname
- .xword sunos_nosys, sys32_quotactl, sunos_nosys
- .xword sunos_mount, sys32_ustat, sunos_semsys
- .xword sunos_nosys, sunos_shmsys, sunos_audit
- .xword sunos_nosys, sunos_getdents, sys_setsid
- .xword sys_fchdir, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sys32_sigpending, sunos_nosys
- .xword sys_setpgid, sunos_pathconf, sunos_fpathconf
- .xword sunos_sysconf, sunos_uname, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
-/*200*/ .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys
-/*250*/ .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sys_aplib
+/*0*/ .word sunos_indir, sys_exit, sys_fork
+ .word sunos_read, sunos_write, sunos_open
+ .word sys_close, sunos_wait4, sys32_creat
+ .word sys32_link, sys32_unlink, sunos_execv
+ .word sys32_chdir, sunos_nosys, sys32_mknod
+ .word sys32_chmod, sys32_chown, sunos_brk
+ .word sunos_nosys, sys32_lseek, sunos_getpid
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_getuid, sunos_nosys, sys_ptrace
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sys32_access, sunos_nosys, sunos_nosys
+ .word sys_sync, sys_kill, sys32_newstat
+ .word sunos_nosys, sys32_newlstat, sys_dup
+ .word sys_pipe, sunos_nosys, sys_profil
+ .word sunos_nosys, sunos_nosys, sunos_getgid
+ .word sunos_nosys, sunos_nosys
+/*50*/ .word sunos_nosys, sys32_acct, sunos_nosys
+ .word sunos_mctl, sunos_ioctl, sys32_reboot
+ .word sunos_nosys, sys32_symlink, sys32_readlink
+ .word sys32_execve, sys_umask, sys32_chroot
+ .word sys32_newfstat, sunos_nosys, sys_getpagesize
+ .word sys32_msync, sys_vfork, sunos_nosys
+ .word sunos_nosys, sunos_sbrk, sunos_sstk
+ .word sunos_mmap, sunos_vadvise, sys32_munmap
+ .word sys32_mprotect, sunos_madvise, sys_vhangup
+ .word sunos_nosys, sunos_mincore, sys32_getgroups
+ .word sys32_setgroups, sys_getpgrp, sunos_setpgrp
+ .word sys32_setitimer, sunos_nosys, sys32_swapon
+ .word sys32_getitimer, sys32_gethostname, sys32_sethostname
+ .word sunos_getdtablesize, sys_dup2, sunos_nop
+ .word sys32_fcntl, sunos_select, sunos_nop
+ .word sys_fsync, sys_setpriority, sys_socket
+ .word sys32_connect, sunos_accept
+/*100*/ .word sys_getpriority, sunos_send, sunos_recv
+ .word sunos_nosys, sys32_bind, sunos_setsockopt
+ .word sys_listen, sunos_nosys, sunos_sigaction
+ .word sunos_sigblock, sunos_sigsetmask, sys_sigpause
+ .word sys32_sigstack, sys32_recvmsg, sys32_sendmsg
+ .word sunos_nosys, sys32_gettimeofday, sys32_getrusage
+ .word sunos_getsockopt, sunos_nosys, sunos_readv
+ .word sunos_writev, sys32_settimeofday, sys_fchown
+ .word sys_fchmod, sys32_recvfrom, sys32_setreuid
+ .word sys_setregid, sys32_rename, sys32_truncate
+ .word sys32_ftruncate, sys_flock, sunos_nosys
+ .word sys32_sendto, sys_shutdown, sys_socketpair
+ .word sys32_mkdir, sys32_rmdir, sys32_utimes
+ .word sys_sigreturn, sunos_nosys, sys32_getpeername
+ .word sunos_gethostid, sunos_nosys, sys32_getrlimit
+ .word sys32_setrlimit, sunos_killpg, sunos_nosys
+ .word sunos_nosys, sunos_nosys
+/*150*/ .word sys32_getsockname, sunos_nosys, sunos_nosys
+ .word sys32_poll, sunos_nosys, sunos_nosys
+ .word sunos_getdirentries, sys32_statfs, sys32_fstatfs
+ .word sys32_umount, sunos_nosys, sunos_nosys
+ .word sunos_getdomainname, sys32_setdomainname
+ .word sunos_nosys, sys32_quotactl, sunos_nosys
+ .word sunos_mount, sys32_ustat, sunos_semsys
+ .word sunos_nosys, sunos_shmsys, sunos_audit
+ .word sunos_nosys, sunos_getdents, sys_setsid
+ .word sys_fchdir, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sys32_sigpending, sunos_nosys
+ .word sys_setpgid, sunos_pathconf, sunos_fpathconf
+ .word sunos_sysconf, sunos_uname, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+/*200*/ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys
+/*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sys_aplib
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index df6a1c05e..8b0152231 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
+/* $Id: time.c,v 1.12 1997/08/22 20:12:13 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
* Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -17,12 +18,17 @@
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <asm/oplib.h>
#include <asm/mostek.h>
#include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/fhc.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
struct mostek48t02 *mstk48t02_regs = 0;
struct mostek48t08 *mstk48t08_regs = 0;
@@ -155,33 +161,55 @@ static int has_low_battery(void)
/* Probe for the real time clock chip. */
-__initfunc(static void clock_probe(void))
+__initfunc(static void set_system_time(void))
{
- struct linux_prom_registers clk_reg[2];
- char model[128];
- int node, sbusnd, err;
-
- /* XXX HACK HACK HACK, delete me soon */
- struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX];
- int XXX_sbus_nranges;
+ unsigned int year, mon, day, hour, min, sec;
+ struct mostek48t02 *mregs;
- node = prom_getchild(prom_root_node);
- sbusnd = prom_searchsiblings(node, "sbus");
- node = prom_getchild(sbusnd);
+ do_get_fast_time = do_gettimeofday;
- if(node == 0 || node == -1) {
- prom_printf("clock_probe: Serious problem can't find sbus PROM node.\n");
+ mregs = mstk48t02_regs;
+ if(!mregs) {
+ prom_printf("Something wrong, clock regs not mapped yet.\n");
prom_halt();
+ }
+
+ mregs->creg |= MSTK_CREG_READ;
+ sec = MSTK_REG_SEC(mregs);
+ min = MSTK_REG_MIN(mregs);
+ hour = MSTK_REG_HOUR(mregs);
+ day = MSTK_REG_DOM(mregs);
+ mon = MSTK_REG_MONTH(mregs);
+ year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
+ xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+ xtime.tv_usec = 0;
+ mregs->creg &= ~MSTK_CREG_READ;
+}
+
+__initfunc(void clock_probe(void))
+{
+ struct linux_prom_registers clk_reg[2];
+ char model[128];
+ int node, busnd = -1, err;
+
+ if(central_bus != NULL) {
+ busnd = central_bus->child->prom_node;
+ }
+#ifdef CONFIG_PCI
+ else if (ebus_chain != NULL) {
+ busnd = ebus_chain->prom_node;
+ }
+#endif
+ else {
+ busnd = SBus_chain->prom_node;
}
- /* XXX FIX ME */
- err = prom_getproperty(sbusnd, "ranges", (char *) XXX_sbus_ranges,
- sizeof(XXX_sbus_ranges));
- if(err == -1) {
- prom_printf("clock_probe: Cannot get XXX sbus ranges\n");
+ if(busnd == -1) {
+ prom_printf("clock_probe: problem, cannot find bus to search.\n");
prom_halt();
}
- XXX_sbus_nranges = (err / sizeof(struct linux_prom_ranges));
+
+ node = prom_getchild(busnd);
while(1) {
prom_getstring(node, "model", model, sizeof(model));
@@ -199,12 +227,48 @@ __initfunc(static void clock_probe(void))
err = prom_getproperty(node, "reg", (char *)clk_reg,
sizeof(clk_reg));
if(err == -1) {
- prom_printf("clock_probe: Cannot make Mostek\n");
+ prom_printf("clock_probe: Cannot get Mostek reg property\n");
prom_halt();
}
- /* XXX fix me badly */
- prom_adjust_regs(clk_reg, 1, XXX_sbus_ranges, XXX_sbus_nranges);
+ if(central_bus) {
+ prom_apply_fhc_ranges(central_bus->child, clk_reg, 1);
+ prom_apply_central_ranges(central_bus, clk_reg, 1);
+ }
+#ifdef CONFIG_PCI
+ else if (ebus_chain) {
+ struct linux_ebus_device *edev;
+
+ for_each_ebusdev(edev, ebus_chain)
+ if (edev->prom_node == node)
+ break;
+ if (!edev) {
+ prom_printf("%s: Mostek not probed by EBUS\n",
+ __FUNCTION__);
+ prom_halt();
+ }
+
+ if (check_region(edev->base_address[0],
+ sizeof(struct mostek48t59))) {
+ prom_printf("%s: Can't get region %lx, %d\n",
+ __FUNCTION__, edev->base_address[0],
+ sizeof(struct mostek48t59));
+ prom_halt();
+ }
+ request_region(edev->base_address[0],
+ sizeof(struct mostek48t59), "clock");
+
+ mstk48t59_regs = (struct mostek48t59 *)
+ edev->base_address[0];
+ mstk48t02_regs = &mstk48t59_regs->regs;
+ break;
+ }
+#endif
+ else {
+ prom_adjust_regs(clk_reg, 1,
+ SBus_chain->sbus_ranges,
+ SBus_chain->num_sbus_ranges);
+ }
if(model[5] == '0' && model[6] == '2') {
mstk48t02_regs = (struct mostek48t02 *)
@@ -234,6 +298,8 @@ __initfunc(static void clock_probe(void))
/* Kick start the clock if it is completely stopped. */
if (mstk48t02_regs->sec & MSTK_STOP)
kick_start_clock();
+
+ set_system_time();
}
#ifndef BCD_TO_BIN
@@ -246,29 +312,10 @@ __initfunc(static void clock_probe(void))
__initfunc(void time_init(void))
{
- unsigned int year, mon, day, hour, min, sec;
- struct mostek48t02 *mregs;
-
- do_get_fast_time = do_gettimeofday;
-
- clock_probe();
-
- mregs = mstk48t02_regs;
- if(!mregs) {
- prom_printf("Something wrong, clock regs not mapped yet.\n");
- prom_halt();
- }
-
- mregs->creg |= MSTK_CREG_READ;
- sec = MSTK_REG_SEC(mregs);
- min = MSTK_REG_MIN(mregs);
- hour = MSTK_REG_HOUR(mregs);
- day = MSTK_REG_DOM(mregs);
- mon = MSTK_REG_MONTH(mregs);
- year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
- xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
- xtime.tv_usec = 0;
- mregs->creg &= ~MSTK_CREG_READ;
+ /* clock_probe() is now done at end of sbus_init on sparc64
+ * so that both sbus and fhc bus information is probed and
+ * available.
+ */
}
extern void init_timers(void (*func)(int, void *, struct pt_regs *));
@@ -301,22 +348,29 @@ void do_gettimeofday(struct timeval *tv)
/* Load doubles must be used on xtime so that what we get
* is guarenteed to be atomic, this is why we can run this
* with interrupts on full blast. Don't touch this... -DaveM
+ *
+ * Note with time_t changes to the timeval type, I must now use
+ * nucleus atomic quad 128-bit loads.
*/
__asm__ __volatile__("
sethi %hi(linux_timers), %o1
sethi %hi(xtime), %g2
ldx [%o1 + %lo(linux_timers)], %g3
-1: ldd [%g2 + %lo(xtime)], %o4
+ or %g2, %lo(xtime), %g2
+1: ldda [%g2] 0x24, %o4
+ membar #LoadLoad | #MemIssue
ldx [%g3], %o1
- ldd [%g2 + %lo(xtime)], %o2
+ membar #LoadLoad | #MemIssue
+ ldda [%g2] 0x24, %o2
+ membar #LoadLoad
xor %o4, %o2, %o2
xor %o5, %o3, %o3
orcc %o2, %o3, %g0
- bne,pn %icc, 1b
+ bne,pn %xcc, 1b
cmp %o1, 0
bge,pt %icc, 1f
sethi %hi(tick), %o3
- ld [%o3 + %lo(tick)], %o3
+ ldx [%o3 + %lo(tick)], %o3
sethi %hi(0x1fffff), %o2
or %o2, %lo(0x1fffff), %o2
add %o5, %o3, %o5
@@ -325,12 +379,12 @@ void do_gettimeofday(struct timeval *tv)
sethi %hi(1000000), %o2
or %o2, %lo(1000000), %o2
cmp %o5, %o2
- bl,a,pn %icc, 1f
- st %o4, [%o0 + 0x0]
+ bl,a,pn %xcc, 1f
+ stx %o4, [%o0 + 0x0]
add %o4, 0x1, %o4
sub %o5, %o2, %o5
- st %o4, [%o0 + 0x0]
-1: st %o5, [%o0 + 0x4]");
+ stx %o4, [%o0 + 0x0]
+1: stx %o5, [%o0 + 0x8]");
}
void do_settimeofday(struct timeval *tv)
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
new file mode 100644
index 000000000..cefcb6ba3
--- /dev/null
+++ b/arch/sparc64/kernel/trampoline.S
@@ -0,0 +1,207 @@
+/* $Id: trampoline.S,v 1.2 1997/08/30 04:53:05 ralf Exp $
+ * trampoline.S: Jump start slave processors on sparc64.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/lsu.h>
+#include <asm/pstate.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/spitfire.h>
+#include <asm/asm_offsets.h>
+
+ .data
+ .align 8
+ .globl smp_trampoline
+smp_trampoline: .skip 0x300
+
+ .text
+ .align 8
+ .globl sparc64_cpu_startup, sparc64_cpu_startup_end
+sparc64_cpu_startup:
+ flushw
+ mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
+ stxa %g1, [%g0] ASI_LSU_CONTROL
+ membar #Sync
+ wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+ wrpr %g0, 15, %pil
+
+ sethi %uhi(PAGE_OFFSET), %g4
+ sllx %g4, 32, %g4
+
+ /* XXX Buggy PROM... */
+ srl %o0, 0, %g6
+ add %g6, %g4, %g6
+
+ sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
+ sllx %g5, 32, %g5
+ or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
+
+ sethi %uhi(_PAGE_PADDR), %g3
+ or %g3, %ulo(_PAGE_PADDR), %g3
+ sllx %g3, 32, %g3
+ sethi %hi(_PAGE_PADDR), %g7
+ or %g7, %lo(_PAGE_PADDR), %g7
+ or %g3, %g7, %g3
+
+ clr %l0
+ set 0x1fff, %l2
+ rd %pc, %l3
+ andn %l3, %l2, %g2
+1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1
+ cmp %g1, %g2
+ be,a,pn %xcc, 2f
+ ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1
+ cmp %l0, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+2: nop
+ nop
+ nop
+ and %g1, %g3, %g1
+ sub %g1, %g2, %g1
+ or %g5, %g1, %g5
+ clr %l0
+ sethi %hi(KERNBASE), %g3
+ sethi %hi(KERNBASE<<1), %g7
+ mov TLB_TAG_ACCESS, %l7
+1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1
+ cmp %g1, %g3
+ blu,pn %xcc, 2f
+ cmp %g1, %g7
+ bgeu,pn %xcc, 2f
+ nop
+ stxa %g0, [%l7] ASI_IMMU
+ stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS
+2: cmp %l0, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+ nop
+ nop
+ nop
+ clr %l0
+1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1
+ cmp %g1, %g3
+ blu,pn %xcc, 2f
+ cmp %g1, %g7
+ bgeu,pn %xcc, 2f
+ nop
+ stxa %g0, [%l7] ASI_DMMU
+ stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS
+2: cmp %l0, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+ nop
+ nop
+ nop
+ sethi %hi(KERNBASE), %g3
+ mov (63 << 3), %g7
+ stxa %g3, [%l7] ASI_DMMU
+ stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+ stxa %g3, [%l7] ASI_IMMU
+ stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+ flush %g3
+ membar #Sync
+ b,pt %xcc, 1f
+ nop
+1: set bounce, %g2
+ jmpl %g2 + %g0, %g0
+ nop
+
+bounce:
+ mov PRIMARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+ mov SECONDARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+
+ mov TLB_TAG_ACCESS, %g2
+ stxa %g3, [%g2] ASI_IMMU
+ stxa %g3, [%g2] ASI_DMMU
+
+ mov (63 << 3), %g7
+ ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+
+ ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+
+ flush %g3
+ membar #Sync
+
+ mov 1, %g5
+ sllx %g5, (PAGE_SHIFT + 1), %g5
+ sub %g5, (REGWIN_SZ + STACK_BIAS), %g5
+ add %g6, %g5, %sp
+ mov 0, %fp
+
+ wrpr %g0, 0, %wstate
+ wrpr %g0, 0, %tl
+
+ /* Setup the trap globals, then we can resurface. */
+ rdpr %pstate, %o1
+ mov %g6, %o2
+ wrpr %o1, (PSTATE_AG | PSTATE_IE), %pstate
+ sethi %hi(sparc64_ttable_tl0), %g5
+ wrpr %g5, %tba
+ mov %o2, %g6
+
+ wrpr %o1, (PSTATE_MG | PSTATE_IE), %pstate
+ sethi %hi(0x1ff8), %g2
+ or %g2, %lo(0x1ff8), %g2
+ ldx [%o2 + AOFF_task_mm], %g6
+ ldx [%g6 + AOFF_mm_pgd], %g6
+ clr %g7
+
+ wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate
+ sethi %hi(ivector_to_mask), %g5
+ or %g5, %lo(ivector_to_mask), %g1
+ mov 0x40, %g2
+
+ wrpr %g0, 0, %wstate
+ wrpr %o1, PSTATE_IE, %pstate
+
+ mov TSB_REG, %o4
+ mov 1, %o5
+ stxa %o5, [%o4] ASI_DMMU
+ stxa %o5, [%o4] ASI_IMMU
+ membar #Sync
+
+ or %o1, PSTATE_IE, %o1
+ wrpr %o1, 0, %pstate
+
+ call smp_callin
+ nop
+ call cpu_idle
+ mov 0, %o0
+ call cpu_panic
+ nop
+1: b,a,pt %xcc, 1b
+
+ .align 8
+sparc64_cpu_startup_end:
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index ac3e79958..1ffd43730 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.29 1997/07/05 09:52:38 davem Exp $
+/* $Id: traps.c,v 1.31 1997/08/11 14:35:33 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -25,6 +25,7 @@
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
+#include <asm/lsu.h>
/* #define SYSCALL_TRACING */
/* #define VERBOSE_SYSCALL_TRACING */
@@ -194,8 +195,55 @@ void data_access_exception (struct pt_regs *regs)
send_sig(SIGSEGV, current, 1);
}
+#ifdef CONFIG_PCI
+/* This is really pathetic... */
+/* #define DEBUG_PCI_POKES */
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_faulted;
+#endif
+
void do_dae(struct pt_regs *regs)
{
+#ifdef CONFIG_PCI
+#ifdef DEBUG_PCI_POKES
+ prom_printf(" (POKE ");
+#endif
+ if(pci_poke_in_progress) {
+ unsigned long va;
+#ifdef DEBUG_PCI_POKES
+ prom_printf("tpc[%016lx] tnpc[%016lx] ",
+ regs->tpc, regs->tnpc);
+#endif
+ pci_poke_faulted = 1;
+ regs->tnpc = regs->tpc + 4;
+
+
+#ifdef DEBUG_PCI_POKES
+ prom_printf("PCI) ");
+ /* prom_halt(); */
+#endif
+ /* Re-enable I/D caches, Ultra turned them off. */
+ for(va = 0; va < (PAGE_SIZE << 1); va += 32) {
+ spitfire_put_icache_tag(va, 0x0);
+ spitfire_put_dcache_tag(va, 0x0);
+ }
+ __asm__ __volatile__("flush %%g6\n\t"
+ "membar #Sync\n\t"
+ "stxa %0, [%%g0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
+ LSU_CONTROL_IM | LSU_CONTROL_DM),
+ "i" (ASI_LSU_CONTROL)
+ : "memory");
+ return;
+ }
+#ifdef DEBUG_PCI_POKES
+ prom_printf("USER) ");
+ prom_printf("tpc[%016lx] tnpc[%016lx]\n");
+ prom_halt();
+#endif
+#endif
send_sig(SIGSEGV, current, 1);
}
@@ -215,11 +263,9 @@ void do_fpe_common(struct pt_regs *regs)
regs->tpc = regs->tnpc;
regs->tnpc += 4;
} else {
- lock_kernel();
current->tss.sig_address = regs->tpc;
current->tss.sig_desc = SUBSIG_FPERROR;
send_sig(SIGFPE, current, 1);
- unlock_kernel();
}
}
@@ -288,6 +334,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
}
printk("Instruction DUMP:");
instruction_dump ((unsigned int *) regs->tpc);
+ lock_kernel(); /* Or else! */
if(regs->tstate & TSTATE_PRIV)
do_exit(SIGKILL);
do_exit(SIGSEGV);
@@ -298,13 +345,11 @@ void do_illegal_instruction(struct pt_regs *regs)
unsigned long pc = regs->tpc;
unsigned long tstate = regs->tstate;
- lock_kernel();
if(tstate & TSTATE_PRIV)
die_if_kernel("Kernel illegal instruction", regs);
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
void mem_address_unaligned(struct pt_regs *regs)
@@ -333,19 +378,16 @@ void do_privact(struct pt_regs *regs)
current->tss.sig_address = regs->tpc;
current->tss.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long tstate)
{
- lock_kernel();
if(tstate & TSTATE_PRIV)
die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
/* XXX User may want to be allowed to do this. XXX */
@@ -353,7 +395,6 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n
void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long tstate)
{
- lock_kernel();
if(regs->tstate & TSTATE_PRIV) {
printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc,
regs->u_regs[UREG_RETPC]);
@@ -363,15 +404,12 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGBUS, current, 1);
- unlock_kernel();
}
void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long psr)
{
- lock_kernel();
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
/* Trap level 1 stuff or other traps we should never see... */
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 73bda96d9..bf00cb231 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.18 1997/07/05 09:52:41 davem Exp $
+/* $Id: ttable.S,v 1.20 1997/08/29 15:51:39 jj Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -44,7 +44,8 @@ tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6)
tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8)
tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10)
tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
-tl0_irq13: TRAP_IRQ(handler_irq, 13) TRAP_IRQ(handler_irq, 14)
+tl0_irq13: TRAP_IRQ(handler_irq, 13)
+tl0_itick: TRAP_TICK
tl0_irq15: TRAP_IRQ(handler_irq, 15)
tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
@@ -99,6 +100,7 @@ tl0_bkpt: BREAKPOINT_TRAP
tl0_resv102: BTRAP(0x102)
tl0_flushw: FLUSH_WINDOW_TRAP
tl0_resv104: BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107)
+ .globl tl0_solaris
tl0_solaris: SOLARIS_SYSCALL_TRAP
tl0_netbsd: NETBSD_SYSCALL_TRAP
tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e)
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index f66889195..3aea13953 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.1 1997/07/18 06:26:45 ralf Exp $
+/* $Id: unaligned.c,v 1.4 1997/08/19 15:25:11 jj Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -205,19 +205,19 @@ __asm__ __volatile__ ( \
"stx %%g7, [%0 + 8]\n" \
"0:\n\n\t" \
".section __ex_table\n\t" \
- ".xword 4b, " #errh "\n\t" \
- ".xword 5b, " #errh "\n\t" \
- ".xword 6b, " #errh "\n\t" \
- ".xword 7b, " #errh "\n\t" \
- ".xword 8b, " #errh "\n\t" \
- ".xword 9b, " #errh "\n\t" \
- ".xword 10b, " #errh "\n\t" \
- ".xword 11b, " #errh "\n\t" \
- ".xword 12b, " #errh "\n\t" \
- ".xword 13b, " #errh "\n\t" \
- ".xword 14b, " #errh "\n\t" \
- ".xword 15b, " #errh "\n\t" \
- ".xword 16b, " #errh "\n\n\t" \
+ ".word 4b, " #errh "\n\t" \
+ ".word 5b, " #errh "\n\t" \
+ ".word 6b, " #errh "\n\t" \
+ ".word 7b, " #errh "\n\t" \
+ ".word 8b, " #errh "\n\t" \
+ ".word 9b, " #errh "\n\t" \
+ ".word 10b, " #errh "\n\t" \
+ ".word 11b, " #errh "\n\t" \
+ ".word 12b, " #errh "\n\t" \
+ ".word 13b, " #errh "\n\t" \
+ ".word 14b, " #errh "\n\t" \
+ ".word 15b, " #errh "\n\t" \
+ ".word 16b, " #errh "\n\n\t" \
".previous\n\t" \
: : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed), "r" (asi) \
: "l1", "l2", "g7", "g1", "cc"); \
@@ -259,20 +259,20 @@ __asm__ __volatile__ ( \
"17:\t" "stba %%l1, [%0 + 1] %%asi\n" \
"0:\n\n\t" \
".section __ex_table\n\t" \
- ".xword 4b, " #errh "\n\t" \
- ".xword 5b, " #errh "\n\t" \
- ".xword 6b, " #errh "\n\t" \
- ".xword 7b, " #errh "\n\t" \
- ".xword 8b, " #errh "\n\t" \
- ".xword 9b, " #errh "\n\t" \
- ".xword 10b, " #errh "\n\t" \
- ".xword 11b, " #errh "\n\t" \
- ".xword 12b, " #errh "\n\t" \
- ".xword 13b, " #errh "\n\t" \
- ".xword 14b, " #errh "\n\t" \
- ".xword 15b, " #errh "\n\t" \
- ".xword 16b, " #errh "\n\t" \
- ".xword 17b, " #errh "\n\n\t" \
+ ".word 4b, " #errh "\n\t" \
+ ".word 5b, " #errh "\n\t" \
+ ".word 6b, " #errh "\n\t" \
+ ".word 7b, " #errh "\n\t" \
+ ".word 8b, " #errh "\n\t" \
+ ".word 9b, " #errh "\n\t" \
+ ".word 10b, " #errh "\n\t" \
+ ".word 11b, " #errh "\n\t" \
+ ".word 12b, " #errh "\n\t" \
+ ".word 13b, " #errh "\n\t" \
+ ".word 14b, " #errh "\n\t" \
+ ".word 15b, " #errh "\n\t" \
+ ".word 16b, " #errh "\n\t" \
+ ".word 17b, " #errh "\n\n\t" \
".previous\n\t" \
: : "r" (dst_addr), "r" (size), "r" (src_val), "r" (asi) \
: "l1", "l2", "g7", "g1", "cc"); \
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index f2c714eae..0ebf92767 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.16 1997/07/13 20:02:42 davem Exp $
+/* $Id: winfixup.S,v 1.19 1997/08/08 08:33:37 jj Exp $
*
* winfixup.S: Handle cases where user stack pointer is found to be bogus.
*
@@ -143,8 +143,9 @@ spill_fixup:
retry
window_scheisse_from_user_common:
wrpr %g1, %cwp
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
window_scheisse_merge:
srlx %l5, PAGE_SHIFT, %o1
@@ -244,8 +245,9 @@ spill_fixup_mna:
retry
window_mna_from_user_common:
wrpr %g1, %cwp
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
window_mna_merge:
call mem_address_unaligned
add %sp, STACK_BIAS + REGWIN_SZ, %o0
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
index 3da21c606..9f8729ee5 100644
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -1,12 +1,12 @@
-# $Id: Makefile,v 1.13 1997/07/16 10:12:03 jj Exp $
+# $Id: Makefile,v 1.15 1997/08/19 03:11:50 davem Exp $
# Makefile for Sparc library files..
#
-CFLAGS := $(CFLAGS) -ansi
+CFLAGS := $(CFLAGS)
-OBJS = blockops.o locks.o strlen.o strncmp.o \
+OBJS = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \
memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
- VIScopy.o VISbzero.o VISmemset.o VIScsum.o
+ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
diff --git a/arch/sparc64/lib/PeeCeeI.c b/arch/sparc64/lib/PeeCeeI.c
new file mode 100644
index 000000000..6677f581a
--- /dev/null
+++ b/arch/sparc64/lib/PeeCeeI.c
@@ -0,0 +1,225 @@
+/* $Id: PeeCeeI.c,v 1.3 1997/08/28 23:59:52 davem Exp $
+ * PeeCeeI.c: The emerging standard...
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_PCI
+
+#include <asm/io.h>
+
+void outsb(unsigned long addr, const void *src, unsigned long count)
+{
+ const u8 *p = src;
+
+ while(count--)
+ outb(*p++, addr);
+}
+
+void outsw(unsigned long addr, const void *src, unsigned long count)
+{
+ if(count) {
+ const u16 *ps = src;
+ const u32 *pi;
+
+ if(((u64)src) & 0x2) {
+ outw(*ps++, addr);
+ count--;
+ }
+ pi = (const u32 *)ps;
+ while(count >= 2) {
+ u32 w;
+
+ w = *pi++;
+ outw(w >> 16, addr);
+ outw(w, addr);
+ count -= 2;
+ }
+ ps = (const u16 *)pi;
+ if(count)
+ outw(*ps, addr);
+ }
+}
+
+void outsl(unsigned long addr, const void *src, unsigned long count)
+{
+ if(count) {
+ if((((u64)src) & 0x3) == 0) {
+ const u32 *p = src;
+ while(count--)
+ outl(*p++, addr);
+ } else {
+ const u8 *pb;
+ const u16 *ps = src;
+ u32 l = 0, l2;
+ const u32 *pi;
+
+ switch(((u64)src) & 0x3) {
+ case 0x2:
+ count -= 1;
+ l = *ps++;
+ pi = (const u32 *)ps;
+ while(count--) {
+ l2 = *pi++;
+ outl(((l <<16) | (l2 >> 16)), addr);
+ l = l2;
+ }
+ ps = (const u16 *)pi;
+ outl(((l << 16) | (*ps >> 16)), addr);
+ break;
+
+ case 0x1:
+ count -= 1;
+ pb = src;
+ l = (*pb++ << 16);
+ ps = (const u16 *)pb;
+ l |= *ps++;
+ pi = (const u32 *)ps;
+ while(count--) {
+ l2 = *pi++;
+ outl(((l << 8) | (l2 >> 24)), addr);
+ l = l2;
+ }
+ pb = (const u8 *)pi;
+ outl(((l << 8) | (*pb >> 24)), addr);
+ break;
+
+ case 0x3:
+ count -= 1;
+ pb = src;
+ l = (*pb++ >> 24);
+ pi = (const u32 *)pb;
+ while(count--) {
+ l2 = *pi++;
+ outl(((l << 24) | (l2 >> 8)), addr);
+ l = l2;
+ }
+ ps = (const u16 *)pi;
+ l2 = (*ps++ << 16);
+ pb = (const u8 *)ps;
+ l2 |= (*pb << 8);
+ outl(((l << 24) | (l2 >> 8)), addr);
+ break;
+ }
+ }
+ }
+}
+
+void insb(unsigned long addr, void *dst, unsigned long count)
+{
+ if(count) {
+ u32 *pi;
+ u8 *pb = dst;
+
+ while((((unsigned long)pb) & 0x3) && count--)
+ *pb++ = inb(addr);
+ pi = (u32 *)pb;
+ while(count >= 4) {
+ u32 w;
+
+ w = (inb(addr) << 24);
+ w |= (inb(addr) << 16);
+ w |= (inb(addr) << 8);
+ w |= inb(addr);
+ *pi++ = w;
+ count -= 4;
+ }
+ pb = (u8 *)pi;
+ while(count--)
+ *pb++ = inb(addr);
+ }
+}
+
+void insw(unsigned long addr, void *dst, unsigned long count)
+{
+ if(count) {
+ u16 *ps = dst;
+ u32 *pi;
+
+ if(((unsigned long)ps) & 0x2) {
+ *ps++ = inw(addr);
+ count--;
+ }
+ pi = (u32 *)ps;
+ while(count >= 2) {
+ u32 w;
+
+ w = (inw(addr) << 16);
+ w |= inw(addr);
+ *pi++ = w;
+ count -= 2;
+ }
+ ps = (u16 *)pi;
+ if(count)
+ *ps = inw(addr);
+ }
+}
+
+void insl(unsigned long addr, void *dst, unsigned long count)
+{
+ if(count) {
+ if((((unsigned long)dst) & 0x3) == 0) {
+ u32 *pi = dst;
+ while(count--)
+ *pi++ = inl(addr);
+ } else {
+ u32 l = 0, l2, *pi;
+ u16 *ps;
+ u8 *pb;
+
+ switch(((unsigned long)dst) & 3) {
+ case 0x2:
+ ps = dst;
+ count -= 1;
+ l = inl(addr);
+ *ps++ = (l >> 16);
+ pi = (u32 *)ps;
+ while(count--) {
+ l2 = inl(addr);
+ *pi++ = (l << 16) | (l2 >> 16);
+ l = l2;
+ }
+ ps = (u16 *)pi;
+ *ps = (l << 16);
+ break;
+
+ case 0x1:
+ pb = dst;
+ count -= 1;
+ *pb++ = (l >> 24);
+ ps = (u16 *)pb;
+ *ps++ = (l >> 8);
+ pi = (u32 *)ps;
+ while(count--) {
+ l2 = inl(addr);
+ *pi++ = ((l << 24) | (l2 >> 8));
+ l = l2;
+ }
+ pb = (u8 *)pi;
+ *pb = (l >> 8);
+ break;
+
+ case 0x3:
+ pb = (u8 *)dst;
+ count -= 1;
+ l = inl(addr);
+ *pb++ = l >> 24;
+ pi = (u32 *)pb;
+ while(count--) {
+ l2 = inl(addr);
+ *pi++ = ((l >> 24) | (l2 << 8));
+ l = l2;
+ }
+ ps = (u16 *)pi;
+ *ps++ = l >> 8;
+ pb = (u8 *)ps;
+ *pb = l;
+ break;
+ }
+ }
+ }
+}
+
+#endif /* CONFIG_PCI */
diff --git a/arch/sparc64/lib/VISbzero.S b/arch/sparc64/lib/VISbzero.S
index 3c86861fd..ede87843b 100644
--- a/arch/sparc64/lib/VISbzero.S
+++ b/arch/sparc64/lib/VISbzero.S
@@ -1,4 +1,4 @@
-/* $Id: VISbzero.S,v 1.1 1997/07/18 06:26:48 ralf Exp $
+/* $Id: VISbzero.S,v 1.8 1997/08/22 15:54:50 jj Exp $
* VISbzero.S: High speed clear operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -16,8 +16,8 @@
99: ba VISbzerofixup_ret##z; \
a, b, %o0; \
.section __ex_table; \
- .align 8; \
- .xword 98b, 99b; \
+ .align 4; \
+ .word 98b, 99b; \
.text; \
.align 4;
#define EXC(x,y,a,b,c...) \
@@ -28,15 +28,15 @@
ba VISbzerofixup_ret0; \
a, b, %o0; \
.section __ex_table; \
- .align 8; \
- .xword 98b, 99b; \
+ .align 4; \
+ .word 98b, 99b; \
.text; \
.align 4;
#define EXO1(x,y) \
98: x,y; \
.section __ex_table; \
- .align 8; \
- .xword 98b, VISbzerofixup_reto1; \
+ .align 4; \
+ .word 98b, VISbzerofixup_reto1; \
.text; \
.align 4;
#define EX(x,y,a,b) EXN(x,y,a,b,0)
@@ -44,8 +44,8 @@
#define EX2(x,y,a,b) EXN(x,y,a,b,2)
#define EXT(start,end,handler) \
.section __ex_table; \
- .align 8; \
- .xword start, 0, end, handler; \
+ .align 4; \
+ .word start, 0, end, handler; \
.text; \
.align 4
#else
@@ -147,7 +147,7 @@ bzero:
#else
wr %g0, ASI_BLK_P, %asi
#endif
- membar #StoreStore | #LoadStore
+ membar #StoreLoad | #StoreStore | #LoadStore
fzero %f0
andcc %o3, 0xc0, %o2
and %o1, 0x3f, %o1
@@ -180,16 +180,28 @@ bzero:
#ifdef __KERNEL__
wr %g0, 0, %fprs
wr %g7, 0x0, %asi
+#else
+#ifndef REGS_64BIT
+ wr %g0, FPRS_FEF, %fprs
#endif
- membar #Sync
+#endif
+ membar #StoreLoad | #StoreStore
9: andcc %o1, 0xf8, %o2
be,pn %xcc, 13f
andcc %o1, 7, %o1
+#ifdef __KERNEL__
+14: sethi %hi(13f), %o4
+ srl %o2, 1, %o3
+ sub %o4, %o3, %o4
+ jmpl %o4 + %lo(13f), %g0
+ add %o0, %o2, %o0
+#else
14: rd %pc, %o4
srl %o2, 1, %o3
sub %o4, %o3, %o4
jmpl %o4 + (13f - 14b), %g0
add %o0, %o2, %o0
+#endif
12: ZERO_BLOCKS(%o0, 0xc8, %g0)
ZERO_BLOCKS(%o0, 0x88, %g0)
ZERO_BLOCKS(%o0, 0x48, %g0)
diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S
index 1429f1658..40b781e73 100644
--- a/arch/sparc64/lib/VIScopy.S
+++ b/arch/sparc64/lib/VIScopy.S
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.1 1997/07/18 06:26:48 ralf Exp $
+/* $Id: VIScopy.S,v 1.14 1997/08/22 15:54:53 jj Exp $
* VIScopy.S: High speed copy operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -42,8 +42,8 @@
99: ba VIScopyfixup_ret; \
a, b, %o0; \
.section __ex_table; \
- .align 8; \
- .xword 98b, 99b; \
+ .align 4; \
+ .word 98b, 99b; \
.text; \
.align 4;
#define EX2(x,y,c,d,e,a,b) \
@@ -54,37 +54,48 @@
ba VIScopyfixup_ret; \
a, b, %o0; \
.section __ex_table; \
- .align 8; \
- .xword 98b, 99b; \
+ .align 4; \
+ .word 98b, 99b; \
.text; \
.align 4;
#define EXO2(x,y) \
98: x,y; \
.section __ex_table; \
- .align 8; \
- .xword 98b, VIScopyfixup_reto2; \
+ .align 4; \
+ .word 98b, VIScopyfixup_reto2; \
.text; \
.align 4;
#define EXVISN(x,y,n) \
98: x,y; \
.section __ex_table; \
- .align 8; \
- .xword 98b, VIScopyfixup_vis##n; \
+ .align 4; \
+ .word 98b, VIScopyfixup_vis##n; \
.text; \
.align 4;
#define EXT(start,end,handler) \
.section __ex_table; \
- .align 8; \
- .xword start, 0, end, handler; \
+ .align 4; \
+ .word start, 0, end, handler; \
.text; \
.align 4;
#else
-#define FPU_CLEAN_RETL \
- retl; \
+#ifdef REGS_64BIT
+#define FPU_CLEAN_RETL \
+ retl; \
mov %g6, %o0;
-#define FPU_RETL \
- retl; \
+#define FPU_RETL \
+ retl; \
mov %g6, %o0;
+#else
+#define FPU_CLEAN_RETL \
+ wr %g0, FPRS_FEF, %fprs; \
+ retl; \
+ mov %g6, %o0;
+#define FPU_RETL \
+ wr %g0, FPRS_FEF, %fprs; \
+ retl; \
+ mov %g6, %o0;
+#endif
#define NORMAL_RETL \
retl; \
mov %g6, %o0;
@@ -113,8 +124,8 @@
#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \
EXVIS(LDBLK [%src] ASIBLK, %fdest); \
- add %src, 0x40, %src; \
ASI_SETDST_BLK \
+ add %src, 0x40, %src; \
add %dest, 0x40, %dest; \
subcc %len, 0x40, %len; \
be,pn %xcc, jmptgt; \
@@ -303,7 +314,7 @@ copy_page: wr %g0, FPRS_FEF, %fprs ! FPU Group
sethi %hi(8192), %o2 ! IEU0 Group
mov ASI_BLK_P, asi_src ! IEU1
b,pt %xcc, dest_is_64byte_aligned ! CTI
- mov ASI_BLK_COMMIT_P, asi_dest ! IEU0 Group
+ mov ASI_BLK_P, asi_dest ! IEU0 Group
.align 32
.globl __copy_from_user
@@ -446,6 +457,13 @@ dest_is_64byte_aligned:
EXVIS1(LDBLK [%o1 + 0x40] ASIBLK, %f16) ! LSU Group
sub %g7, 0x80, %g7 ! IEU0
EXVIS(LDBLK [%o1 + 0x80] ASIBLK, %f32) ! LSU Group
+#ifdef __KERNEL__
+vispc: sll %g2, 9, %g2 ! IEU0 Group
+ sethi %hi(vis00), %g5 ! IEU1
+ or %g5, %lo(vis00), %g5 ! IEU0 Group
+ jmpl %g5 + %g2, %g0 ! CTI Group brk forced
+ addcc %o1, 0xc0, %o1 ! IEU1 Group
+#else
! Clk1 Group 8-(
! Clk2 Group 8-(
! Clk3 Group 8-(
@@ -455,6 +473,7 @@ vispc: rd %pc, %g5 ! PDU Group 8-(
sll %g2, 9, %g2 ! IEU0
jmpl %g5 + %g2, %g0 ! CTI Group brk forced
addcc %o1, 0xc0, %o1 ! IEU1 Group
+#endif
.align 512 /* OK, here comes the fun part... */
vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis01)
FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) LOOP_CHUNK2(o1, o0, g7, vis02)
@@ -721,20 +740,21 @@ __memcpy_16plus:
3: andcc %o2, 0x70, %g7 ! IEU1 Group
41: be,pn %xcc, 80f ! CTI
andcc %o2, 8, %g0 ! IEU1 Group
- ! Clk1 8-(
- ! Clk2 8-(
- ! Clk3 8-(
- ! Clk4 8-(
-79: rd %pc, %o5 ! PDU Group
#ifdef __KERNEL__
+79: sethi %hi(80f), %o5 ! IEU0
sll %g7, 1, %g5 ! IEU0 Group
add %o1, %g7, %o1 ! IEU1
srl %g7, 1, %g2 ! IEU0 Group
sub %o5, %g5, %o5 ! IEU1
sub %o5, %g2, %o5 ! IEU0 Group
- jmpl %o5 + %lo(80f - 79b), %g0 ! CTI Group brk forced
+ jmpl %o5 + %lo(80f), %g0 ! CTI Group brk forced
add %o0, %g7, %o0 ! IEU0 Group
#else
+ ! Clk1 8-(
+ ! Clk2 8-(
+ ! Clk3 8-(
+ ! Clk4 8-(
+79: rd %pc, %o5 ! PDU Group
sll %g7, 1, %g5 ! IEU0 Group
add %o1, %g7, %o1 ! IEU1
sub %o5, %g5, %o5 ! IEU0 Group
@@ -814,19 +834,20 @@ normal_retl:
andcc %o2, 0x70, %g7 ! IEU1
be,pn %xcc, 84f ! CTI
andcc %o2, 8, %g0 ! IEU1 Group
+#ifdef __KERNEL__
+83: srl %g7, 1, %g5 ! IEU0
+ sethi %hi(84f), %o5 ! IEU0 Group
+ add %g7, %g5, %g5 ! IEU1
+ add %o1, %g7, %o1 ! IEU0 Group
+ sub %o5, %g5, %o5 ! IEU1
+ jmpl %o5 + %lo(84f), %g0 ! CTI Group brk forced
+ add %o0, %g7, %o0 ! IEU0 Group
+#else
! Clk1 8-(
! Clk2 8-(
! Clk3 8-(
! Clk4 8-(
83: rd %pc, %o5 ! PDU Group
-#ifdef __KERNEL__
- srl %g7, 1, %g5 ! IEU0 Group
- add %g7, %g5, %g5 ! IEU0 Group
- add %o1, %g7, %o1 ! IEU1
- sub %o5, %g5, %o5 ! IEU0 Group
- jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced
- add %o0, %g7, %o0 ! IEU0 Group
-#else
add %o1, %g7, %o1 ! IEU0 Group
sub %o5, %g7, %o5 ! IEU1
jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced
diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S
index 1ccb98759..81b020c49 100644
--- a/arch/sparc64/lib/VIScsum.S
+++ b/arch/sparc64/lib/VIScsum.S
@@ -1,4 +1,4 @@
-/* $Id: VIScsum.S,v 1.1 1997/07/18 06:26:49 ralf Exp $
+/* $Id: VIScsum.S,v 1.2 1997/08/08 08:34:05 jj Exp $
* VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -345,11 +345,19 @@ csum_partial:
20: andcc %o1, 0xf0, %g1 /* IEU1 Group */
be,pn %icc, 23f /* CTI */
and %o1, 0xf, %o3 /* IEU0 */
-22: rd %pc, %g7 /* LSU Group */
+#ifdef __KERNEL__
+22: sll %g1, 1, %o4 /* IEU0 Group */
+ sethi %hi(23f), %g7 /* IEU1 */
+ sub %g7, %o4, %g7 /* IEU0 Group */
+ jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced */
+ add %o0, %g1, %o0 /* IEU0 */
+#else
+22: rd %pc, %g7 /* LSU Group+4bubbles */
sll %g1, 1, %o4 /* IEU0 Group */
sub %g7, %o4, %g7 /* IEU0 Group (regdep) */
jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced */
- add %o0, %g1, %o0 /* IEU0 */
+ add %o0, %g1, %o0 /* IEU0 */
+#endif
CSUM_LASTCHUNK(0xe0)
CSUM_LASTCHUNK(0xd0)
CSUM_LASTCHUNK(0xc0)
diff --git a/arch/sparc64/lib/VIScsumcopy.S b/arch/sparc64/lib/VIScsumcopy.S
new file mode 100644
index 000000000..efd2bfcd5
--- /dev/null
+++ b/arch/sparc64/lib/VIScsumcopy.S
@@ -0,0 +1,880 @@
+/* $Id: VIScsumcopy.S,v 1.2 1997/08/19 15:25:22 jj Exp $
+ * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous
+ * copying utilizing the UltraSparc Visual Instruction Set.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on older sparc32/sparc64 checksum.S, which is:
+ *
+ * Copyright(C) 1995 Linus Torvalds
+ * Copyright(C) 1995 Miguel de Icaza
+ * Copyright(C) 1996,1997 David S. Miller
+ * derived from:
+ * Linux/Alpha checksum c-code
+ * Linux/ix86 inline checksum assembly
+ * RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ * David Mosberger-Tang for optimized reference c-code
+ * BSD4.4 portable checksum routine
+ */
+
+#ifdef __sparc_v9__
+#define STACKOFF 0x7ff+128
+#else
+#define STACKOFF 64
+#endif
+
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#else
+#define ASI_P 0x80
+#define ASI_BLK_P 0xf0
+#define FRPS_FEF 0x04
+#define FPRS_DU 0x02
+#define FPRS_DL 0x01
+#endif
+#define ASI_BLK_XOR (ASI_BLK_P ^ ASI_P)
+
+#define src o0
+#define dst o1
+#define len o2
+#define sum o3
+#define x1 g1
+#define x2 g2
+#define x3 g3
+#define x4 g4
+#define x5 g5
+#define x6 g7
+#define x7 o4
+#define x8 o5
+
+/* Dobrou noc, SunSoft engineers. Spete sladce.
+ * This has a couple of tricks in and those
+ * tricks are UltraLinux trade secrets :))
+ * Once AGAIN, the SunSoft engineers are caught
+ * asleep at the keyboard :)).
+ * The main loop does about 20 superscalar cycles
+ * per 64bytes checksummed/copied.
+ */
+
+#define LDBLK(O0) \
+ ldda [%src] %asi, %O0 /* Load Group */
+
+#define STBLK \
+ stda %f48, [%dst] ASI_BLK_P /* Store */
+
+#define ST(fx,off) \
+ std %fx, [%dst + off] /* Store */
+
+#define SYNC \
+ membar #Sync
+
+
+#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DYMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \
+ LOAD /* Load Group */; \
+ faligndata %A14, %F0, %A14 /* FPA Group */; \
+ inc %x5 /* IEU0 */; \
+ STORE1 /* Store (optional) */; \
+ faligndata %F0, %F2, %A0 /* FPA Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ fpadd32 %F0, %f0, %F0 /* FPA Group */; \
+ inc %x6 /* IEU0 */; \
+ STORE2 /* Store (optional) */; \
+ faligndata %F2, %F4, %A2 /* FPA Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fpadd32 %F2, %f2, %F2 /* FPA Group */; \
+ add %src, 64, %src /* IEU0 */; \
+ add %dst, 64, %dst /* IEU1 */; \
+ fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \
+ inc %x7 /* IEU0 */; \
+ STORE3 /* Store (optional) */; \
+ faligndata %F4, %F6, %A4 /* FPA */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ fpadd32 %F4, %f4, %F4 /* FPA */; \
+ fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \
+ inc %x8 /* IEU0 */; \
+ STORE4 /* Store (optional) */; \
+ faligndata %F6, %F8, %A6 /* FPA */; \
+ srl %x8, 1, %x8 /* IEU0 Group */; \
+ add %sum, %x7, %sum /* IEU1 */; \
+ fpadd32 %F6, %f6, %F6 /* FPA */; \
+ fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \
+ inc %x1 /* IEU0 */; \
+ STORE5 /* Store (optional) */; \
+ faligndata %F8, %F10, %A8 /* FPA */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ add %sum, %x8, %sum /* IEU1 */; \
+ fpadd32 %F8, %f8, %F8 /* FPA */; \
+ fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \
+ inc %x2 /* IEU0 */; \
+ STORE6 /* Store (optional) */; \
+ faligndata %F10, %F12, %A10 /* FPA */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ fpadd32 %F10, %f10, %F10 /* FPA */; \
+ fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \
+ inc %x3 /* IEU0 */; \
+ STORE7 /* Store (optional) */; \
+ faligndata %F12, %F14, %A12 /* FPA */; \
+ srl %x3, 1, %x3 /* IEU0 Group */; \
+ add %sum, %x2, %sum /* IEU1 */; \
+ fpadd32 %F12, %f12, %F12 /* FPA */; \
+ fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \
+ inc %x4 /* IEU0 */; \
+ STORE8 /* Store (optional) */; \
+ fmovd %F14, %B14 /* FPA */; \
+ srl %x4, 1, %x4 /* IEU0 Group */; \
+ add %sum, %x3, %sum /* IEU1 */; \
+ fpadd32 %F14, %f14, %F14 /* FPA */; \
+ fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \
+ subcc %len, 64, %len /* IEU1 */; \
+ BRANCH /* CTI */; \
+ fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \
+
+#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \
+ inc %x5 /* IEU0 Group */; \
+ fpadd32 %f2, %f0, %S0 /* FPA */; \
+ srl %x5, 1, %x5 /* IEU0 Group */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ fpadd32 %f6, %f4, %S1 /* FPA */; \
+ inc %x6 /* IEU0 Group */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ inc %x7 /* IEU1 */; \
+ fpadd32 %f10, %f8, %S2 /* FPA */; \
+ fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \
+ srl %x7, 1, %x7 /* IEU0 */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ fpadd32 %f14, %f12, %S3 /* FPA */; \
+ inc %x8 /* IEU0 Group */; \
+ add %sum, %x7, %sum /* IEU1 */; \
+ fzero %fz /* FPA */; \
+ fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \
+ srl %x8, 1, %x8 /* IEU0 */; \
+ inc %x1 /* IEU1 */; \
+ fpadd32 %S0, %S1, %T0 /* FPA */; \
+ fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \
+ srl %x1, 1, %x1 /* IEU0 */; \
+ add %sum, %x8, %sum /* IEU1 */; \
+ fpadd32 %S2, %S3, %T1 /* FPA */; \
+ inc %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \
+ srl %x2, 1, %x2 /* IEU0 */; \
+ inc %x3 /* IEU1 */; \
+ fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \
+ srl %x3, 1, %x3 /* IEU0 */; \
+ add %sum, %x2, %sum /* IEU1 */; \
+ inc %x4 /* IEU0 Group */; \
+ add %sum, %x3, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \
+ srl %x4, 1, %x4 /* IEU0 */; \
+ inc %x5 /* IEU1 */; \
+ fpadd32 %T0, %T1, %U0 /* FPA */; \
+ fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ inc %x6 /* IEU0 Group */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ inc %x7 /* IEU1 */; \
+ fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \
+ ba,pt %xcc, ett /* CTI */; \
+ fmovd %FA, %FB /* FPA */; \
+
+#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \
+ END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62)
+
+#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \
+ fpadd32 %U0, %U1, %V0 /* FPA Group */; \
+ srl %x7, 1, %x7 /* IEU0 */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ std %V0, [%sp + STACKOFF] /* Store Group */; \
+ inc %x8 /* IEU0 */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \
+ srl %x8, 1, %x8 /* IEU0 */; \
+ inc %x1 /* IEU1 */; \
+ fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \
+ srl %x1, 1, %x1 /* IEU0 */; \
+ sub %sum, %x8, %sum /* IEU1 */; \
+ ldx [%sp + STACKOFF], %x8 /* Load Group */; \
+ inc %x2 /* IEU0 */; \
+ sub %sum, %x1, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \
+ srl %x2, 1, %x2 /* IEU0 */; \
+ inc %x3 /* IEU1 */; \
+ fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \
+ srl %x3, 1, %x3 /* IEU0 */; \
+ sub %sum, %x2, %sum /* IEU1 */; \
+ inc %x4 /* IEU0 Group */; \
+ sub %sum, %x3, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \
+ srl %x4, 1, %x4 /* IEU0 */; \
+ inc %x5 /* IEU1 */; \
+ fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ sub %sum, %x4, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \
+ inc %x6 /* IEU0 */; \
+ sub %sum, %x5, %sum /* IEU1 */; \
+ srl %x6, 1, %x6 /* IEU0 Group */; \
+ inc %x7 /* IEU1 */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ inc %x1 /* IEU0 Group */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ inc %x2 /* IEU1 */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ sub %sum, %x2, %sum /* IEU0 Group */; \
+ addcc %sum, %x8, %sum /* IEU Group */; \
+ bcs,a,pn %xcc, 33f /* CTI */; \
+ add %sum, 1, %sum /* IEU0 */; \
+33: /* That's it */;
+
+ .text
+ .globl csum_partial_copy_vis
+ .align 32
+/* %asi should be either ASI_P or ASI_S for csum_partial_copy resp. csum_partial_copy_from_user */
+/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */
+csum_partial_copy_vis:
+ andcc %dst, 7, %g0 /* IEU1 Group */
+ be,pt %icc, 4f /* CTI */
+ and %dst, 0x38, %g3 /* IEU0 */
+ mov 1, %g5 /* IEU0 Group */
+ andcc %dst, 2, %g0 /* IEU1 */
+ be,pt %icc, 1f /* CTI */
+ and %dst, 4, %g7 /* IEU0 Group */
+ lduha [%src] %asi, %g2 /* Load */
+ sub %len, 2, %len /* IEU0 Group */
+ add %dst, 2, %dst /* IEU1 */
+ andcc %dst, 4, %g7 /* IEU1 Group */
+ sll %g5, 16, %g5 /* IEU0 */
+ sth %g2, [%dst - 2] /* Store Group */
+ sll %g2, 16, %g2 /* IEU0 */
+ add %src, 2, %src /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, %g5, %sum /* IEU0 */
+1: lduwa [%src] %asi, %g2 /* Load */
+ brz,a,pn %g7, 4f /* CTI+IEU1 Group */
+ and %dst, 0x38, %g3 /* IEU0 */
+ add %dst, 4, %dst /* IEU0 Group */
+ sub %len, 4, %len /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: and %dst, 0x38, %g3 /* IEU0 Group */
+ stw %g2, [%dst - 4] /* Store */
+ add %src, 4, %src /* IEU1 */
+4:
+#ifdef __KERNEL__
+ wr %g0, FPRS_FEF, %fprs /* LSU Group */
+#endif
+ mov %src, %g7 /* IEU1 Group */
+ fzero %f48 /* FPA */
+ alignaddr %src, %g0, %src /* Single Group */
+ subcc %g7, %src, %g7 /* IEU1 Group */
+ be,pt %xcc, 1f /* CTI */
+ mov 0x40, %g1 /* IEU0 */
+ lduwa [%src] %asi, %g2 /* Load Group */
+ subcc %sum, %g2, %sum /* IEU1 Group+load stall */
+ bcs,a,pn %icc, 1f /* CTI */
+ sub %sum, 1, %sum /* IEU0 */
+1: srl %sum, 0, %sum /* IEU0 Group */
+ clr %g5 /* IEU1 */
+ brz,pn %g3, 3f /* CTI+IEU1 Group */
+ sub %g1, %g3, %g1 /* IEU0 */
+ ldda [%src] %asi, %f0 /* Load */
+ clr %g3 /* IEU0 Group */
+ andcc %dst, 8, %g0 /* IEU1 */
+ be,pn %icc, 1f /* CTI */
+ ldda [%src + 8] %asi, %f2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ sub %len, 8, %len /* IEU1 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ addcc %dst, 8, %dst /* IEU1 Group */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %g3 /* FPM Group */
+ fmovd %f2, %f0 /* FPA Group */
+ ldda [%src + 8] %asi, %f2 /* Load */
+ std %f16, [%dst - 8] /* Store */
+ fmovd %f50, %f48 /* FPA */
+1: andcc %g1, 0x10, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ and %g1, 0x20, %g1 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldda [%src + 16] %asi, %f4 /* Load Group */
+ add %src, 16, %src /* IEU0 */
+ add %dst, 16, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ sub %len, 16, %len /* IEU0 */
+ inc %g3 /* IEU1 */
+ std %f16, [%dst - 16] /* Store Group */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ srl %g3, 1, %o5 /* IEU0 */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ std %f18, [%dst - 8] /* Store */
+ fcmpgt32 %f50, %f48, %g3 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ ldda [%src + 8] %asi, %f2 /* Load */
+ fmovd %f4, %f0 /* FPA */
+1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */
+ rd %asi, %g2 /* LSU Group + 4 bubbles */
+ inc %g5 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldda [%src + 16] %asi, %f4 /* Load Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ add %dst, 32, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %o5 /* FPM Group */
+ inc %g3 /* IEU0 */
+ ldda [%src + 24] %asi, %f6 /* Load */
+ srl %g3, 1, %g3 /* IEU0 Group */
+ add %g5, %sum, %sum /* IEU1 */
+ ldda [%src + 32] %asi, %f8 /* Load */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ sub %len, 32, %len /* IEU0 */
+ std %f16, [%dst - 32] /* Store */
+ fcmpgt32 %f50, %f48, %o4 /* FPM Group */
+ inc %o5 /* IEU0 */
+ add %g3, %sum, %sum /* IEU1 */
+ fpadd32 %f4, %f48, %f50 /* FPA */
+ faligndata %f4, %f6, %f20 /* FPA Group */
+ srl %o5, 1, %o5 /* IEU0 */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ std %f18, [%dst - 24] /* Store */
+ fpadd32 %f6, %f50, %f48 /* FPA */
+ inc %o4 /* IEU0 Group */
+ std %f20, [%dst - 16] /* Store */
+ add %src, 32, %src /* IEU1 */
+ faligndata %f6, %f8, %f22 /* FPA */
+ fcmpgt32 %f50, %f48, %g3 /* FPM Group */
+ srl %o4, 1, %o4 /* IEU0 */
+ std %f22, [%dst - 8] /* Store */
+ add %o4, %sum, %sum /* IEU0 Group */
+3: rd %asi, %g2 /* LSU Group + 4 bubbles */
+#ifdef __KERNEL__
+4: sethi %hi(vis0s), %g7 /* IEU0 Group */
+#else
+4: rd %pc, %g7 /* LSU Group + 4 bubbles */
+#endif
+ inc %g5 /* IEU0 Group */
+ and %src, 0x38, %o4 /* IEU1 */
+ membar #StoreLoad /* LSU Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ inc %g3 /* IEU1 */
+ sll %o4, 8, %o4 /* IEU0 Group */
+ sub %len, 0xc0, %len /* IEU1 */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ srl %g3, 1, %g3 /* IEU0 */
+ add %g7, %o4, %g7 /* IEU0 Group */
+ add %g3, %sum, %sum /* IEU1 */
+#ifdef __KERNEL__
+ jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */
+#else
+ jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */
+#endif
+ fzero %f32 /* FPA */
+
+ .align 2048
+vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f62 /* FPA Group */
+ faligndata %f0, %f2, %f48 /* FPA Group */
+ fcmpgt32 %f32, %f2, %x1 /* FPM Group */
+ fpadd32 %f0, %f62, %f0 /* FPA */
+ fcmpgt32 %f32, %f4, %x2 /* FPM Group */
+ faligndata %f2, %f4, %f50 /* FPA */
+ fcmpgt32 %f62, %f0, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f52 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ inc %x1 /* IEU0 */
+ faligndata %f6, %f8, %f54 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ srl %x1, 1, %x1 /* IEU0 */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f56 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ srl %x2, 1, %x2 /* IEU0 */
+ add %sum, %x1, %sum /* IEU1 */
+ faligndata %f10, %f12, %f58 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f60 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f62 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
+vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f32), STBLK,,,,,,,,
+ ,bcs,pn %icc, vis0e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f0), STBLK,,,,,,,,
+ ,bcs,pn %icc, vis0e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f16), STBLK,,,,,,,,
+ ,bcc,pt %icc, vis0)
+vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f32,
+ ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+ ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2)
+vis0e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f0,
+ ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+ ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3)
+vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f16,
+ ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+ ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 8, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fcmpgt32 %f32, %f2, %x2 /* FPM Group */
+ faligndata %f2, %f4, %f48 /* FPA */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f50 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f52 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f54 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ srl %x2, 1, %x2 /* IEU0 */
+ faligndata %f10, %f12, %f56 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f58 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f60 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
+vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+ ,LDBLK(f32), ,STBLK,,,,,,,
+ ,bcs,pn %icc, vis1e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+ ,LDBLK(f0), ,STBLK,,,,,,,
+ ,bcs,pn %icc, vis1e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+ ,LDBLK(f16), ,STBLK,,,,,,,
+ ,bcc,pt %icc, vis1)
+vis1e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f32,
+ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+ ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e2)
+vis1e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f0,
+ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+ ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e3)
+vis1e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f16,
+ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+ ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 16, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fzero %f2 /* FPA Group */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f48 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f50 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f52 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f54 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ faligndata %f12, %f14, %f56 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f58 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
+vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+ ,LDBLK(f32), ,,STBLK,,,,,,
+ ,bcs,pn %icc, vis2e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+ ,LDBLK(f0), ,,STBLK,,,,,,
+ ,bcs,pn %icc, vis2e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+ ,LDBLK(f16), ,,STBLK,,,,,,
+ ,bcc,pt %icc, vis2)
+vis2e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f32,
+ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+ ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e2)
+vis2e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f0,
+ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+ ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e3)
+vis2e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f16,
+ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+ ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 24, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fzero %f2 /* FPA Group */
+ fzero %f4 /* FPA Group */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f48 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f50 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f52 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f54 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f56 /* FPA */
+ inc %x4 /* IEU0 */
+ srl %x4, 1, %x4 /* IEU0 Group */
+vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+ ,LDBLK(f32), ,,,STBLK,,,,,
+ ,bcs,pn %icc, vis3e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+ ,LDBLK(f0), ,,,STBLK,,,,,
+ ,bcs,pn %icc, vis3e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+ ,LDBLK(f16), ,,,STBLK,,,,,
+ ,bcc,pt %icc, vis3)
+vis3e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f32,
+ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+ ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e2)
+vis3e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f0,
+ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+ ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e3)
+vis3e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f16,
+ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+ ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 32, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fzero %f2 /* FPA Group */
+ fzero %f4 /* FPA Group */
+ fzero %f6 /* FPA Group */
+ clr %x4 /* IEU0 */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f48 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f50 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f52 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f54 /* FPA */
+vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+ ,LDBLK(f32), ,,,,STBLK,,,,
+ ,bcs,pn %icc, vis4e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+ ,LDBLK(f0), ,,,,STBLK,,,,
+ ,bcs,pn %icc, vis4e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+ ,LDBLK(f16), ,,,,STBLK,,,,
+ ,bcc,pt %icc, vis4)
+vis4e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f32,
+ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+ ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e2)
+vis4e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f0,
+ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+ ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e3)
+vis4e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f16,
+ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+ ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis5s: add %src, 128 - 40, %src /* IEU0 Group */
+ ldda [%src-88] %asi, %f10 /* Load Group */
+ ldda [%src-80] %asi, %f12 /* Load Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ faligndata %f10, %f12, %f48 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f50 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f52 /* FPA */
+vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+ ,LDBLK(f32), ,,,,,STBLK,,,
+ ,bcs,pn %icc, vis5e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+ ,LDBLK(f0), ,,,,,STBLK,,,
+ ,bcs,pn %icc, vis5e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+ ,LDBLK(f16), ,,,,,STBLK,,,
+ ,bcc,pt %icc, vis5)
+vis5e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f32,
+ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
+ ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e2)
+vis5e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f0,
+ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
+ ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e3)
+vis5e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f16,
+ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
+ ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis6s: add %src, 128 - 48, %src /* IEU0 Group */
+ ldda [%src-80] %asi, %f12 /* Load Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ faligndata %f12, %f14, %f48 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f50 /* FPA */
+vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+ ,LDBLK(f32), ,,,,,,STBLK,,
+ ,bcs,pn %icc, vis6e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+ ,LDBLK(f0), ,,,,,,STBLK,,
+ ,bcs,pn %icc, vis6e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+ ,LDBLK(f16), ,,,,,,STBLK,,
+ ,bcc,pt %icc, vis6)
+vis6e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f32,
+ ,SYNC, ,,,,,,STBLK,ST(f48,64),
+ ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e2)
+vis6e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f0,
+ ,SYNC, ,,,,,,STBLK,ST(f48,64),
+ ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e3)
+vis6e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f16,
+ ,SYNC, ,,,,,,STBLK,ST(f48,64),
+ ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis7s: add %src, 128 - 56, %src /* IEU0 Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ faddd %f32, %f32, %f12 /* FPA Group */
+ clr %x7 /* IEU0 */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fmovd %f14, %f48 /* FPA */
+vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+ ,LDBLK(f32), ,,,,,,,STBLK,
+ ,bcs,pn %icc, vis7e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+ ,LDBLK(f0), ,,,,,,,STBLK,
+ ,bcs,pn %icc, vis7e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+ ,LDBLK(f16), ,,,,,,,STBLK,
+ ,bcc,pt %icc, vis7)
+vis7e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f32,
+ ,SYNC, ,,,,,,,STBLK,
+ ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e2)
+vis7e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f0,
+ ,SYNC, ,,,,,,,STBLK,
+ ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e3)
+vis7e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f16,
+ ,SYNC, ,,,,,,,STBLK,
+ ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e1)
+e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6)
+e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6)
+e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6)
+ett: rd %gsr, %x3 /* LSU Group+4bubbles */
+ andcc %x3, 7, %x3 /* IEU1 Group */
+ add %dst, 8, %dst /* IEU0 Group */
+ bne,pn %icc, 1f /* CTI */
+ fzero %f10 /* FPA */
+ brz,a,pn %len, 2f /* CTI+IEU1 Group */
+ std %f6, [%dst - 8] /* Store */
+1: rd %asi, %x4 /* LSU Group+4bubbles */
+ sub %src, 64, %src /* IEU0 Group */
+ cmp %len, 8 /* IEU1 */
+ blu,pn %icc, 3f /* CTI */
+ wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */
+1: ldda [%src] %asi, %f2 /* Load Group */
+ fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ faligndata %f6, %f2, %f14 /* FPA Group */
+ fcmpgt32 %f10, %f12, %x5 /* FPM Group */
+ std %f14, [%dst - 16] /* Store */
+ fmovd %f2, %f6 /* FPA */
+ fmovd %f12, %f10 /* FPA Group */
+ sub %len, 8, %len /* IEU1 */
+ fzero %f16 /* FPA Group - FPU nop */
+ fzero %f18 /* FPA Group - FPU nop */
+ inc %x5 /* IEU0 */
+ srl %x5, 1, %x5 /* IEU0 Group (regdep) */
+ cmp %len, 8 /* IEU1 */
+ bgeu,pt %icc, 1b /* CTI */
+ add %x5, %sum, %sum /* IEU0 Group */
+3: brz,a,pt %x3, 2f /* CTI+IEU1 */
+ std %f6, [%dst - 8] /* Store Group */
+ st %f7, [%dst - 8] /* Store Group */
+ sub %dst, 4, %dst /* IEU0 */
+ add %len, 4, %len /* IEU1 */
+2:
+#ifdef __KERNEL__
+ sub %sp, 8, %sp /* IEU0 Group */
+#endif
+ END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
+ membar #Sync /* LSU Group */
+#ifdef __KERNEL__
+ wr %g0, 0, %fprs /* LSU Group */
+ add %sp, 8, %sp /* IEU0 Group */
+#endif
+23: brnz,pn %len, 26f /* CTI+IEU1 Group */
+24: sllx %sum, 32, %g1 /* IEU0 */
+25: addcc %sum, %g1, %src /* IEU1 Group */
+ srlx %src, 32, %src /* IEU0 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %src, 1, %src /* IEU1 */
+#ifndef __KERNEL__
+1: retl /* CTI Group brk forced */
+ srl %src, 0, %src /* IEU0 */
+#else
+1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */
+ retl /* CTI Group brk forced */
+ sllx %g4, 32, %g4 /* IEU0 */
+#endif
+26: andcc %len, 8, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ lduwa [%src] %asi, %g3 /* Load */
+ lduwa [%src+4] %asi, %g2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ sllx %g3, 32, %g5 /* IEU0 Group */
+ stw %g3, [%dst - 8] /* Store */
+ or %g5, %g2, %g5 /* IEU0 Group */
+ stw %g2, [%dst - 4] /* Store */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: andcc %len, 4, %g0 /* IEU1 Group */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g2 /* IEU0 */
+ lduwa [%src] %asi, %g7 /* Load */
+ add %src, 4, %src /* IEU0 Group */
+ add %dst, 4, %dst /* IEU1 */
+ sllx %g7, 32, %g2 /* IEU0 Group */
+ stw %g7, [%dst - 4] /* Store */
+1: andcc %len, 2, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o4 /* IEU0 Group */
+ lduha [%src] %asi, %g7 /* Load */
+ add %src, 2, %src /* IEU1 */
+ add %dst, 2, %dst /* IEU0 Group */
+ sll %g7, 16, %o4 /* IEU0 Group */
+ sth %g7, [%dst - 2] /* Store */
+1: andcc %len, 1, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o5 /* IEU0 Group */
+ lduba [%src] %asi, %g7 /* Load */
+ sll %g7, 8, %o5 /* IEU0 Group */
+ stb %g7, [%dst] /* Store */
+1: or %g2, %o4, %o4 /* IEU1 */
+ or %o5, %o4, %o4 /* IEU0 Group (regdep) */
+ addcc %o4, %sum, %sum /* IEU1 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: ba,pt %xcc, 25b /* CTI Group */
+ sllx %sum, 32, %g1 /* IEU0 */
+
+#ifdef __KERNEL__
+end:
+
+ .section __ex_table
+ .align 4
+ .word csum_partial_copy_vis, 0, end, cpc_handler
+#endif
diff --git a/arch/sparc64/lib/VISmemset.S b/arch/sparc64/lib/VISmemset.S
index d674f2a6e..4c24931ba 100644
--- a/arch/sparc64/lib/VISmemset.S
+++ b/arch/sparc64/lib/VISmemset.S
@@ -1,4 +1,4 @@
-/* $Id: VISmemset.S,v 1.1 1997/07/18 06:26:49 ralf Exp $
+/* $Id: VISmemset.S,v 1.7 1997/08/22 15:54:56 jj Exp $
* VISmemset.S: High speed memset operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -171,11 +171,22 @@ memset:
12:
#ifdef __KERNEL__
wr %g0, 0, %fprs
+#else
+#ifndef REGS_64BIT
+ wr %g0, FPRS_FEF, %fprs
#endif
- membar #Sync
+#endif
+ membar #StoreLoad | #StoreStore
9: andcc %o2, 0x78, %g5
be,pn %xcc, 13f
andcc %o2, 7, %o2
+#ifdef __KERNEL__
+14: srl %g5, 1, %o3
+ sethi %hi(13f), %o4
+ sub %o4, %o3, %o4
+ jmpl %o4 + %lo(13f), %g0
+ add %o0, %g5, %o0
+#else
14: rd %pc, %o4
#ifdef REGS_64BIT
srl %g5, 1, %o3
@@ -185,6 +196,7 @@ memset:
#endif
jmpl %o4 + (13f - 14b), %g0
add %o0, %g5, %o0
+#endif
12: SET_BLOCKS(%o0, 0x68, %o1)
SET_BLOCKS(%o0, 0x48, %o1)
SET_BLOCKS(%o0, 0x28, %o1)
diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
index 59083aa02..7d5b240ad 100644
--- a/arch/sparc64/lib/blockops.S
+++ b/arch/sparc64/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.10 1997/06/24 17:29:10 jj Exp $
+/* $Id: blockops.S,v 1.11 1997/07/29 09:35:36 davem Exp $
* arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -15,7 +15,7 @@ __bfill64: /* %o0 = buf, %o1= ptr to pattern */
wr %g0, FPRS_FEF, %fprs ! FPU Group
ldd [%o1], %f48 ! Load Group
wr %g0, ASI_BLK_P, %asi ! LSU Group
- membar #StoreStore | #LoadStore ! LSU Group
+ membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
mov 32, %g2 ! IEU0 Group
/* Cannot perform real arithmatic on the pattern, that can
@@ -36,7 +36,7 @@ __bfill64: /* %o0 = buf, %o1= ptr to pattern */
subcc %g2, 1, %g2 ! IEU1 Group
bne,pt %icc, 1b ! CTI
add %o0, 0x100, %o0 ! IEU0
- membar #Sync ! LSU Group
+ membar #StoreLoad | #StoreStore ! LSU Group
jmpl %o7 + 0x8, %g0 ! CTI Group brk forced
wr %g0, 0, %fprs ! FPU Group
@@ -56,7 +56,7 @@ __bzero_1page:
faddd %f0, %f2, %f12 ! FPA Group
fmuld %f0, %f2, %f14 ! FPM
wr %g0, ASI_BLK_P, %asi ! LSU Group
- membar #StoreStore | #LoadStore ! LSU Group
+ membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
1: stda %f0, [%o0 + 0x00] %asi ! Store Group
stda %f0, [%o0 + 0x40] %asi ! Store Group
stda %f0, [%o0 + 0x80] %asi ! Store Group
@@ -65,6 +65,6 @@ __bzero_1page:
subcc %g1, 1, %g1 ! IEU1
bne,pt %icc, 1b ! CTI
add %o0, 0x100, %o0 ! IEU0 Group
- membar #Sync ! LSU Group
+ membar #StoreLoad | #StoreStore ! LSU Group
jmpl %o7 + 0x8, %g0 ! CTI Group brk forced
wr %g0, 0, %fprs ! FPU Group
diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S
index 703370fc6..5f35f136b 100644
--- a/arch/sparc64/lib/checksum.S
+++ b/arch/sparc64/lib/checksum.S
@@ -23,456 +23,456 @@
* are two fold. Firstly, they cannot pair with jack shit,
* and also they only add in the 32-bit carry condition bit
* into the accumulated sum. The following is much better.
- *
- * This should run at max bandwidth for ecache hits, a better
- * technique is to use VIS and fpu operations. This is already
- * done for csum_partial, needs to be written for the copy stuff
- * still.
+ * For larger chunks we use VIS code, which is faster ;)
*/
- .text
- .globl __csum_partial_copy_start, __csum_partial_copy_end
-__csum_partial_copy_start:
+#define src o0
+#define dst o1
+#define len o2
+#define sum o3
+ .text
/* I think I have an erection... Once _AGAIN_ the SunSoft
* engineers are caught asleep at the keyboard, tsk tsk...
*/
-#define CSUMCOPY_ECACHE_LOAD(src, off, t0, t1, t2, t3, t4, t5, t6, t7) \
- ldxa [src + off + 0x00] %asi, t0; \
- ldxa [src + off + 0x08] %asi, t1; \
- ldxa [src + off + 0x10] %asi, t2; \
- ldxa [src + off + 0x18] %asi, t3; \
- ldxa [src + off + 0x20] %asi, t4; \
- ldxa [src + off + 0x28] %asi, t5; \
- ldxa [src + off + 0x30] %asi, t6; \
- ldxa [src + off + 0x38] %asi, t7; \
+#define CSUMCOPY_ECACHE_LOAD(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ ldxa [%src + off + 0x00] %asi, t0; \
+ ldxa [%src + off + 0x08] %asi, t1; \
+ ldxa [%src + off + 0x10] %asi, t2; \
+ ldxa [%src + off + 0x18] %asi, t3; \
+ ldxa [%src + off + 0x20] %asi, t4; \
+ ldxa [%src + off + 0x28] %asi, t5; \
+ ldxa [%src + off + 0x30] %asi, t6; \
+ ldxa [%src + off + 0x38] %asi, t7; \
nop; nop; /* DO NOT TOUCH THIS!!!!! */
-#define CSUMCOPY_EC_STALIGNED_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
- stx t0, [dest + off - 0x40]; \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STALIGNED_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ stx t0, [%dst + off - 0x40]; \
+ addcc %sum, t0, %sum; \
bcc,pt %xcc, 11f; \
- ldxa [src + off + 0x00] %asi, t0; \
- add sum, 1, sum; \
-11: stx t1, [dest + off - 0x38]; \
- addcc sum, t1, sum; \
+ ldxa [%src + off + 0x00] %asi, t0; \
+ add %sum, 1, %sum; \
+11: stx t1, [%dst + off - 0x38]; \
+ addcc %sum, t1, %sum; \
bcc,pt %xcc, 12f; \
- ldxa [src + off + 0x08] %asi, t1; \
- add sum, 1, sum; \
-12: stx t2, [dest + off - 0x30]; \
- addcc sum, t2, sum; \
+ ldxa [%src + off + 0x08] %asi, t1; \
+ add %sum, 1, %sum; \
+12: stx t2, [%dst + off - 0x30]; \
+ addcc %sum, t2, %sum; \
bcc,pt %xcc, 13f; \
- ldxa [src + off + 0x10] %asi, t2; \
- add sum, 1, sum; \
-13: stx t3, [dest + off - 0x28]; \
- addcc sum, t3, sum; \
+ ldxa [%src + off + 0x10] %asi, t2; \
+ add %sum, 1, %sum; \
+13: stx t3, [%dst + off - 0x28]; \
+ addcc %sum, t3, %sum; \
bcc,pt %xcc, 14f; \
- ldxa [src + off + 0x18] %asi, t3; \
- add sum, 1, sum; \
-14: stx t4, [dest + off - 0x20]; \
- addcc sum, t4, sum; \
+ ldxa [%src + off + 0x18] %asi, t3; \
+ add %sum, 1, %sum; \
+14: stx t4, [%dst + off - 0x20]; \
+ addcc %sum, t4, %sum; \
bcc,pt %xcc, 15f; \
- ldxa [src + off + 0x20] %asi, t4; \
- add sum, 1, sum; \
-15: stx t5, [dest + off - 0x18]; \
- addcc sum, t5, sum; \
+ ldxa [%src + off + 0x20] %asi, t4; \
+ add %sum, 1, %sum; \
+15: stx t5, [%dst + off - 0x18]; \
+ addcc %sum, t5, %sum; \
bcc,pt %xcc, 16f; \
- ldxa [src + off + 0x28] %asi, t5; \
- add sum, 1, sum; \
-16: stx t6, [dest + off - 0x10]; \
- addcc sum, t6, sum; \
+ ldxa [%src + off + 0x28] %asi, t5; \
+ add %sum, 1, %sum; \
+16: stx t6, [%dst + off - 0x10]; \
+ addcc %sum, t6, %sum; \
bcc,pt %xcc, 17f; \
- ldxa [src + off + 0x30] %asi, t6; \
- add sum, 1, sum; \
-17: stx t7, [dest + off - 0x08]; \
- addcc sum, t7, sum; \
+ ldxa [%src + off + 0x30] %asi, t6; \
+ add %sum, 1, %sum; \
+17: stx t7, [%dst + off - 0x08]; \
+ addcc %sum, t7, %sum; \
bcc,pt %xcc, 18f; \
- ldxa [src + off + 0x38] %asi, t7; \
- add sum, 1, sum; \
+ ldxa [%src + off + 0x38] %asi, t7; \
+ add %sum, 1, %sum; \
18:
-#define CSUMCOPY_EC_STUNALIGN_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
- stw t0, [dest + off - 0x3c]; \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STUNALIGN_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ stw t0, [%dst + off - 0x3c]; \
+ addcc %sum, t0, %sum; \
srlx t0, 32, t0; \
- stw t0, [dest + off - 0x40]; \
+ stw t0, [%dst + off - 0x40]; \
bcc,pt %xcc, 21f; \
- ldxa [src + off + 0x00] %asi, t0; \
- add sum, 1, sum; \
-21: stw t1, [dest + off - 0x34]; \
- addcc sum, t1, sum; \
+ ldxa [%src + off + 0x00] %asi, t0; \
+ add %sum, 1, %sum; \
+21: stw t1, [%dst + off - 0x34]; \
+ addcc %sum, t1, %sum; \
srlx t1, 32, t1; \
- stw t1, [dest + off - 0x38]; \
+ stw t1, [%dst + off - 0x38]; \
bcc,pt %xcc, 22f; \
- ldxa [src + off + 0x08] %asi, t1; \
- add sum, 1, sum; \
-22: stw t2, [dest + off - 0x2c]; \
- addcc sum, t2, sum; \
+ ldxa [%src + off + 0x08] %asi, t1; \
+ add %sum, 1, %sum; \
+22: stw t2, [%dst + off - 0x2c]; \
+ addcc %sum, t2, %sum; \
srlx t2, 32, t2; \
- stw t2, [dest + off - 0x30]; \
+ stw t2, [%dst + off - 0x30]; \
bcc,pt %xcc, 23f; \
- ldxa [src + off + 0x10] %asi, t2; \
- add sum, 1, sum; \
-23: stw t3, [dest + off - 0x24]; \
- addcc sum, t3, sum; \
+ ldxa [%src + off + 0x10] %asi, t2; \
+ add %sum, 1, %sum; \
+23: stw t3, [%dst + off - 0x24]; \
+ addcc %sum, t3, %sum; \
srlx t3, 32, t3; \
- stw t3, [dest + off - 0x28]; \
+ stw t3, [%dst + off - 0x28]; \
bcc,pt %xcc, 24f; \
- ldxa [src + off + 0x18] %asi, t3; \
- add sum, 1, sum; \
-24: stw t4, [dest + off - 0x1c]; \
- addcc sum, t4, sum; \
+ ldxa [%src + off + 0x18] %asi, t3; \
+ add %sum, 1, %sum; \
+24: stw t4, [%dst + off - 0x1c]; \
+ addcc %sum, t4, %sum; \
srlx t4, 32, t4; \
- stw t4, [dest + off - 0x20]; \
+ stw t4, [%dst + off - 0x20]; \
bcc,pt %xcc, 25f; \
- ldxa [src + off + 0x20] %asi, t4; \
- add sum, 1, sum; \
-25: stw t5, [dest + off - 0x14]; \
- addcc sum, t5, sum; \
+ ldxa [%src + off + 0x20] %asi, t4; \
+ add %sum, 1, %sum; \
+25: stw t5, [%dst + off - 0x14]; \
+ addcc %sum, t5, %sum; \
srlx t5, 32, t5; \
- stw t5, [dest + off - 0x18]; \
+ stw t5, [%dst + off - 0x18]; \
bcc,pt %xcc, 26f; \
- ldxa [src + off + 0x28] %asi, t5; \
- add sum, 1, sum; \
-26: stw t6, [dest + off - 0x0c]; \
- addcc sum, t6, sum; \
+ ldxa [%src + off + 0x28] %asi, t5; \
+ add %sum, 1, %sum; \
+26: stw t6, [%dst + off - 0x0c]; \
+ addcc %sum, t6, %sum; \
srlx t6, 32, t6; \
- stw t6, [dest + off - 0x10]; \
+ stw t6, [%dst + off - 0x10]; \
bcc,pt %xcc, 27f; \
- ldxa [src + off + 0x30] %asi, t6; \
- add sum, 1, sum; \
-27: stw t7, [dest + off - 0x04]; \
- addcc sum, t7, sum; \
+ ldxa [%src + off + 0x30] %asi, t6; \
+ add %sum, 1, %sum; \
+27: stw t7, [%dst + off - 0x04]; \
+ addcc %sum, t7, %sum; \
srlx t7, 32, t7; \
- stw t7, [dest + off - 0x08]; \
+ stw t7, [%dst + off - 0x08]; \
bcc,pt %xcc, 28f; \
- ldxa [src + off + 0x38] %asi, t7; \
- add sum, 1, sum; \
+ ldxa [%src + off + 0x38] %asi, t7; \
+ add %sum, 1, %sum; \
28:
-#define CSUMCOPY_EC_STALIGNED(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7) \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STALIGNED(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ addcc %sum, t0, %sum; \
bcc,pt %xcc, 31f; \
- stx t0, [dest + off + 0x00]; \
- add sum, 1, sum; \
-31: addcc sum, t1, sum; \
+ stx t0, [%dst + off + 0x00]; \
+ add %sum, 1, %sum; \
+31: addcc %sum, t1, %sum; \
bcc,pt %xcc, 32f; \
- stx t1, [dest + off + 0x08]; \
- add sum, 1, sum; \
-32: addcc sum, t2, sum; \
+ stx t1, [%dst + off + 0x08]; \
+ add %sum, 1, %sum; \
+32: addcc %sum, t2, %sum; \
bcc,pt %xcc, 33f; \
- stx t2, [dest + off + 0x10]; \
- add sum, 1, sum; \
-33: addcc sum, t3, sum; \
+ stx t2, [%dst + off + 0x10]; \
+ add %sum, 1, %sum; \
+33: addcc %sum, t3, %sum; \
bcc,pt %xcc, 34f; \
- stx t3, [dest + off + 0x18]; \
- add sum, 1, sum; \
-34: addcc sum, t4, sum; \
+ stx t3, [%dst + off + 0x18]; \
+ add %sum, 1, %sum; \
+34: addcc %sum, t4, %sum; \
bcc,pt %xcc, 35f; \
- stx t4, [dest + off + 0x20]; \
- add sum, 1, sum; \
-35: addcc sum, t5, sum; \
+ stx t4, [%dst + off + 0x20]; \
+ add %sum, 1, %sum; \
+35: addcc %sum, t5, %sum; \
bcc,pt %xcc, 36f; \
- stx t5, [dest + off + 0x28]; \
- add sum, 1, sum; \
-36: addcc sum, t6, sum; \
+ stx t5, [%dst + off + 0x28]; \
+ add %sum, 1, %sum; \
+36: addcc %sum, t6, %sum; \
bcc,pt %xcc, 37f; \
- stx t6, [dest + off + 0x30]; \
- add sum, 1, sum; \
-37: addcc sum, t7, sum; \
+ stx t6, [%dst + off + 0x30]; \
+ add %sum, 1, %sum; \
+37: addcc %sum, t7, %sum; \
bcc,pt %xcc, 38f; \
- stx t7, [dest + off + 0x38]; \
- add sum, 1, sum; \
+ stx t7, [%dst + off + 0x38]; \
+ add %sum, 1, %sum; \
38:
-#define CSUMCOPY_EC_STUNALIGN(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7) \
- stw t0, [dest + off + 0x04]; \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STUNALIGN(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ stw t0, [%dst + off + 0x04]; \
+ addcc %sum, t0, %sum; \
srlx t0, 32, t0; \
bcc,pt %xcc, 41f; \
- stw t0, [dest + off + 0x00]; \
- add sum, 1, sum; \
-41: stw t1, [dest + off + 0x0c]; \
- addcc sum, t1, sum; \
+ stw t0, [%dst + off + 0x00]; \
+ add %sum, 1, %sum; \
+41: stw t1, [%dst + off + 0x0c]; \
+ addcc %sum, t1, %sum; \
srlx t1, 32, t1; \
bcc,pt %xcc, 42f; \
- stw t1, [dest + off + 0x08]; \
- add sum, 1, sum; \
-42: stw t2, [dest + off + 0x14]; \
- addcc sum, t2, sum; \
+ stw t1, [%dst + off + 0x08]; \
+ add %sum, 1, %sum; \
+42: stw t2, [%dst + off + 0x14]; \
+ addcc %sum, t2, %sum; \
srlx t2, 32, t2; \
bcc,pt %xcc, 43f; \
- stw t2, [dest + off + 0x10]; \
- add sum, 1, sum; \
-43: stw t3, [dest + off + 0x1c]; \
- addcc sum, t3, sum; \
+ stw t2, [%dst + off + 0x10]; \
+ add %sum, 1, %sum; \
+43: stw t3, [%dst + off + 0x1c]; \
+ addcc %sum, t3, %sum; \
srlx t3, 32, t3; \
bcc,pt %xcc, 44f; \
- stw t3, [dest + off + 0x18]; \
- add sum, 1, sum; \
-44: stw t4, [dest + off + 0x24]; \
- addcc sum, t4, sum; \
+ stw t3, [%dst + off + 0x18]; \
+ add %sum, 1, %sum; \
+44: stw t4, [%dst + off + 0x24]; \
+ addcc %sum, t4, %sum; \
srlx t4, 32, t4; \
bcc,pt %xcc, 45f; \
- stw t4, [dest + off + 0x20]; \
- add sum, 1, sum; \
-45: stw t5, [dest + off + 0x2c]; \
- addcc sum, t5, sum; \
+ stw t4, [%dst + off + 0x20]; \
+ add %sum, 1, %sum; \
+45: stw t5, [%dst + off + 0x2c]; \
+ addcc %sum, t5, %sum; \
srlx t5, 32, t5; \
bcc,pt %xcc, 46f; \
- stw t5, [dest + off + 0x28]; \
- add sum, 1, sum; \
-46: stw t6, [dest + off + 0x34]; \
- addcc sum, t6, sum; \
+ stw t5, [%dst + off + 0x28]; \
+ add %sum, 1, %sum; \
+46: stw t6, [%dst + off + 0x34]; \
+ addcc %sum, t6, %sum; \
srlx t6, 32, t6; \
bcc,pt %xcc, 47f; \
- stw t6, [dest + off + 0x30]; \
- add sum, 1, sum; \
-47: stw t7, [dest + off + 0x3c]; \
- addcc sum, t7, sum; \
+ stw t6, [%dst + off + 0x30]; \
+ add %sum, 1, %sum; \
+47: stw t7, [%dst + off + 0x3c]; \
+ addcc %sum, t7, %sum; \
srlx t7, 32, t7; \
bcc,pt %xcc, 48f; \
- stw t7, [dest + off + 0x38]; \
- add sum, 1, sum; \
+ stw t7, [%dst + off + 0x38]; \
+ add %sum, 1, %sum; \
48:
-#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1) \
- ldxa [src - off - 0x08] %asi, t0; \
- ldxa [src - off - 0x00] %asi, t1; \
+#define CSUMCOPY_LASTCHUNK(off, t0, t1) \
+ ldxa [%src - off - 0x08] %asi, t0; \
+ ldxa [%src - off - 0x00] %asi, t1; \
nop; nop; \
- addcc t0, sum, sum; \
- stw t0, [dst - off - 0x04]; \
+ addcc t0, %sum, %sum; \
+ stw t0, [%dst - off - 0x04]; \
srlx t0, 32, t0; \
bcc,pt %xcc, 51f; \
- stw t0, [dst - off - 0x08]; \
- add sum, 1, sum; \
-51: addcc t1, sum, sum; \
- stw t1, [dst - off + 0x04]; \
+ stw t0, [%dst - off - 0x08]; \
+ add %sum, 1, %sum; \
+51: addcc t1, %sum, %sum; \
+ stw t1, [%dst - off + 0x04]; \
srlx t1, 32, t1; \
bcc,pt %xcc, 52f; \
- stw t1, [dst - off - 0x00]; \
- add sum, 1, sum; \
+ stw t1, [%dst - off - 0x00]; \
+ add %sum, 1, %sum; \
52:
+cpc_start:
cc_end_cruft:
- andcc %o3, 8, %g0 ! IEU1 Group
+ andcc %g7, 8, %g0 ! IEU1 Group
be,pn %icc, 1f ! CTI
- and %o3, 4, %g5 ! IEU0
- ldxa [%o0 + 0x00] %asi, %g2 ! Load Group
- add %o1, 8, %o1 ! IEU0
- add %o0, 8, %o0 ! IEU1
- addcc %g2, %g7, %g7 ! IEU1 Group + 2 bubbles
- stw %g2, [%o1 - 0x04] ! Store
+ and %g7, 4, %g5 ! IEU0
+ ldxa [%src + 0x00] %asi, %g2 ! Load Group
+ add %dst, 8, %dst ! IEU0
+ add %src, 8, %src ! IEU1
+ addcc %g2, %sum, %sum ! IEU1 Group + 2 bubbles
+ stw %g2, [%dst - 0x04] ! Store
srlx %g2, 32, %g2 ! IEU0
bcc,pt %xcc, 1f ! CTI Group
- stw %g2, [%o1 - 0x08] ! Store
- add %g7, 1, %g7 ! IEU0
+ stw %g2, [%dst - 0x08] ! Store
+ add %sum, 1, %sum ! IEU0
1: brz,pt %g5, 1f ! CTI Group
clr %g2 ! IEU0
- lduwa [%o0 + 0x00] %asi, %g2 ! Load
- add %o1, 4, %o1 ! IEU0 Group
- add %o0, 4, %o0 ! IEU1
- stw %g2, [%o1 - 0x04] ! Store Group + 2 bubbles
+ lduwa [%src + 0x00] %asi, %g2 ! Load
+ add %dst, 4, %dst ! IEU0 Group
+ add %src, 4, %src ! IEU1
+ stw %g2, [%dst - 0x04] ! Store Group + 2 bubbles
sllx %g2, 32, %g2 ! IEU0
-1: andcc %o3, 2, %g0 ! IEU1
+1: andcc %g7, 2, %g0 ! IEU1
be,pn %icc, 1f ! CTI Group
clr %o4 ! IEU1
- lduha [%o0 + 0x00] %asi, %o4 ! Load
- add %o0, 2, %o0 ! IEU0 Group
- add %o1, 2, %o1 ! IEU1
- sth %o4, [%o1 - 0x2] ! Store Group + 2 bubbles
+ lduha [%src + 0x00] %asi, %o4 ! Load
+ add %src, 2, %src ! IEU0 Group
+ add %dst, 2, %dst ! IEU1
+ sth %o4, [%dst - 0x2] ! Store Group + 2 bubbles
sll %o4, 16, %o4 ! IEU0
-1: andcc %o3, 1, %g0 ! IEU1
+1: andcc %g7, 1, %g0 ! IEU1
be,pn %icc, 1f ! CTI Group
clr %o5 ! IEU0
- lduba [%o0 + 0x00] %asi, %o5 ! Load
- stb %o5, [%o1 + 0x00] ! Store Group + 2 bubbles
+ lduba [%src + 0x00] %asi, %o5 ! Load
+ stb %o5, [%dst + 0x00] ! Store Group + 2 bubbles
sll %o5, 8, %o5 ! IEU0
1: or %g2, %o4, %o4 ! IEU1
or %o5, %o4, %o4 ! IEU0 Group
- addcc %o4, %g7, %g7 ! IEU1
+ addcc %o4, %sum, %sum ! IEU1
bcc,pt %xcc, ccfold ! CTI
sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 Group
b,pt %xcc, ccfold ! CTI
- add %g7, 1, %g7 ! IEU1
+ add %sum, 1, %sum ! IEU1
cc_fixit:
bl,a,pn %icc, ccte ! CTI
- andcc %g1, 0xf, %o3 ! IEU1 Group
- andcc %o0, 1, %g0 ! IEU1 Group
- bne,pn %icc, ccslow ! CTI
- andcc %o0, 2, %g0 ! IEU1 Group
+ andcc %len, 0xf, %g7 ! IEU1 Group
+ andcc %src, 2, %g0 ! IEU1 Group
be,pn %icc, 1f ! CTI
- andcc %o0, 0x4, %g0 ! IEU1 Group
- lduha [%o0 + 0x00] %asi, %g4 ! Load
- sub %g1, 2, %g1 ! IEU0
- add %o0, 2, %o0 ! IEU0 Group
- add %o1, 2, %o1 ! IEU1
+ andcc %src, 0x4, %g0 ! IEU1 Group
+ lduha [%src + 0x00] %asi, %g4 ! Load
+ sub %len, 2, %len ! IEU0
+ add %src, 2, %src ! IEU0 Group
+ add %dst, 2, %dst ! IEU1
sll %g4, 16, %g3 ! IEU0 Group + 1 bubble
- addcc %g3, %g7, %g7 ! IEU1
+ addcc %g3, %sum, %sum ! IEU1
bcc,pt %xcc, 0f ! CTI
- srl %g7, 16, %g3 ! IEU0 Group
+ srl %sum, 16, %g3 ! IEU0 Group
add %g3, 1, %g3 ! IEU0 4 clocks (mispredict)
-0: andcc %o0, 0x4, %g0 ! IEU1 Group
- sth %g4, [%o1 - 0x2] ! Store
- sll %g7, 16, %g7 ! IEU0
+0: andcc %src, 0x4, %g0 ! IEU1 Group
+ sth %g4, [%dst - 0x2] ! Store
+ sll %sum, 16, %sum ! IEU0
sll %g3, 16, %g3 ! IEU0 Group
- srl %g7, 16, %g7 ! IEU0 Group
- or %g3, %g7, %g7 ! IEU0 Group (regdep)
+ srl %sum, 16, %sum ! IEU0 Group
+ or %g3, %sum, %sum ! IEU0 Group (regdep)
1: be,pt %icc, cc_dword_aligned ! CTI
- andn %g1, 0xff, %g2 ! IEU1
- lduwa [%o0 + 0x00] %asi, %g4 ! Load Group
- sub %g1, 4, %g1 ! IEU0
- add %o0, 4, %o0 ! IEU1
- add %o1, 4, %o1 ! IEU0 Group
- addcc %g4, %g7, %g7 ! IEU1 Group + 1 bubble
- stw %g4, [%o1 - 0x4] ! Store
+ andn %len, 0xff, %g2 ! IEU1
+ lduwa [%src + 0x00] %asi, %g4 ! Load Group
+ sub %len, 4, %len ! IEU0
+ add %src, 4, %src ! IEU1
+ add %dst, 4, %dst ! IEU0 Group
+ addcc %g4, %sum, %sum ! IEU1 Group + 1 bubble
+ stw %g4, [%dst - 0x4] ! Store
bcc,pt %xcc, cc_dword_aligned ! CTI
- andn %g1, 0xff, %g2 ! IEU0 Group
+ andn %len, 0xff, %g2 ! IEU0 Group
b,pt %xcc, cc_dword_aligned ! CTI 4 clocks (mispredict)
- add %g7, 1, %g7 ! IEU0
+ add %sum, 1, %sum ! IEU0
.align 32
- .globl __csum_partial_copy_sparc_generic, csum_partial_copy
-csum_partial_copy:
-__csum_partial_copy_sparc_generic: /* %o0=src, %o1=dest, %g1=len, %g7=sum */
- xorcc %o0, %o1, %o4 ! IEU1 Group
- srl %g7, 0, %g7 ! IEU0
+ .globl csum_partial_copy_sparc64
+csum_partial_copy_sparc64: /* %o0=src, %o1=dest, %o2=len, %o3=sum */
+ xorcc %src, %dst, %o4 ! IEU1 Group
+ srl %sum, 0, %sum ! IEU0
andcc %o4, 3, %g0 ! IEU1 Group
- srl %g1, 0, %g1 ! IEU0
+ srl %len, 0, %len ! IEU0
+ bne,pn %icc, ccslow ! CTI
+ andcc %src, 1, %g0 ! IEU1 Group
bne,pn %icc, ccslow ! CTI
- andcc %o0, 7, %g0 ! IEU1 Group
+ cmp %len, 256 ! IEU1 Group
+ bgeu,pt %icc, csum_partial_copy_vis ! CTI
+ andcc %src, 7, %g0 ! IEU1 Group
be,pt %icc, cc_dword_aligned ! CTI
- andn %g1, 0xff, %g2 ! IEU0
+ andn %len, 0xff, %g2 ! IEU0
b,pt %xcc, cc_fixit ! CTI Group
- cmp %g1, 6 ! IEU1
+ cmp %len, 6 ! IEU1
cc_dword_aligned:
brz,pn %g2, 3f ! CTI Group
- andcc %o1, 4, %g0 ! IEU1 Group (brz uses IEU1)
+ andcc %dst, 4, %g0 ! IEU1 Group (brz uses IEU1)
be,pn %icc, ccdbl + 4 ! CTI
-5: CSUMCOPY_ECACHE_LOAD( %o0, 0x00, %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN( %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+5: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
10:
- sub %g1, 256, %g1 ! IEU0 Group
- add %o0, 256, %o0 ! IEU1
- andncc %g1, 0xff, %g0 ! IEU1 Group
+ sub %len, 256, %len ! IEU0 Group
+ add %src, 256, %src ! IEU1
+ andncc %len, 0xff, %g0 ! IEU1 Group
bne,pt %icc, 5b ! CTI
- add %o1, 256, %o1 ! IEU0
-3: andcc %g1, 0xf0, %o2 ! IEU1 Group
+ add %dst, 256, %dst ! IEU0
+3: andcc %len, 0xf0, %g1 ! IEU1 Group
ccmerge:be,pn %icc, ccte ! CTI
- andcc %g1, 0xf, %o3 ! IEU1 Group
- sll %o2, 2, %o4 ! IEU0
-13: rd %pc, %o5 ! LSU Group + 4 clocks
- add %o0, %o2, %o0 ! IEU0 Group
- sub %o5, %o4, %o5 ! IEU1 Group
- jmpl %o5 + (12f - 13b), %g0 ! CTI Group brk forced
- add %o1, %o2, %o1 ! IEU0 Group
-cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xe8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xd8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xc8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xb8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xa8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x98,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x88,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x78,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x48,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x38,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3)
+ andcc %len, 0xf, %g7 ! IEU1 Group
+ sll %g1, 2, %o4 ! IEU0
+13: sethi %hi(12f), %o5 ! IEU0 Group
+ add %src, %g1, %src ! IEU1
+ sub %o5, %o4, %o5 ! IEU0 Group
+ jmpl %o5 + %lo(12f), %g0 ! CTI Group brk forced
+ add %dst, %g1, %dst ! IEU0 Group
+cctbl: CSUMCOPY_LASTCHUNK(0xe8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xd8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xc8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xb8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xa8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x98,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x88,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x78,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x68,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x58,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x48,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x38,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x28,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x18,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x08,%g2,%g3)
12:
- andcc %g1, 0xf, %o3 ! IEU1 Group
+ andcc %len, 0xf, %g7 ! IEU1 Group
ccte: bne,pn %icc, cc_end_cruft ! CTI
sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
-ccfold: sllx %g7, 32, %o0 ! IEU0 Group
- addcc %g7, %o0, %o0 ! IEU1 Group (regdep)
+ccfold: sllx %sum, 32, %o0 ! IEU0 Group
+ addcc %sum, %o0, %o0 ! IEU1 Group (regdep)
srlx %o0, 32, %o0 ! IEU0 Group (regdep)
bcs,a,pn %xcc, 1f ! CTI
add %o0, 1, %o0 ! IEU1 4 clocks (mispredict)
1: retl ! CTI Group brk forced
sllx %g4, 32,%g4 ! IEU0 Group
-ccdbl: CSUMCOPY_ECACHE_LOAD( %o0, 0x00, %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED( %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ccdbl: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
11:
- sub %g1, 256, %g1 ! IEU0 Group
- add %o0, 256, %o0 ! IEU1
- andncc %g1, 0xff, %g0 ! IEU1 Group
+ sub %len, 256, %len ! IEU0 Group
+ add %src, 256, %src ! IEU1
+ andncc %len, 0xff, %g0 ! IEU1 Group
bne,pt %icc, ccdbl ! CTI
- add %o1, 256, %o1 ! IEU0
+ add %dst, 256, %dst ! IEU0
b,pt %xcc, ccmerge ! CTI Group
- andcc %g1, 0xf0, %o2 ! IEU1
+ andcc %len, 0xf0, %g1 ! IEU1
ccslow: mov 0, %g5
- brlez,pn %g1, 4f
- andcc %o0, 1, %o5
+ brlez,pn %len, 4f
+ andcc %src, 1, %o5
be,a,pt %icc, 1f
- srl %g1, 1, %o3
- sub %g1, 1, %g1
- lduba [%o0] %asi, %g5
- add %o0, 1, %o0
- stb %g5, [%o1]
- srl %g1, 1, %o3
- add %o1, 1, %o1
-1: brz,a,pn %o3, 3f
- andcc %g1, 1, %g0
- andcc %o0, 2, %g0
+ srl %len, 1, %g7
+ sub %len, 1, %len
+ lduba [%src] %asi, %g5
+ add %src, 1, %src
+ stb %g5, [%dst]
+ srl %len, 1, %g7
+ add %dst, 1, %dst
+1: brz,a,pn %g7, 3f
+ andcc %len, 1, %g0
+ andcc %src, 2, %g0
be,a,pt %icc, 1f
- srl %o3, 1, %o3
- lduha [%o0] %asi, %o4
- sub %g1, 2, %g1
+ srl %g7, 1, %g7
+ lduha [%src] %asi, %o4
+ sub %len, 2, %len
srl %o4, 8, %g2
- sub %o3, 1, %o3
- stb %g2, [%o1]
+ sub %g7, 1, %g7
+ stb %g2, [%dst]
add %o4, %g5, %g5
- stb %o4, [%o1 + 1]
- add %o0, 2, %o0
- srl %o3, 1, %o3
- add %o1, 2, %o1
-1: brz,a,pn %o3, 2f
- andcc %g1, 2, %g0
- lda [%o0] %asi, %o4
+ stb %o4, [%dst + 1]
+ add %src, 2, %src
+ srl %g7, 1, %g7
+ add %dst, 2, %dst
+1: brz,a,pn %g7, 2f
+ andcc %len, 2, %g0
+ lduwa [%src] %asi, %o4
5: srl %o4, 24, %g2
srl %o4, 16, %g3
- stb %g2, [%o1]
+ stb %g2, [%dst]
srl %o4, 8, %g2
- stb %g3, [%o1 + 1]
- add %o0, 4, %o0
- stb %g2, [%o1 + 2]
+ stb %g3, [%dst + 1]
+ add %src, 4, %src
+ stb %g2, [%dst + 2]
addcc %o4, %g5, %g5
- stb %o4, [%o1 + 3]
- addc %g5, %g0, %g5 ! I am now to lazy to optimize this (question is if it
- add %o1, 4, %o1 ! is worthy). Maybe some day - with the sll/srl
- subcc %o3, 1, %o3 ! tricks
+ stb %o4, [%dst + 3]
+ addc %g5, %g0, %g5
+ add %dst, 4, %dst
+ subcc %g7, 1, %g7
bne,a,pt %icc, 5b
- lda [%o0] %asi, %o4
+ lduwa [%src] %asi, %o4
sll %g5, 16, %g2
srl %g5, 16, %g5
srl %g2, 16, %g2
- andcc %g1, 2, %g0
+ andcc %len, 2, %g0
add %g2, %g5, %g5
2: be,a,pt %icc, 3f
- andcc %g1, 1, %g0
- lduha [%o0] %asi, %o4
- andcc %g1, 1, %g0
+ andcc %len, 1, %g0
+ lduha [%src] %asi, %o4
+ andcc %len, 1, %g0
srl %o4, 8, %g2
- add %o0, 2, %o0
- stb %g2, [%o1]
+ add %src, 2, %src
+ stb %g2, [%dst]
add %g5, %o4, %g5
- stb %o4, [%o1 + 1]
- add %o1, 2, %o1
+ stb %o4, [%dst + 1]
+ add %dst, 2, %dst
3: be,a,pt %icc, 1f
sll %g5, 16, %o4
- lduba [%o0] %asi, %g2
+ lduba [%src] %asi, %g2
sll %g2, 8, %o4
- stb %g2, [%o1]
+ stb %g2, [%dst]
add %g5, %o4, %g5
sll %g5, 16, %o4
1: addcc %o4, %g5, %g5
@@ -484,8 +484,22 @@ ccslow: mov 0, %g5
and %o4, 0xff, %o4
sll %g2, 8, %g2
or %g2, %o4, %g5
-4: addcc %g7, %g5, %g7
- addc %g0, %g7, %o0
+4: addcc %sum, %g5, %sum
+ addc %g0, %sum, %o0
retl
srl %o0, 0, %o0
-__csum_partial_copy_end:
+cpc_end:
+
+ .globl cpc_handler
+cpc_handler:
+ ldx [%sp + 0x7ff + 128], %g1
+ sub %g0, EFAULT, %g2
+ brnz,a,pt %g1, 1f
+ st %g2, [%g1]
+1: retl
+ nop
+
+ .section __ex_table
+ .align 4
+ .word cpc_start, 0, cpc_end, cpc_handler
+
diff --git a/arch/sparc64/lib/locks.S b/arch/sparc64/lib/locks.S
index 74054f63a..7b2bdba62 100644
--- a/arch/sparc64/lib/locks.S
+++ b/arch/sparc64/lib/locks.S
@@ -1,4 +1,4 @@
-/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $
+/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $
* locks.S: SMP low-level lock primitives on Sparc64.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -12,9 +12,9 @@
.align 32
___lk_busy_spin:
- orcc %g2, 0, %g0
- bne,pt %icc, ___lk_busy_spin
- ldub [%g1 + 0], %g2
+ ldub [%g1 + 0], %g2
+ brnz,pt %g2, ___lk_busy_spin
+ membar #LoadLoad
b,pt %xcc, 1f
ldstub [%g1 + 0], %g2
@@ -23,16 +23,15 @@ ___lock_kernel:
addcc %g2, -1, %g2
rdpr %pil, %g3
bcs,a,pn %icc, 9f
- st %g2, [%g6 + AOFF_task_lock_depth]
+ stw %g2, [%g6 + AOFF_task_lock_depth]
wrpr %g0, 15, %pil
ldstub [%g1 + 0], %g2
-1: brnz,a,pn %g2, ___lk_busy_spin
- ldub [%g1 + 0], %g2
+1: brnz,pn %g2, ___lk_busy_spin
+ membar #StoreLoad | #StoreStore
lduw [%g6 + AOFF_task_processor], %g2
- membar #LoadLoad | #LoadStore
stb %g2, [%g1 + 1]
2: mov -1, %g2
- st %g2, [%g6 + AOFF_task_lock_depth]
+ stw %g2, [%g6 + AOFF_task_lock_depth]
wrpr %g3, 0, %pil
9: jmpl %o7 + 0x8, %g0
mov %g5, %o7
@@ -41,16 +40,16 @@ ___lock_kernel:
___lock_reacquire_kernel:
rdpr %pil, %g3
wrpr %g0, 15, %pil
- st %g2, [%g6 + AOFF_task_lock_depth]
+ stw %g2, [%g6 + AOFF_task_lock_depth]
ldstub [%g1 + 0], %g2
1: brz,pt %g2, 3f
- ldub [%g1 + 0], %g2
-2: brnz,a,pt %g2, 2b
- ldub [%g1 + 0], %g2
+ membar #StoreLoad | #StoreStore
+2: ldub [%g1 + 0], %g2
+ brnz,pt %g2, 2b
+ membar #LoadLoad
b,pt %xcc, 1b
ldstub [%g1 + 0], %g2
3: lduw [%g6 + AOFF_task_processor], %g2
- membar #LoadLoad | #LoadStore
stb %g2, [%g1 + 1]
wrpr %g3, 0, %pil
jmpl %o7 + 0x8, %g0
diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S
index ef6cee5a6..9ae3d0381 100644
--- a/arch/sparc64/lib/strlen_user.S
+++ b/arch/sparc64/lib/strlen_user.S
@@ -78,11 +78,11 @@ __strlen_user:
clr %o0
.section __ex_table,#alloc
- .align 8
+ .align 4
- .xword 10b, 30b
- .xword 11b, 30b
- .xword 12b, 30b
- .xword 15b, 30b
- .xword 13b, 30b
- .xword 14b, 30b
+ .word 10b, 30b
+ .word 11b, 30b
+ .word 12b, 30b
+ .word 15b, 30b
+ .word 13b, 30b
+ .word 14b, 30b
diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S
index 7a5dc768f..e0fb0f09b 100644
--- a/arch/sparc64/lib/strncpy_from_user.S
+++ b/arch/sparc64/lib/strncpy_from_user.S
@@ -49,6 +49,6 @@ __strncpy_from_user:
mov -EFAULT, %o0
.section __ex_table,#alloc
- .align 8
- .xword 10b, 4b
- .xword 11b, 4b
+ .align 4
+ .word 10b, 4b
+ .word 11b, 4b
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 5e16e1218..6bc52f3eb 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.18 1997/07/17 02:20:56 davem Exp $
+/* $Id: fault.c,v 1.20 1997/08/04 16:16:51 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -217,56 +217,3 @@ bad_area:
out:
unlock_kernel();
}
-
-void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
- struct vm_area_struct *vmaring;
- struct inode *inode;
- unsigned long vaddr, offset, start;
- pgd_t *pgdp;
- pmd_t *pmdp;
- pte_t *ptep;
- int alias_found = 0;
-
- inode = vma->vm_dentry->d_inode;
- if(!inode)
- return;
-
- offset = (address & PAGE_MASK) - vma->vm_start;
- vmaring = inode->i_mmap;
- do {
- vaddr = vmaring->vm_start + offset;
-
- /* This conditional is misleading... */
- if((vaddr ^ address) & PAGE_SIZE) {
- alias_found++;
- start = vmaring->vm_start;
- while(start < vmaring->vm_end) {
- pgdp = pgd_offset(vmaring->vm_mm, start);
- if(!pgdp) goto next;
- pmdp = pmd_offset(pgdp, start);
- if(!pmdp) goto next;
- ptep = pte_offset(pmdp, start);
- if(!ptep) goto next;
-
- if(pte_val(*ptep) & _PAGE_PRESENT) {
- flush_cache_page(vmaring, start);
- *ptep = __pte(pte_val(*ptep) &
- ~(_PAGE_CV));
- flush_tlb_page(vmaring, start);
- }
- next:
- start += PAGE_SIZE;
- }
- }
- } while((vmaring = vmaring->vm_next_share) != NULL);
-
- if(alias_found && (pte_val(pte) & _PAGE_CV)) {
- pgdp = pgd_offset(vma->vm_mm, address);
- pmdp = pmd_offset(pgdp, address);
- ptep = pte_offset(pmdp, address);
- flush_cache_page(vma, address);
- *ptep = __pte(pte_val(*ptep) & ~(_PAGE_CV));
- flush_tlb_page(vma, address);
- }
-}
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 386c8540f..4a7a1bce1 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $
+/* $Id: init.c,v 1.55 1997/08/24 01:22:29 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -37,6 +37,18 @@ unsigned long tlb_context_cache = CTX_FIRST_VERSION;
/* References to section boundaries */
extern char __init_begin, __init_end, etext, __bss_start;
+extern void __bfill64(void *, unsigned long *);
+
+static __inline__ void __init_pmd(pmd_t *pmdp)
+{
+ __bfill64((void *)pmdp, &null_pte_table);
+}
+
+static __inline__ void __init_pgd(pgd_t *pgdp)
+{
+ __bfill64((void *)pgdp, &null_pmd_table);
+}
+
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
@@ -103,48 +115,72 @@ void show_mem(void)
/* IOMMU support, the ideas are right, the code should be cleaned a bit still... */
-/* XXX Also, play with the streaming buffers at some point, both
- * XXX Fusion and Sunfire both have them aparently... -DaveM
- */
-
/* This keeps track of pages used in sparc_alloc_dvma() invocations. */
static unsigned long dvma_map_pages[0x10000000 >> 16] = { 0, };
static unsigned long dvma_pages_current_offset = 0;
static int dvma_pages_current_index = 0;
+/* #define E3000_DEBUG */
+
__initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
unsigned long memory_end, struct linux_sbus *sbus))
{
struct iommu_struct *iommu;
struct sysio_regs *sregs;
- struct linux_prom_registers rprop[2];
+ struct linux_prom64_registers rprop;
unsigned long impl, vers;
unsigned long control, tsbbase;
unsigned long *iopte;
+ u32 rlow, rhigh;
int err, i;
- err = prom_getproperty(iommu_node, "reg", (char *)rprop,
+#ifdef E3000_DEBUG
+ prom_printf("\niommu_init: [%x:%016lx:%016lx:%p] ",
+ iommu_node, memory_start, memory_end, sbus);
+#endif
+ err = prom_getproperty(iommu_node, "reg", (char *)&rprop,
sizeof(rprop));
if(err == -1) {
prom_printf("iommu_init: Cannot map SYSIO control registers.\n");
prom_halt();
}
- sregs = (struct sysio_regs *) sparc_alloc_io(rprop[0].phys_addr,
- (void *)0,
+ rlow = (rprop.phys_addr & 0xffffffff);
+ rhigh = (rprop.phys_addr >> 32);
+#ifdef E3000_DEBUG
+ prom_printf("rlow[%08x] rhigh[%08x] ", rlow, rhigh);
+#endif
+ sregs = (struct sysio_regs *) sparc_alloc_io(rlow, (void *)0,
sizeof(struct sysio_regs),
- "SYSIO Regs",
- rprop[0].which_io, 0x0);
+ "SYSIO Regs", rhigh, 0x0);
+#ifdef E3000_DEBUG
+ prom_printf("sregs[%p]\n");
+#endif
+ if(!sregs) {
+ prom_printf("iommu_init: Fatal error, sysio regs not mapped\n");
+ prom_halt();
+ }
memory_start = (memory_start + 7) & ~7;
iommu = (struct iommu_struct *) memory_start;
memory_start += sizeof(struct iommu_struct);
+
+#ifdef E3000_DEBUG
+ prom_printf("iommu_init: iommu[%p] ", iommu);
+#endif
+
+ spin_lock_init(&iommu->iommu_lock);
iommu->sysio_regs = sregs;
sbus->iommu = iommu;
control = sregs->iommu_control;
impl = (control & IOMMU_CTRL_IMPL) >> 60;
vers = (control & IOMMU_CTRL_VERS) >> 56;
- printk("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
+#ifdef E3000_DEBUG
+ prom_printf("sreg_control[%08x]\n", control);
+ prom_printf("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
+ (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
+#endif
+ printk("IOMMU(SBUS): IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
(unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
control &= ~(IOMMU_CTRL_TSBSZ);
@@ -168,7 +204,8 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
/* Setup aliased mappings... */
for(i = 0; i < (65536 - 4096); i++) {
- *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+ *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF |
+ IOPTE_CACHE | IOPTE_WRITE);
*iopte |= (i << 16);
iopte++;
}
@@ -177,15 +214,47 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
for( ; i < 65536; i++)
*iopte++ = 0;
+#ifdef E3000_DEBUG
+ prom_printf("IOMMU: pte's mapped, enabling IOMMU... ");
+#endif
sregs->iommu_tsbbase = __pa(tsbbase);
sregs->iommu_control = control;
+#ifdef E3000_DEBUG
+ prom_printf("done\n");
+#endif
+ /* Get the streaming buffer going. */
+ control = sregs->sbuf_control;
+ impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60;
+ vers = (control & SYSIO_SBUFCTRL_REV) >> 56;
+#ifdef E3000_DEBUG
+ prom_printf("IOMMU: enabling streaming buffer, control[%08x]... ",
+ control);
+#endif
+ printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ",
+ (unsigned int)impl, (unsigned int)vers);
+ printk("FlushFLAG[%p,%016lx] ... ",
+ (iommu->sbuf_flushflag_va = (unsigned int *)memory_start),
+ (iommu->sbuf_flushflag_pa = __pa(memory_start)));
+ *(iommu->sbuf_flushflag_va) = 0;
+ memory_start += sizeof(unsigned long); /* yes, unsigned long, for alignment */
+
+ sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN);
+
+#ifdef E3000_DEBUG
+ prom_printf("done, returning %016lx\n", memory_start);
+#endif
+ printk("ENABLED\n");
+
+ /* Finally enable DVMA arbitration for all devices, just in case. */
+ sregs->sbus_control |= SYSIO_SBCNTRL_AEN;
+
return memory_start;
}
-void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
+void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
+ struct linux_sbus *sbus)
{
- struct iommu_struct *iommu = SBus_chain->iommu; /* GROSS ME OUT! */
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
@@ -193,6 +262,7 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
/* Find out if we need to grab some pages. */
if(!dvma_map_pages[dvma_pages_current_index] ||
((dvma_pages_current_offset + len) > (1 << 16))) {
+ struct linux_sbus *sbus;
unsigned long *iopte;
unsigned long newpages = __get_free_pages(GFP_KERNEL, 3, 0);
int i;
@@ -212,9 +282,16 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
/* Stick it in the IOMMU. */
i = (65536 - 4096) + i;
- iopte = (unsigned long *)(iommu->page_table + i);
- *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
- *iopte |= __pa(newpages);
+ for_each_sbus(sbus) {
+ struct iommu_struct *iommu = sbus->iommu;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+ iopte = (unsigned long *)(iommu->page_table + i);
+ *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+ *iopte |= __pa(newpages);
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+ }
}
/* Get this out of the way. */
@@ -258,6 +335,33 @@ __u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
return (__u32)0;
}
+void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+ struct iommu_struct *iommu = sbus->iommu;
+ struct sysio_regs *sregs = iommu->sysio_regs;
+ unsigned long start = (unsigned long) vaddr;
+ unsigned long end = PAGE_ALIGN(start + len);
+ unsigned long flags;
+ unsigned int *sync_word;
+
+ start &= PAGE_MASK;
+
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+ sync_word = iommu->sbuf_flushflag_va;
+ sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+ membar("#StoreLoad | #MemIssue");
+ while((*sync_word & 0x1) == 0)
+ membar("#LoadLoad");
+ *sync_word = 0;
+
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
{
while(sz >= 0) {
@@ -273,6 +377,36 @@ void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
}
}
+void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+ struct iommu_struct *iommu = sbus->iommu;
+ struct sysio_regs *sregs = iommu->sysio_regs;
+ unsigned long flags;
+ unsigned int *sync_word;
+
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+ while(sz >= 0) {
+ unsigned long start = sg[sz].dvma_addr;
+ unsigned long end = PAGE_ALIGN(start + sg[sz].len);
+
+ start &= PAGE_MASK;
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+ sz--;
+ }
+ sync_word = iommu->sbuf_flushflag_va;
+ sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+ membar("#StoreLoad | #MemIssue");
+ while((*sync_word & 0x1) == 0)
+ membar("#LoadLoad");
+ *sync_word = 0;
+
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
static char sfmmuinfo[512];
char *mmu_info(void)
@@ -340,7 +474,7 @@ int prom_itlb_ent, prom_dtlb_ent;
unsigned long prom_itlb_tag, prom_itlb_data;
unsigned long prom_dtlb_tag, prom_dtlb_data;
-static inline void inherit_locked_prom_mappings(void)
+void inherit_locked_prom_mappings(int save_p)
{
int i;
int dtlb_seen = 0;
@@ -367,9 +501,12 @@ static inline void inherit_locked_prom_mappings(void)
data = spitfire_get_dtlb_data(i);
if(!dtlb_seen && (data & _PAGE_L)) {
unsigned long tag = spitfire_get_dtlb_tag(i);
- prom_dtlb_ent = i;
- prom_dtlb_tag = tag;
- prom_dtlb_data = data;
+
+ if(save_p) {
+ prom_dtlb_ent = i;
+ prom_dtlb_tag = tag;
+ prom_dtlb_data = data;
+ }
__asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
membar("#Sync");
@@ -390,9 +527,12 @@ static inline void inherit_locked_prom_mappings(void)
data = spitfire_get_itlb_data(i);
if(!itlb_seen && (data & _PAGE_L)) {
unsigned long tag = spitfire_get_itlb_tag(i);
- prom_itlb_ent = i;
- prom_itlb_tag = tag;
- prom_itlb_data = data;
+
+ if(save_p) {
+ prom_itlb_ent = i;
+ prom_itlb_tag = tag;
+ prom_itlb_data = data;
+ }
__asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
membar("#Sync");
@@ -443,10 +583,14 @@ void __flush_cache_all(void)
/* If not locked, zap it. */
void __flush_tlb_all(void)
{
- unsigned long flags;
+ unsigned long pstate;
int i;
- save_flags(flags); cli();
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate\n\t"
+ "flushw"
+ : "=r" (pstate)
+ : "i" (PSTATE_IE));
for(i = 0; i < 64; i++) {
if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
__asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -465,19 +609,67 @@ void __flush_tlb_all(void)
membar("#Sync");
}
}
- restore_flags(flags);
+ __asm__ __volatile__("wrpr %0, 0, %%pstate"
+ : : "r" (pstate));
}
-void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx)
+/* We are always protected by scheduler_lock under SMP. */
+void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx)
{
- if((ctx & ~(CTX_VERSION_MASK)) == 0) {
- flush_tlb_all();
- ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
- if(ctx == 1)
- ctx = CTX_FIRST_VERSION;
+ unsigned int new_ctx = *ctx;
+
+ if((new_ctx & ~(CTX_VERSION_MASK)) == 0) {
+ new_ctx += CTX_FIRST_VERSION;
+ if(new_ctx == 1)
+ new_ctx = CTX_FIRST_VERSION;
+ *ctx = new_ctx;
+ DO_LOCAL_FLUSH(smp_processor_id());
}
- tlb_context_cache = ctx + 1;
- mm->context = ctx;
+ mm->context = new_ctx;
+ mm->cpu_vm_mask = 0; /* Callers sets it properly. */
+ (*ctx)++;
+}
+
+#ifndef __SMP__
+unsigned long *pgd_quicklist = NULL;
+unsigned long *pmd_quicklist = NULL;
+unsigned long *pte_quicklist = NULL;
+unsigned long pgtable_cache_size = 0;
+#endif
+
+pgd_t *get_pgd_slow(void)
+{
+ pgd_t *pgd;
+
+ pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
+ if(pgd)
+ __init_pgd(pgd);
+ return pgd;
+}
+
+pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+ pmd_t *pmd;
+
+ pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+ if(pmd) {
+ __init_pmd(pmd);
+ pgd_set(pgd, pmd);
+ return pmd + offset;
+ }
+ return NULL;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) get_free_page(GFP_KERNEL);
+ if(pte) {
+ pmd_set(pmd, pte);
+ return pte + offset;
+ }
+ return NULL;
}
__initfunc(static void
@@ -595,7 +787,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
*/
pt = phys_base | _PAGE_VALID | _PAGE_SZ4MB;
pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W;
- save_flags(flags); cli();
+ __save_and_cli(flags);
__asm__ __volatile__("
stxa %1, [%0] %3
stxa %2, [%5] %4
@@ -608,15 +800,18 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
: "memory");
- restore_flags(flags);
+ __restore_flags(flags);
/* Now set kernel pgd to upper alias so physical page computations
* work.
*/
init_mm.pgd += ((shift) / (sizeof(pgd_t *)));
- null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + shift);
- null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + shift);
+ /* The funny offsets are to make page table operations much quicker and
+ * requite less state, see pgtable.h for gory details.
+ */
+ null_pmd_table=__pa(((unsigned long)&empty_null_pmd_table)+shift);
+ null_pte_table=__pa(((unsigned long)&empty_null_pte_table)+shift);
pmdp = (pmd_t *) &empty_null_pmd_table;
for(i = 0; i < 1024; i++)
@@ -658,7 +853,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
flushi((long)&empty_zero_page);
membar("#Sync");
- inherit_locked_prom_mappings();
+ inherit_locked_prom_mappings(1);
flush_tlb_all();
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 18f9a363d..ec96e8871 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $
+/* $Id: ultra.S,v 1.3 1997/08/30 04:53:20 ralf Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,28 +13,26 @@
.align 32
.globl __flush_tlb_mm, __flush_tlb_range, __flush_tlb_page
__flush_tlb_mm: /* %o0 == (mm->context & 0x1fff) */
- rdpr %otherwin, %g1
- brz,pt %g1, 1f
- mov %o7, %g3
- call __flushw_user
- clr %g2
-1: rdpr %pil, %g1
-9: mov SECONDARY_CONTEXT, %g7
- wrpr %g0, 15, %pil
-
- ldxa [%g7] ASI_DMMU, %g2
+ mov SECONDARY_CONTEXT, %g7
+9: ldxa [%g7] ASI_DMMU, %g2
cmp %g2, %o0
- be,pt %icc, 1f
+ bne,pn %icc, 1f
mov 0x50, %g3
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ retl
+ flush %g6
+1: rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%g7] ASI_DMMU
-1: stxa %g0, [%g3] ASI_DMMU_DEMAP
- be,pt %icc, 1f
- stxa %g0, [%g3] ASI_IMMU_DEMAP
-
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ flush %g6
stxa %g2, [%g7] ASI_DMMU
-1: wrpr %g1, 0x0, %pil
+ flush %g6
retl
- flush %g6
+ wrpr %g1, 0, %pstate
+ nop
__flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
sethi %hi(8192 - 1), %g5
or %g5, %lo(8192 - 1), %g5
@@ -43,19 +41,13 @@ __flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
sub %o2, %o1, %o3
add %g5, 1, %g5
- orcc %o1, 0x50, %o1
+ orcc %o1, 0x10, %o1
srlx %o3, 13, %o4
- rdpr %otherwin, %g1
- brz,pt %g1, 1f
- mov %o7, %g3
- call __flushw_user
-
- clr %g2
-1: cmp %o4, 96
+ cmp %o4, 96
bgu,pn %icc, 9b
- rdpr %pil, %g1
- mov SECONDARY_CONTEXT, %g7
- wrpr %g0, 15, %pil
+ mov SECONDARY_CONTEXT, %g7
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
ldxa [%g7] ASI_DMMU, %g2
cmp %g2, %o0
@@ -66,37 +58,37 @@ __flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
stxa %g0, [%o1 + %o3] ASI_IMMU_DEMAP
brnz,pt %o3, 1b
sub %o3, %g5, %o3
- nop
+ flush %g6
- be,pt %icc, 1f
- wrpr %g1, 0x0, %pil
+ be,a,pt %icc, 1f
+ nop
stxa %g2, [%g7] ASI_DMMU
-1: retl
- flush %g6
+1: flush %g6
+ wrpr %g1, 0, %pstate
+ retl
+ nop
.align 32
__flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
- rdpr %otherwin, %g1
- brz,pt %g1, 1f
- mov %o7, %g3
- call __flushw_user
- clr %g2
-1: rdpr %pil, %g1
mov SECONDARY_CONTEXT, %g7
- wrpr %g0, 15, %pil
-
ldxa [%g7] ASI_DMMU, %g2
cmp %g2, %o0
be,pt %icc, 1f
or %o1, 0x10, %g3
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ retl
+ flush %g6
+1: rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%g7] ASI_DMMU
-1: stxa %g0, [%g3] ASI_DMMU_DEMAP
- be,pt %icc, 1f
- stxa %g0, [%g3] ASI_IMMU_DEMAP
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ flush %g6
stxa %g2, [%g7] ASI_DMMU
-1: wrpr %g1, 0x0, %pil
+ flush %g6
retl
- flush %g6
+ wrpr %g1, 0, %pstate
#ifdef __SMP__
/* These are all called by the slaves of a cross call, at
@@ -111,50 +103,29 @@ __flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
* %g2 scratch 1
* %g3 scratch 2
* %g4 scratch 3
- *
- * NOTE: We do not acknowledge the UPA until we are done
- * with the service. This is what tells the master
- * that he can consider the effects of the flush
- * "complete" on this cpu.
*/
.align 32
- .globl xcall_flush_tlb_page
+ .globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
xcall_flush_tlb_page:
mov SECONDARY_CONTEXT, %g2
- nop
+ or %g6, 0x10, %g4
ldxa [%g2] ASI_DMMU, %g3
- cmp %g3, %g5
- be,pt %icc, 1f
- or %g6, 0x10, %g4
stxa %g5, [%g2] ASI_DMMU
-1: stxa %g0, [%g4] ASI_DMMU_DEMAP
-
- be,pt %icc, 1f
- stxa %g0, [%g4] ASI_IMMU_DEMAP
+ stxa %g0, [%g4] ASI_DMMU_DEMAP
+ stxa %g0, [%g4] ASI_IMMU_DEMAP
stxa %g3, [%g2] ASI_DMMU
-1: b,pt %xcc, do_ivec_return
- flush %g1
+ retry
- .align 32
- .globl xcall_flush_tlb_mm
xcall_flush_tlb_mm:
mov SECONDARY_CONTEXT, %g2
- nop
+ mov 0x50, %g4
ldxa [%g2] ASI_DMMU, %g3
- cmp %g3, %g5
- be,pt %icc, 1f
- mov 0x50, %g4
stxa %g5, [%g2] ASI_DMMU
-1: stxa %g0, [%g4] ASI_DMMU_DEMAP
-
- be,pt %icc, 1f
- stxa %g0, [%g4] ASI_IMMU_DEMAP
+ stxa %g0, [%g4] ASI_DMMU_DEMAP
+ stxa %g0, [%g4] ASI_IMMU_DEMAP
stxa %g3, [%g2] ASI_DMMU
-1: b,pt %xcc, do_ivec_return
- flush %g1
+ retry
- .align 32
- .globl xcall_flush_tlb_range
xcall_flush_tlb_range:
sethi %hi(8192 - 1), %g2
or %g2, %lo(8192 - 1), %g2
@@ -162,26 +133,54 @@ xcall_flush_tlb_range:
andn %g7, %g2, %g7
sub %g7, %g6, %g3
add %g2, 1, %g2
- orcc %g6, 0x50, %g6
+ orcc %g6, 0x10, %g6
srlx %g3, 13, %g4
cmp %g4, 96
bgu,pn %icc, xcall_flush_tlb_mm
mov SECONDARY_CONTEXT, %g4
ldxa [%g4] ASI_DMMU, %g7
- cmp %g7, %g5
- be,pt %icc, 1f
- sub %g3, %g2, %g3
+ sub %g3, %g2, %g3
stxa %g5, [%g4] ASI_DMMU
+ nop
+ nop
1: stxa %g0, [%g6 + %g3] ASI_DMMU_DEMAP
stxa %g0, [%g6 + %g3] ASI_IMMU_DEMAP
brnz,pt %g3, 1b
sub %g3, %g2, %g3
- bne,a,pn %icc, 1f
- stxa %g7, [%g4] ASI_DMMU
-1: b,pt %xcc, do_ivec_return
- flush %g1
+ stxa %g7, [%g4] ASI_DMMU
+ retry
+ nop
+ nop
+
+ .globl xcall_report_regs
+xcall_report_regs:
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
+ b,pt %xcc, etrap_irq
+109: or %g7, %lo(109b), %g7
+ call __show_regs
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ b,pt %xcc, rtrap
+ clr %l6
+
+ .globl xcall_capture
+xcall_capture:
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
+ b,pt %xcc, etrap_irq
+109: or %g7, %lo(109b), %g7
+ call smp_penguin_jailcell
+ nop
+ b,pt %xcc, rtrap
+ clr %l6
/* These two are not performance critical... */
.globl xcall_flush_tlb_all
@@ -209,8 +208,8 @@ xcall_flush_tlb_all:
cmp %g2, 63
ble,pt %icc, 1b
sll %g2, 3, %g3
- b,pt %xcc, do_ivec_return
- flush %g1
+ flush %g1
+ retry
.globl xcall_flush_cache_all
xcall_flush_cache_all:
@@ -222,6 +221,6 @@ xcall_flush_cache_all:
cmp %g3, %g2
bleu,pt %xcc, 1b
nop
- b,pt %xcc, do_ivec_return
- flush %g1
+ flush %g1
+ retry
#endif /* __SMP__ */
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c
index 40b33da4b..80ba5ec10 100644
--- a/arch/sparc64/prom/console.c
+++ b/arch/sparc64/prom/console.c
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.7 1997/07/19 08:28:29 ecd Exp $
+/* $Id: console.c,v 1.8 1997/08/16 08:00:16 davem Exp $
* console.c: Routines that deal with sending and receiving IO
* to/from the current console device using the PROM.
*
@@ -85,13 +85,13 @@ prom_query_input_device()
if(prom_node_has_property(st_p, "keyboard"))
return PROMDEV_IKBD;
prom_getproperty(st_p, "device_type", propb, sizeof(propb));
- if(strncmp(propb, "serial", sizeof("serial")))
+ if(strncmp(propb, "serial", 6))
return PROMDEV_I_UNK;
/* FIXME: Is there any better way how to find out? */
memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "input-device", propb, sizeof(propb));
- if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
+ if (strncmp (propb, "tty", 3) || !propb[3])
return PROMDEV_I_UNK;
switch (propb[3]) {
case 'a': return PROMDEV_ITTYA;
@@ -114,13 +114,13 @@ prom_query_output_device()
if (propl >= 0 && propl == sizeof("display") &&
strncmp("display", propb, sizeof("display")) == 0)
return PROMDEV_OSCREEN;
- if(strncmp("serial", propb, sizeof("serial")))
+ if(strncmp("serial", propb, 6))
return PROMDEV_O_UNK;
/* FIXME: Is there any better way how to find out? */
memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "output-device", propb, sizeof(propb));
- if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
+ if (strncmp (propb, "tty", 3) || !propb[3])
return PROMDEV_O_UNK;
switch (propb[3]) {
case 'a': return PROMDEV_OTTYA;
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c
index 0703b5cd7..9c5bce294 100644
--- a/arch/sparc64/prom/p1275.c
+++ b/arch/sparc64/prom/p1275.c
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $
+/* $Id: p1275.c,v 1.12 1997/07/26 18:39:01 davem Exp $
* p1275.c: Sun IEEE 1275 PROM low level interface routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -64,7 +64,7 @@ long p1275_cmd (char *service, long fmt, ...)
long ctx = 0;
p = p1275buf.prom_buffer;
- save_and_cli(flags);
+ __save_and_cli(flags);
ctx = spitfire_get_primary_context ();
if (ctx) {
flushw_user ();
@@ -149,7 +149,7 @@ long p1275_cmd (char *service, long fmt, ...)
if (ctx)
spitfire_set_primary_context (ctx);
- restore_flags(flags);
+ __restore_flags(flags);
return x;
}
diff --git a/arch/sparc64/prom/ranges.c b/arch/sparc64/prom/ranges.c
index 323539237..83f860d45 100644
--- a/arch/sparc64/prom/ranges.c
+++ b/arch/sparc64/prom/ranges.c
@@ -1,15 +1,21 @@
-/* $Id: ranges.c,v 1.3 1997/03/21 12:33:36 jj Exp $
+/* $Id: ranges.c,v 1.8 1997/08/17 22:39:45 ecd Exp $
* ranges.c: Handle ranges in newer proms for obio/sbus.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
+#include <linux/config.h>
#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/sbus.h>
+#include <asm/fhc.h>
#include <asm/system.h>
+#ifdef CONFIG_PCI
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#endif
struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
int num_obio_ranges;
@@ -62,6 +68,25 @@ void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers
}
}
+/* Apply probed fhc ranges to registers passed, if no ranges return. */
+void prom_apply_fhc_ranges(struct linux_fhc *fhc,
+ struct linux_prom_registers *regs,
+ int nregs)
+{
+ if(fhc->num_fhc_ranges)
+ prom_adjust_regs(regs, nregs, fhc->fhc_ranges,
+ fhc->num_fhc_ranges);
+}
+
+/* Apply probed central ranges to registers passed, if no ranges return. */
+void prom_apply_central_ranges(struct linux_central *central,
+ struct linux_prom_registers *regs, int nregs)
+{
+ if(central->num_central_ranges)
+ prom_adjust_regs(regs, nregs, central->central_ranges,
+ central->num_central_ranges);
+}
+
__initfunc(void prom_ranges_init(void))
{
}
@@ -78,6 +103,56 @@ __initfunc(void prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus))
sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges));
}
+__initfunc(void prom_central_ranges_init(int cnode, struct linux_central *central))
+{
+ int success;
+
+ central->num_central_ranges = 0;
+ success = prom_getproperty(central->prom_node, "ranges",
+ (char *) central->central_ranges,
+ sizeof (central->central_ranges));
+ if (success != -1)
+ central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+__initfunc(void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc))
+{
+ int success;
+
+ fhc->num_fhc_ranges = 0;
+ success = prom_getproperty(fhc->prom_node, "ranges",
+ (char *) fhc->fhc_ranges,
+ sizeof (fhc->fhc_ranges));
+ if (success != -1)
+ fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+#ifdef CONFIG_PCI
+__initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus))
+{
+ int success;
+
+ ebus->num_ebus_ranges = 0;
+ success = prom_getproperty(ebus->prom_node, "ranges",
+ (char *)ebus->ebus_ranges,
+ sizeof(ebus->ebus_ranges));
+ if (success != -1)
+ ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
+}
+
+__initfunc(void prom_pbm_ranges_init(int pnode, struct linux_pbm_info *pbm))
+{
+ int success;
+
+ pbm->num_pbm_ranges = 0;
+ success = prom_getproperty(pbm->prom_node, "ranges",
+ (char *)&pbm->pbm_ranges,
+ sizeof(pbm->pbm_ranges));
+ if(success != -1)
+ pbm->num_pbm_ranges = (success/sizeof(struct linux_prom_pci_ranges));
+}
+#endif
+
void
prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
{
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c
index ae4baf858..c2b386641 100644
--- a/arch/sparc64/prom/tree.c
+++ b/arch/sparc64/prom/tree.c
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.5 1997/03/24 17:44:01 jj Exp $
+/* $Id: tree.c,v 1.6 1997/08/12 16:32:48 davem Exp $
* tree.c: Basic device tree traversal/scanning for the Linux
* prom library.
*
@@ -26,7 +26,7 @@ __prom_getchild(int node)
__inline__ int
prom_getchild(int node)
{
- long cnode;
+ int cnode;
if(node == -1) return 0;
cnode = __prom_getchild(node);
@@ -37,7 +37,7 @@ prom_getchild(int node)
__inline__ int
prom_getparent(int node)
{
- long cnode;
+ int cnode;
if(node == -1) return 0;
cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
@@ -57,12 +57,12 @@ __prom_getsibling(int node)
__inline__ int
prom_getsibling(int node)
{
- long sibnode;
+ int sibnode;
if(node == -1) return 0;
sibnode = __prom_getsibling(node);
if(sibnode == -1) return 0;
- return (int)sibnode;
+ return sibnode;
}
/* Return the length in bytes of property 'prop' at node 'node'.
diff --git a/arch/sparc64/solaris/Makefile b/arch/sparc64/solaris/Makefile
new file mode 100644
index 000000000..56d252962
--- /dev/null
+++ b/arch/sparc64/solaris/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for the Solaris binary emulation.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := solaris.o
+O_OBJS := entry64.o fs.o misc.o signal.o systbl.o ioctl.o ipc.o socksys.o
+ifeq ($(CONFIG_SOLARIS_EMUL),m)
+M_OBJS := $(O_TARGET)
+endif
+
+.S.s:
+ $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+
+ifneq ($(CONFIG_SOLARIS_EMUL),y)
+do_it_all:
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/sparc64/solaris/conv.h b/arch/sparc64/solaris/conv.h
new file mode 100644
index 000000000..c806d3dc1
--- /dev/null
+++ b/arch/sparc64/solaris/conv.h
@@ -0,0 +1,28 @@
+/* $Id: conv.h,v 1.2 1997/09/03 12:29:13 jj Exp $
+ * conv.h: Utility macros for Solaris emulation
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+/* #define DEBUG_SOLARIS */
+
+#ifndef __ASSEMBLY__
+
+#include <asm/unistd.h>
+
+/* As gcc will warn about casting u32 to some ptr, we have to cast it to
+ * unsigned long first, and that's what is A() for.
+ * You just do (void *)A(x), instead of having to
+ * type (void *)((unsigned long)x) or instead of just (void *)x, which will
+ * produce warnings.
+ */
+#define A(x) ((unsigned long)x)
+
+extern unsigned sys_call_table[];
+extern unsigned sys_call_table32[];
+extern unsigned sunos_sys_table[];
+
+#define SYS(name) ((long)sys_call_table[__NR_##name])
+#define SUNOS(x) ((long)sunos_sys_table[x])
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/sparc64/solaris/entry64.S b/arch/sparc64/solaris/entry64.S
new file mode 100644
index 000000000..e983010d1
--- /dev/null
+++ b/arch/sparc64/solaris/entry64.S
@@ -0,0 +1,202 @@
+/* $Id: entry64.S,v 1.3 1997/09/03 12:29:12 jj Exp $
+ * entry64.S: Solaris syscall emulation entry point.
+ *
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+
+#include <linux/errno.h>
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/smp.h>
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/signal.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+
+#include "conv.h"
+
+#define NR_SYSCALLS 256
+
+ .text
+solaris_syscall_trace:
+ call syscall_trace
+ nop
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov %i3, %o3
+ b,pt %xcc, 2f
+ mov %i4, %o4
+
+solaris_sucks:
+/* Solaris is a big system which needs to be able to do all the things
+ * in Inf+1 different ways */
+ add %i6, 0x5c, %o0
+ mov %i0, %g1
+ mov %i1, %i0
+ mov %i2, %i1
+ srl %o0, 0, %o0
+ mov %i3, %i2
+ mov %i4, %i3
+ mov %i5, %i4
+ ba,pt %xcc, solaris_sparc_syscall
+exen: lduwa [%o0] ASI_S, %i5
+
+exenf: ba,pt %xcc, solaris_sparc_syscall
+ clr %i5
+
+/* For shared binaries, binfmt_elf32 already sets up personality
+ and exec_domain. This is to handle static binaries as well */
+solaris_reg:
+ call solaris_register
+ nop
+ ba,pt %xcc, 1f
+ mov %i0, %o0
+
+linux_syscall_for_solaris:
+ sll %l7, 2, %l4
+ ba,pt %xcc, 10f
+ lduw [%l6 + %l4], %l7
+
+ /* Solaris system calls enter here... */
+ .align 32
+ .globl solaris_sparc_syscall
+solaris_sparc_syscall:
+#ifdef DEBUG_SOLARIS
+ mov %g1, %o0
+ call entry_printk
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+#endif
+ ldub [%g6 + AOFF_task_personality + ASIZ_task_personality - 1], %l0
+ cmp %g1, 255
+ bg,pn %icc, solaris_unimplemented
+ srl %g1, 0, %g1
+ sethi %hi(solaris_sys_table), %l7
+ brz,pn %g1, solaris_sucks
+ mov %i0, %o0
+ sll %g1, 2, %l4
+ cmp %l0, 1
+ bne,pn %icc, solaris_reg
+1: mov %i1, %o1
+ lduw [%l7 + %l4], %l7
+ mov %i2, %o2
+ ldx [%g6 + AOFF_task_flags], %l5
+! st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS]
+ cmp %l7, NR_SYSCALLS
+ bleu,a,pn %xcc, linux_syscall_for_solaris
+ sethi %hi(sys_call_table32), %l6
+ andcc %l7, 1, %g0
+ bne,a,pn %icc, 10f
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+10: mov %i3, %o3
+ mov %i4, %o4
+ andn %l7, 3, %l7
+ andcc %l5, 0x20, %g0
+ bne,pn %icc, solaris_syscall_trace
+ mov %i0, %l5
+2: call %l7
+ mov %i5, %o5
+ret_from_solaris:
+#ifdef DEBUG_SOLARIS
+ call exit_printk
+ mov %o0, %l0
+ mov %l0, %o0
+#endif
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+ ldx [%g6 + AOFF_task_flags], %l6
+ sra %o0, 0, %o0
+ mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
+ cmp %o0, -ENOIOCTLCMD
+ sllx %g2, 32, %g2
+ bgeu,pn %xcc, 1f
+ andcc %l6, 0x20, %l6
+
+ /* System call success, clear Carry condition code. */
+ andn %g3, %g2, %g3
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+ bne,pn %icc, solaris_syscall_trace2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
+ add %l1, 0x4, %l2 !npc = npc+4
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+ clr %l6
+ call rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+1:
+ /* System call failure, set Carry condition code.
+ * Also, get abs(errno) to return to the process.
+ */
+ sub %g0, %o0, %o0
+ or %g3, %g2, %g3
+ cmp %o0, ERANGE /* 0-ERANGE are identity mapped */
+ bleu,pt %icc, 1f
+ cmp %o0, EMEDIUMTYPE
+ bgu,pn %icc, 1f
+ sethi %hi(solaris_err_table), %l6
+ sll %o0, 2, %o0
+ or %l6, %lo(solaris_err_table), %l6
+ ldsw [%l6 + %o0], %o0
+1: stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+ mov 1, %l6
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+ bne,pn %icc, solaris_syscall_trace2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
+ add %l1, 0x4, %l2 !npc = npc+4
+
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+ call rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+solaris_syscall_trace2:
+ call syscall_trace
+ add %l1, 0x4, %l2 /* npc = npc+4 */
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+ call rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+
+ /* This one is tricky, so that's why we do it in assembly */
+ .globl solaris_sigsuspend
+solaris_sigsuspend:
+ call do_sol_sigsuspend
+ nop
+ brlz,pn %o0, ret_from_solaris
+ nop
+ call sys_sigsuspend
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+
+ .globl solaris_getpid
+solaris_getpid:
+ call sys_getppid /* This is tricky, so don't do it in assembly */
+ nop
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+ b,pt %xcc, ret_from_solaris
+ lduw [%g6 + AOFF_task_pid], %o0
+
+ .globl solaris_getuid
+solaris_getuid:
+ lduh [%g6 + AOFF_task_euid], %o1
+ lduh [%g6 + AOFF_task_uid], %o0
+ b,pt %xcc, ret_from_solaris
+ stx %o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+
+ .globl solaris_getgid
+solaris_getgid:
+ lduh [%g6 + AOFF_task_egid], %o1
+ lduh [%g6 + AOFF_task_gid], %o0
+ b,pt %xcc, ret_from_solaris
+ stx %o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+
+ .globl solaris_unimplemented
+solaris_unimplemented:
+ call do_sol_unimplemented
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, ret_from_solaris
+ nop
+
+ .section __ex_table,#alloc
+ .align 4
+ .word exen, exenf
+
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
new file mode 100644
index 000000000..9d0905adc
--- /dev/null
+++ b/arch/sparc64/solaris/fs.c
@@ -0,0 +1,711 @@
+/* $Id: fs.c,v 1.4 1997/09/04 15:46:26 jj Exp $
+ * fs.c: fs related syscall emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/smp_lock.h>
+#include <linux/limits.h>
+#include <linux/resource.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/ptrace.h>
+
+#include "conv.h"
+
+extern char * getname32(u32 filename);
+#define putname32 putname
+
+#define R4_DEV(DEV) ((DEV & 0xff) | ((DEV & 0xff00) << 10))
+#define R4_MAJOR(DEV) (((DEV) >> 18) & 0x3fff)
+#define R4_MINOR(DEV) ((DEV) & 0x3ffff)
+#define R3_VERSION 1
+#define R4_VERSION 2
+
+typedef struct {
+ s32 tv_sec;
+ s32 tv_nsec;
+} timestruct_t;
+
+struct sol_stat {
+ u32 st_dev;
+ s32 st_pad1[3]; /* network id */
+ u32 st_ino;
+ u32 st_mode;
+ u32 st_nlink;
+ u32 st_uid;
+ u32 st_gid;
+ u32 st_rdev;
+ s32 st_pad2[2];
+ s32 st_size;
+ s32 st_pad3; /* st_size, off_t expansion */
+ timestruct_t st_atime;
+ timestruct_t st_mtime;
+ timestruct_t st_ctime;
+ s32 st_blksize;
+ s32 st_blocks;
+ char st_fstype[16];
+ s32 st_pad4[8]; /* expansion area */
+};
+
+#define UFSMAGIC (((unsigned)'u'<<24)||((unsigned)'f'<<16)||((unsigned)'s'<<8))
+
+static inline int putstat(struct sol_stat *ubuf, struct stat *kbuf)
+{
+ if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev) ||
+ __put_user (kbuf->st_ino, &ubuf->st_ino) ||
+ __put_user (kbuf->st_mode, &ubuf->st_mode) ||
+ __put_user (kbuf->st_nlink, &ubuf->st_nlink) ||
+ __put_user (kbuf->st_uid, &ubuf->st_uid) ||
+ __put_user (kbuf->st_gid, &ubuf->st_gid) ||
+ __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev) ||
+ __put_user (kbuf->st_size, &ubuf->st_size) ||
+ __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec) ||
+ __put_user (0, &ubuf->st_atime.tv_nsec) ||
+ __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec) ||
+ __put_user (0, &ubuf->st_mtime.tv_nsec) ||
+ __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec) ||
+ __put_user (0, &ubuf->st_ctime.tv_nsec) ||
+ __put_user (kbuf->st_blksize, &ubuf->st_blksize) ||
+ __put_user (kbuf->st_blocks, &ubuf->st_blocks) ||
+ __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage int solaris_stat(u32 filename, u32 statbuf)
+{
+ int ret;
+ struct stat s;
+ char *filenam;
+ unsigned long old_fs = get_fs();
+ int (*sys_newstat)(char *,struct stat *) =
+ (int (*)(char *,struct stat *))SYS(stat);
+
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
+ set_fs (KERNEL_DS);
+ ret = sys_newstat(filenam, &s);
+ set_fs (old_fs);
+ putname32 (filenam);
+ if (putstat ((struct sol_stat *)A(statbuf), &s))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+asmlinkage int solaris_xstat(int vers, u32 filename, u32 statbuf)
+{
+ /* Solaris doesn't bother with looking at vers, so we do neither */
+ return solaris_stat(filename, statbuf);
+}
+
+asmlinkage int solaris_lstat(u32 filename, u32 statbuf)
+{
+ int ret;
+ struct stat s;
+ char *filenam;
+ unsigned long old_fs = get_fs();
+ int (*sys_newlstat)(char *,struct stat *) =
+ (int (*)(char *,struct stat *))SYS(lstat);
+
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
+ set_fs (KERNEL_DS);
+ ret = sys_newlstat(filenam, &s);
+ set_fs (old_fs);
+ putname32 (filenam);
+ if (putstat ((struct sol_stat *)A(statbuf), &s))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+asmlinkage int solaris_lxstat(int vers, u32 filename, u32 statbuf)
+{
+ return solaris_lstat(filename, statbuf);
+}
+
+asmlinkage int solaris_fstat(unsigned int fd, u32 statbuf)
+{
+ int ret;
+ struct stat s;
+ unsigned long old_fs = get_fs();
+ int (*sys_newfstat)(unsigned,struct stat *) =
+ (int (*)(unsigned,struct stat *))SYS(fstat);
+
+ set_fs (KERNEL_DS);
+ ret = sys_newfstat(fd, &s);
+ set_fs (old_fs);
+ if (putstat ((struct sol_stat *)A(statbuf), &s))
+ return -EFAULT;
+ return ret;
+}
+
+asmlinkage int solaris_fxstat(int vers, u32 fd, u32 statbuf)
+{
+ return solaris_fstat(fd, statbuf);
+}
+
+asmlinkage int solaris_mknod(u32 path, u32 mode, s32 dev)
+{
+ int (*sys_mknod)(const char *,int,dev_t) =
+ (int (*)(const char *,int,dev_t))SYS(mknod);
+ int major, minor;
+
+ if ((major = R4_MAJOR(dev)) > 255 ||
+ (minor = R4_MINOR(dev)) > 255) return -EINVAL;
+ return sys_mknod((const char *)A(path), mode, MKDEV(major,minor));
+}
+
+asmlinkage int solaris_xmknod(int vers, u32 path, u32 mode, s32 dev)
+{
+ return solaris_mknod(path, mode, dev);
+}
+
+/* This statfs thingie probably will go in the near future, but... */
+
+struct sol_statfs {
+ short f_type;
+ s32 f_bsize;
+ s32 f_frsize;
+ s32 f_blocks;
+ s32 f_bfree;
+ u32 f_files;
+ u32 f_ffree;
+ char f_fname[6];
+ char f_fpack[6];
+};
+
+asmlinkage int solaris_statfs(u32 path, u32 buf, int len, int fstype)
+{
+ int ret;
+ struct statfs s;
+ unsigned long old_fs = get_fs();
+ int (*sys_statfs)(const char *,struct statfs *) =
+ (int (*)(const char *,struct statfs *))SYS(statfs);
+ struct sol_statfs *ss = (struct sol_statfs *)A(buf);
+
+ if (len != sizeof(struct sol_statfs)) return -EINVAL;
+ if (!fstype) {
+ set_fs (KERNEL_DS);
+ ret = sys_statfs((const char *)A(path), &s);
+ set_fs (old_fs);
+ if (!ret) {
+ if (put_user (s.f_type, &ss->f_type) ||
+ __put_user (s.f_bsize, &ss->f_bsize) ||
+ __put_user (0, &ss->f_frsize) ||
+ __put_user (s.f_blocks, &ss->f_blocks) ||
+ __put_user (s.f_bfree, &ss->f_bfree) ||
+ __put_user (s.f_files, &ss->f_files) ||
+ __put_user (s.f_ffree, &ss->f_ffree) ||
+ __clear_user (&ss->f_fname, 12))
+ return -EFAULT;
+ }
+ return ret;
+ }
+/* Linux can't stat unmounted filesystems so we
+ * simply lie and claim 100MB of 1GB is free. Sorry.
+ */
+ if (put_user (fstype, &ss->f_type) ||
+ __put_user (1024, &ss->f_bsize) ||
+ __put_user (0, &ss->f_frsize) ||
+ __put_user (1024*1024, &ss->f_blocks) ||
+ __put_user (100*1024, &ss->f_bfree) ||
+ __put_user (60000, &ss->f_files) ||
+ __put_user (50000, &ss->f_ffree) ||
+ __clear_user (&ss->f_fname, 12))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage int solaris_fstatfs(u32 fd, u32 buf, int len, int fstype)
+{
+ int ret;
+ struct statfs s;
+ unsigned long old_fs = get_fs();
+ int (*sys_fstatfs)(unsigned,struct statfs *) =
+ (int (*)(unsigned,struct statfs *))SYS(fstatfs);
+ struct sol_statfs *ss = (struct sol_statfs *)A(buf);
+
+ if (len != sizeof(struct sol_statfs)) return -EINVAL;
+ if (!fstype) {
+ set_fs (KERNEL_DS);
+ ret = sys_fstatfs(fd, &s);
+ set_fs (old_fs);
+ if (!ret) {
+ if (put_user (s.f_type, &ss->f_type) ||
+ __put_user (s.f_bsize, &ss->f_bsize) ||
+ __put_user (0, &ss->f_frsize) ||
+ __put_user (s.f_blocks, &ss->f_blocks) ||
+ __put_user (s.f_bfree, &ss->f_bfree) ||
+ __put_user (s.f_files, &ss->f_files) ||
+ __put_user (s.f_ffree, &ss->f_ffree) ||
+ __clear_user (&ss->f_fname, 12))
+ return -EFAULT;
+ }
+ return ret;
+ }
+ /* Otherwise fstatfs is the same as statfs */
+ return solaris_statfs(0, buf, len, fstype);
+}
+
+struct sol_statvfs {
+ u32 f_bsize;
+ u32 f_frsize;
+ u32 f_blocks;
+ u32 f_bfree;
+ u32 f_bavail;
+ u32 f_files;
+ u32 f_ffree;
+ u32 f_favail;
+ u32 f_fsid;
+ char f_basetype[16];
+ u32 f_flag;
+ u32 f_namemax;
+ char f_fstr[32];
+ u32 f_filler[16];
+};
+
+static int report_statvfs(struct inode *inode, u32 buf)
+{
+ struct statfs s;
+ unsigned long old_fs = get_fs();
+ int error;
+ struct sol_statvfs *ss = (struct sol_statvfs *)A(buf);
+
+ set_fs (KERNEL_DS);
+ error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
+ set_fs (old_fs);
+ if (!error) {
+ const char *p = inode->i_sb->s_type->name;
+ int i = 0;
+ int j = strlen (p);
+
+ if (j > 15) j = 15;
+ if (IS_RDONLY(inode)) i = 1;
+ if (IS_NOSUID(inode)) i |= 2;
+ if (put_user (s.f_bsize, &ss->f_bsize) ||
+ __put_user (0, &ss->f_frsize) ||
+ __put_user (s.f_blocks, &ss->f_blocks) ||
+ __put_user (s.f_bfree, &ss->f_bfree) ||
+ __put_user (s.f_bavail, &ss->f_bavail) ||
+ __put_user (s.f_files, &ss->f_files) ||
+ __put_user (s.f_ffree, &ss->f_ffree) ||
+ __put_user (s.f_ffree, &ss->f_favail) ||
+ __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) ||
+ __copy_to_user (ss->f_basetype,p,j) ||
+ __put_user (0, (char *)&ss->f_basetype[j]) ||
+ __put_user (s.f_namelen, &ss->f_namemax) ||
+ __put_user (i, &ss->f_flag) ||
+ __clear_user (&ss->f_fstr, 32))
+ return -EFAULT;
+ }
+ return error;
+}
+
+asmlinkage int solaris_statvfs(u32 path, u32 buf)
+{
+ struct dentry * dentry;
+ int error;
+
+ lock_kernel();
+ dentry = namei((const char *)A(path));
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+
+ error = -ENOSYS;
+ if (inode->i_sb->s_op->statfs)
+ error = report_statvfs(inode, buf);
+ dput(dentry);
+ }
+ unlock_kernel();
+ return error;
+}
+
+asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
+{
+ struct inode * inode;
+ struct dentry * dentry;
+ struct file * file;
+ int error;
+
+ lock_kernel();
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ error = -EBADF;
+ else if (!(dentry = file->f_dentry))
+ error = -ENOENT;
+ else if (!(inode = dentry->d_inode))
+ error = -ENOENT;
+ else if (!inode->i_sb)
+ error = -ENODEV;
+ else if (!inode->i_sb->s_op->statfs)
+ error = -ENOSYS;
+ else
+ error = report_statvfs(inode, buf);
+ unlock_kernel();
+ return error;
+}
+
+asmlinkage int solaris_open(u32 filename, int flags, u32 mode)
+{
+ int (*sys_open)(const char *,int,int) =
+ (int (*)(const char *,int,int))SYS(open);
+ int fl = flags & 0xf;
+
+ if (flags & 0x8050) fl |= O_SYNC;
+ if (flags & 0x80) fl |= O_NONBLOCK;
+ if (flags & 0x100) fl |= O_CREAT;
+ if (flags & 0x200) fl |= O_TRUNC;
+ if (flags & 0x400) fl |= O_EXCL;
+ if (flags & 0x800) fl |= O_NOCTTY;
+ return sys_open((const char *)A(filename), fl, mode);
+}
+
+#define SOL_F_SETLK 6
+#define SOL_F_SETLKW 7
+#define SOL_F_FREESP 11
+#define SOL_F_ISSTREAM 13
+#define SOL_F_GETLK 14
+#define SOL_F_PRIV 15
+#define SOL_F_NPRIV 16
+#define SOL_F_QUOTACTL 17
+#define SOL_F_BLOCKS 18
+#define SOL_F_BLKSIZE 19
+#define SOL_F_GETOWN 23
+#define SOL_F_SETOWN 24
+
+struct sol_flock {
+ short l_type;
+ short l_whence;
+ u32 l_start;
+ u32 l_len;
+ s32 l_sysid;
+ s32 l_pid;
+ s32 l_pad[4];
+};
+
+asmlinkage int solaris_fcntl(unsigned fd, unsigned cmd, u32 arg)
+{
+ int (*sys_fcntl)(unsigned,unsigned,unsigned long) =
+ (int (*)(unsigned,unsigned,unsigned long))SYS(fcntl);
+ int ret, flags;
+
+ switch (cmd) {
+ case F_DUPFD:
+ case F_GETFD:
+ case F_SETFD: return sys_fcntl(fd, cmd, (unsigned long)arg);
+ case F_GETFL:
+ flags = sys_fcntl(fd, cmd, 0);
+ ret = flags & 0xf;
+ if (flags & O_SYNC) ret |= 0x8050;
+ if (flags & O_NONBLOCK) ret |= 0x80;
+ return ret;
+ case F_SETFL:
+ flags = arg & 0xf;
+ if (arg & 0x8050) flags |= O_SYNC;
+ if (arg & 0x80) flags |= O_NONBLOCK;
+ return sys_fcntl(fd, cmd, (long)flags);
+ case SOL_F_GETLK:
+ case SOL_F_SETLK:
+ case SOL_F_SETLKW:
+ {
+ struct flock f;
+ unsigned long old_fs = get_fs();
+
+ switch (cmd) {
+ case SOL_F_GETLK: cmd = F_GETLK; break;
+ case SOL_F_SETLK: cmd = F_SETLK; break;
+ case SOL_F_SETLKW: cmd = F_SETLKW; break;
+ }
+
+ get_user_ret (f.l_type, &((struct sol_flock *)A(arg))->l_type, -EFAULT);
+ __get_user_ret (f.l_whence, &((struct sol_flock *)A(arg))->l_whence, -EFAULT);
+ __get_user_ret (f.l_start, &((struct sol_flock *)A(arg))->l_start, -EFAULT);
+ __get_user_ret (f.l_len, &((struct sol_flock *)A(arg))->l_len, -EFAULT);
+ __get_user_ret (f.l_pid, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT);
+ set_fs(KERNEL_DS);
+ ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+ set_fs(old_fs);
+ __put_user_ret (f.l_type, &((struct sol_flock *)A(arg))->l_type, -EFAULT);
+ __put_user_ret (f.l_whence, &((struct sol_flock *)A(arg))->l_whence, -EFAULT);
+ __put_user_ret (f.l_start, &((struct sol_flock *)A(arg))->l_start, -EFAULT);
+ __put_user_ret (f.l_len, &((struct sol_flock *)A(arg))->l_len, -EFAULT);
+ __put_user_ret (f.l_pid, &((struct sol_flock *)A(arg))->l_pid, -EFAULT);
+ __put_user_ret (0, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT);
+ return ret;
+ }
+ }
+ return -EINVAL;
+}
+
+asmlinkage int solaris_ulimit(int cmd, int val)
+{
+ switch (cmd) {
+ case 1: /* UL_GETFSIZE - in 512B chunks */
+ return current->rlim[RLIMIT_FSIZE].rlim_cur >> 9;
+ case 2: /* UL_SETFSIZE */
+ if ((unsigned long)val > (LONG_MAX>>9)) return -ERANGE;
+ val <<= 9;
+ lock_kernel();
+ if (val > current->rlim[RLIMIT_FSIZE].rlim_max) {
+ if (!suser()) {
+ unlock_kernel();
+ return -EPERM;
+ }
+ current->rlim[RLIMIT_FSIZE].rlim_max = val;
+ }
+ current->rlim[RLIMIT_FSIZE].rlim_cur = val;
+ unlock_kernel();
+ return 0;
+ case 3: /* UL_GMEMLIM */
+ return current->rlim[RLIMIT_DATA].rlim_cur;
+ case 4: /* UL_GDESLIM */
+ return NR_OPEN;
+ }
+ return -EINVAL;
+}
+
+static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
+{
+ struct inode * inode;
+ struct iattr newattrs;
+ int error;
+
+ error = -ENOENT;
+ if (!(inode = dentry->d_inode)) {
+ printk("chown_common: NULL inode\n");
+ goto out;
+ }
+ error = -EROFS;
+ if (IS_RDONLY(inode))
+ goto out;
+ error = -EPERM;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ goto out;
+ if (user == (uid_t) -1)
+ user = inode->i_uid;
+ if (group == (gid_t) -1)
+ group = inode->i_gid;
+ newattrs.ia_mode = inode->i_mode;
+ newattrs.ia_uid = user;
+ newattrs.ia_gid = group;
+ newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
+ /*
+ * If the owner has been changed, remove the setuid bit
+ */
+ if (inode->i_mode & S_ISUID) {
+ newattrs.ia_mode &= ~S_ISUID;
+ newattrs.ia_valid |= ATTR_MODE;
+ }
+ /*
+ * If the group has been changed, remove the setgid bit
+ *
+ * Don't remove the setgid bit if no group execute bit.
+ * This is a file marked for mandatory locking.
+ */
+ if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
+ newattrs.ia_mode &= ~S_ISGID;
+ newattrs.ia_valid |= ATTR_MODE;
+ }
+ if (inode->i_sb && inode->i_sb->dq_op) {
+ inode->i_sb->dq_op->initialize(inode, -1);
+ error = -EDQUOT;
+ if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
+ goto out;
+ error = notify_change(inode, &newattrs);
+ if (error)
+ inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
+ } else
+ error = notify_change(inode, &newattrs);
+out:
+ return error;
+}
+
+/* Linux chown works like Solaris lchown. Solaris chown does follow symlink */
+asmlinkage int solaris_chown(u32 filename, s32 user, s32 group)
+{
+ struct dentry * dentry;
+ int error;
+
+ lock_kernel();
+ dentry = namei((const char *)A(filename));
+
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ error = chown_common(dentry, user, group);
+ dput(dentry);
+ }
+ unlock_kernel();
+ return error;
+}
+
+/* At least at the time I'm writing this, Linux doesn't have ACLs, so we
+ just fake this */
+asmlinkage int solaris_acl(u32 filename, int cmd, int nentries, u32 aclbufp)
+{
+ return -ENOSYS;
+}
+
+asmlinkage int solaris_facl(unsigned int fd, int cmd, int nentries, u32 aclbufp)
+{
+ return -ENOSYS;
+}
+
+asmlinkage int solaris_pread(int fd, u32 buf, u32 nbyte, s32 offset)
+{
+ off_t temp;
+ int retval;
+ struct file * file;
+ long (*sys_read)(unsigned int, char *, unsigned long) =
+ (long (*)(unsigned int, char *, unsigned long))SYS(read);
+ long (*sys_lseek)(unsigned int, off_t, unsigned int) =
+ (long (*)(unsigned int, off_t, unsigned int))SYS(lseek);
+
+ lock_kernel();
+ retval = -EBADF;
+ if (fd >= NR_OPEN ||
+ !(file = current->files->fd[fd]))
+ goto bad;
+ temp = file->f_pos;
+ if (temp != offset) {
+ retval = sys_lseek(fd, offset, 0);
+ if (retval < 0) goto bad;
+ }
+ retval = sys_read(fd, (char *)A(buf), nbyte);
+ if (file->f_pos != temp) {
+ if (!retval)
+ retval = sys_lseek(fd, temp, 0);
+ else
+ sys_lseek(fd, temp, 0);
+ }
+bad:
+ unlock_kernel();
+ return retval;
+}
+
+asmlinkage int solaris_pwrite(int fd, u32 buf, u32 nbyte, s32 offset)
+{
+ off_t temp;
+ int retval;
+ struct file * file;
+ long (*sys_write)(unsigned int, char *, unsigned long) =
+ (long (*)(unsigned int, char *, unsigned long))SYS(read);
+ long (*sys_lseek)(unsigned int, off_t, unsigned int) =
+ (long (*)(unsigned int, off_t, unsigned int))SYS(lseek);
+
+ lock_kernel();
+ retval = -EBADF;
+ if (fd >= NR_OPEN ||
+ !(file = current->files->fd[fd]))
+ goto bad;
+ temp = file->f_pos;
+ if (temp != offset) {
+ retval = sys_lseek(fd, offset, 0);
+ if (retval < 0) goto bad;
+ }
+ retval = sys_write(fd, (char *)A(buf), nbyte);
+ if (file->f_pos != temp) {
+ if (!retval)
+ retval = sys_lseek(fd, temp, 0);
+ else
+ sys_lseek(fd, temp, 0);
+ }
+bad:
+ unlock_kernel();
+ return retval;
+}
+
+/* POSIX.1 names */
+#define _PC_LINK_MAX 1
+#define _PC_MAX_CANON 2
+#define _PC_MAX_INPUT 3
+#define _PC_NAME_MAX 4
+#define _PC_PATH_MAX 5
+#define _PC_PIPE_BUF 6
+#define _PC_NO_TRUNC 7
+#define _PC_VDISABLE 8
+#define _PC_CHOWN_RESTRICTED 9
+/* POSIX.4 names */
+#define _PC_ASYNC_IO 10
+#define _PC_PRIO_IO 11
+#define _PC_SYNC_IO 12
+#define _PC_LAST 12
+
+/* This is not a real and complete implementation yet, just to keep
+ * the easy Solaris binaries happy.
+ */
+asmlinkage int solaris_fpathconf(int fd, int name)
+{
+ int ret;
+
+ switch(name) {
+ case _PC_LINK_MAX:
+ ret = LINK_MAX;
+ break;
+ case _PC_MAX_CANON:
+ ret = MAX_CANON;
+ break;
+ case _PC_MAX_INPUT:
+ ret = MAX_INPUT;
+ break;
+ case _PC_NAME_MAX:
+ ret = NAME_MAX;
+ break;
+ case _PC_PATH_MAX:
+ ret = PATH_MAX;
+ break;
+ case _PC_PIPE_BUF:
+ ret = PIPE_BUF;
+ break;
+ case _PC_CHOWN_RESTRICTED:
+ ret = 1;
+ break;
+ case _PC_NO_TRUNC:
+ case _PC_VDISABLE:
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+asmlinkage int solaris_pathconf(u32 path, int name)
+{
+ return solaris_fpathconf(0, name);
+}
+
+/* solaris_llseek returns long long - quite difficult */
+asmlinkage long solaris_llseek(struct pt_regs *regs, u32 off_hi, u32 off_lo, int whence)
+{
+ int (*sys_llseek)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int) =
+ (int (*)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int))SYS(_llseek);
+ int ret;
+ unsigned long old_fs = get_fs();
+ loff_t retval;
+
+ set_fs(KERNEL_DS);
+ ret = sys_llseek((unsigned int)regs->u_regs[UREG_I0], off_hi, off_lo, &retval, whence);
+ set_fs(old_fs);
+ if (ret < 0) return ret;
+ regs->u_regs[UREG_I1] = (u32)retval;
+ return (retval >> 32);
+}
+
+/* Have to mask out all but lower 3 bits */
+asmlinkage int solaris_access(u32 filename, long mode)
+{
+ int (*sys_access)(const char *, int) =
+ (int (*)(const char *, int))SYS(access);
+
+ return sys_access((const char *)A(filename), mode & 7);
+}
diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c
new file mode 100644
index 000000000..43b844caf
--- /dev/null
+++ b/arch/sparc64/solaris/ioctl.c
@@ -0,0 +1,316 @@
+/* $Id: ioctl.c,v 1.2 1997/09/04 00:59:22 davem Exp $
+ * ioctl.c: Solaris ioctl emulation.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Streams & timod emulation based on code
+ * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+
+#include <asm/uaccess.h>
+#include <asm/termios.h>
+
+#include "conv.h"
+
+extern char * getname32(u32 filename);
+#define putname32 putname
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd,
+ unsigned long arg);
+extern asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd,
+ u32 arg);
+asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
+
+/* termio* stuff {{{ */
+
+struct solaris_termios {
+ u32 c_iflag;
+ u32 c_oflag;
+ u32 c_cflag;
+ u32 c_lflag;
+ u8 c_cc[19];
+};
+
+struct solaris_termio {
+ u16 c_iflag;
+ u16 c_oflag;
+ u16 c_cflag;
+ u16 c_lflag;
+ s8 c_line;
+ u8 c_cc[8];
+};
+
+struct solaris_termiox {
+ u16 x_hflag;
+ u16 x_cflag;
+ u16 x_rflag[5];
+ u16 x_sflag;
+};
+
+static u32 solaris_to_linux_cflag(u32 cflag)
+{
+ cflag &= 0x7fdff000;
+ if (cflag & 0x200000) {
+ int baud = cflag & 0xf;
+ cflag &= ~0x20000f;
+ switch (baud) {
+ case 0: baud = B57600; break;
+ case 1: baud = B76800; break;
+ case 2: baud = B115200; break;
+ case 3: baud = B153600; break;
+ case 4: baud = B230400; break;
+ case 5: baud = B307200; break;
+ case 6: baud = B460800; break;
+ }
+ cflag |= CBAUDEX | baud;
+ }
+ return cflag;
+}
+
+static u32 linux_to_solaris_cflag(u32 cflag)
+{
+ cflag &= ~(CMSPAR | CIBAUD);
+ if (cflag & CBAUDEX) {
+ int baud = cflag & CBAUD;
+ cflag &= ~CBAUD;
+ switch (baud) {
+ case B57600: baud = 0; break;
+ case B76800: baud = 1; break;
+ case B115200: baud = 2; break;
+ case B153600: baud = 3; break;
+ case B230400: baud = 4; break;
+ case B307200: baud = 5; break;
+ case B460800: baud = 6; break;
+ case B614400: baud = 7; break;
+ case B921600: baud = 8; break;
+ /* case B1843200: baud = 9; break; */
+ }
+ cflag |= 0x200000 | baud;
+ }
+ return cflag;
+}
+
+static inline int linux_to_solaris_termio(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret;
+
+ ret = sys_ioctl(fd, cmd, A(arg));
+ if (!ret) {
+ u32 cflag;
+
+ if (__get_user (cflag, &((struct solaris_termio *)A(arg))->c_cflag))
+ return -EFAULT;
+ cflag = linux_to_solaris_cflag(cflag);
+ if (__put_user (cflag, &((struct solaris_termio *)A(arg))->c_cflag))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static int solaris_to_linux_termio(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret;
+ struct solaris_termio s;
+ unsigned long old_fs = get_fs();
+
+ if (copy_from_user (&s, (struct solaris_termio *)A(arg), sizeof(struct solaris_termio)))
+ return -EFAULT;
+ s.c_cflag = solaris_to_linux_cflag(s.c_cflag);
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, cmd, (unsigned long)&s);
+ set_fs(old_fs);
+ return ret;
+}
+
+static inline int linux_to_solaris_termios(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret;
+ struct solaris_termios s;
+ unsigned long old_fs = get_fs();
+
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, cmd, (unsigned long)&s);
+ set_fs(old_fs);
+ if (!ret) {
+ if (put_user (s.c_iflag, &((struct solaris_termios *)A(arg))->c_iflag) ||
+ __put_user (s.c_oflag, &((struct solaris_termios *)A(arg))->c_oflag) ||
+ __put_user (linux_to_solaris_cflag(s.c_cflag), &((struct solaris_termios *)A(arg))->c_cflag) ||
+ __put_user (s.c_lflag, &((struct solaris_termios *)A(arg))->c_lflag) ||
+ __copy_to_user (((struct solaris_termios *)A(arg))->c_cc, s.c_cc, 16) ||
+ __clear_user (((struct solaris_termios *)A(arg))->c_cc + 16, 2))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static int solaris_to_linux_termios(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret;
+ struct solaris_termios s;
+ unsigned long old_fs = get_fs();
+
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, TCGETS, (unsigned long)&s);
+ set_fs(old_fs);
+ if (ret) return ret;
+ if (put_user (s.c_iflag, &((struct solaris_termios *)A(arg))->c_iflag) ||
+ __put_user (s.c_oflag, &((struct solaris_termios *)A(arg))->c_oflag) ||
+ __put_user (s.c_cflag, &((struct solaris_termios *)A(arg))->c_cflag) ||
+ __put_user (s.c_lflag, &((struct solaris_termios *)A(arg))->c_lflag) ||
+ __copy_from_user (s.c_cc, ((struct solaris_termios *)A(arg))->c_cc, 16))
+ return -EFAULT;
+ s.c_cflag = solaris_to_linux_cflag(s.c_cflag);
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, cmd, (unsigned long)&s);
+ set_fs(old_fs);
+ return ret;
+}
+
+static inline int solaris_T(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ switch (cmd & 0xff) {
+ case 1: /* TCGETA */
+ return linux_to_solaris_termio(fd, TCGETA, arg);
+ case 2: /* TCSETA */
+ return solaris_to_linux_termio(fd, TCSETA, arg);
+ case 3: /* TCSETAW */
+ return solaris_to_linux_termio(fd, TCSETAW, arg);
+ case 4: /* TCSETAF */
+ return solaris_to_linux_termio(fd, TCSETAF, arg);
+ case 5: /* TCSBRK */
+ return sys_ioctl(fd, TCSBRK, arg);
+ case 6: /* TCXONC */
+ return sys_ioctl(fd, TCXONC, arg);
+ case 7: /* TCFLSH */
+ return sys_ioctl(fd, TCFLSH, arg);
+ case 13: /* TCGETS */
+ return linux_to_solaris_termios(fd, TCGETS, arg);
+ case 14: /* TCSETS */
+ return solaris_to_linux_termios(fd, TCSETS, arg);
+ case 15: /* TCSETSW */
+ return solaris_to_linux_termios(fd, TCSETSW, arg);
+ case 16: /* TCSETSF */
+ return solaris_to_linux_termios(fd, TCSETSF, arg);
+ case 103: /* TIOCSWINSZ */
+ return sys_ioctl(fd, TIOCSWINSZ, arg);
+ case 104: /* TIOCGWINSZ */
+ return sys_ioctl(fd, TIOCGWINSZ, arg);
+ }
+ return -ENOSYS;
+}
+
+static inline int solaris_t(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ switch (cmd & 0xff) {
+ case 20: /* TIOCGPGRP */
+ return sys_ioctl(fd, TIOCGPGRP, arg);
+ case 21: /* TIOCSPGRP */
+ return sys_ioctl(fd, TIOCSPGRP, arg);
+ }
+ return -ENOSYS;
+}
+
+/* }}} */
+
+/* A pseudo STREAMS support {{{ */
+
+struct strioctl {
+ int cmd, timeout, len;
+ u32 data;
+};
+
+static inline int solaris_S(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ char *p;
+ int ret;
+ unsigned long old_fs;
+ struct strioctl si;
+
+ switch (cmd & 0xff) {
+ case 1: /* I_NREAD */
+ return -ENOSYS;
+ case 2: /* I_PUSH */
+ p = getname32 (arg);
+ if (IS_ERR (p))
+ return PTR_ERR(p);
+ putname32 (p);
+ return 0;
+ case 3: /* I_POP */
+ return 0;
+ case 5: /* I_FLUSH */
+ return 0;
+ case 8: /* I_STR */
+ if (copy_from_user (&si, (struct strioctl *)A(arg), sizeof(struct strioctl)))
+ return -EFAULT;
+ switch ((si.cmd >> 8) & 0xff) {
+ case 'T':
+ default:
+ return solaris_ioctl(fd, si.cmd, si.data);
+ }
+ case 9: /* I_SETSIG */
+ return sys_ioctl(fd, FIOSETOWN, current->pid);
+ case 10: /* I_GETSIG */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ sys_ioctl(fd, FIOGETOWN, (unsigned long)&ret);
+ set_fs(old_fs);
+ if (ret == current->pid) return 0x3ff;
+ else return -EINVAL;
+ case 11: /* I_FIND */
+ p = getname32 (arg);
+ if (IS_ERR (p))
+ return PTR_ERR(p);
+ ret = !strcmp(p, "timod");
+ putname32 (p);
+ return ret;
+ }
+ return -ENOSYS;
+}
+/* }}} */
+
+asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ struct file * filp;
+ int error = -EBADF;
+
+ lock_kernel();
+ if(fd >= NR_OPEN) goto out;
+
+ filp = current->files->fd[fd];
+ if(!filp) goto out;
+
+ if (!filp->f_op || !filp->f_op->ioctl) {
+ error = sys_ioctl (fd, cmd, (unsigned long)arg);
+ goto out;
+ }
+
+ error = -EFAULT;
+ switch ((cmd >> 8) & 0xff) {
+ case 'S': error = solaris_S(fd, cmd, arg); break;
+ case 'T': error = solaris_T(fd, cmd, arg); break;
+ case 't': error = solaris_t(fd, cmd, arg); break;
+ default:
+ error = -ENOSYS;
+ break;
+ }
+out:
+ if (error == -ENOSYS) {
+ unsigned char c = cmd>>8;
+
+ if (c < ' ' || c > 126) c = '.';
+ printk("solaris_ioctl: Unknown cmd fd(%d) cmd(%08x '%c') arg(%08x)\n",
+ (int)fd, (unsigned int)cmd, c, (unsigned int)arg);
+ error = -EINVAL;
+ }
+ unlock_kernel();
+ return error;
+}
diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c
new file mode 100644
index 000000000..132028447
--- /dev/null
+++ b/arch/sparc64/solaris/ipc.c
@@ -0,0 +1,122 @@
+/* $Id: ipc.c,v 1.1 1997/09/03 12:29:29 jj Exp $
+ * ipc.c: Solaris IPC emulation
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+#include <linux/shm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/ipc.h>
+
+#include "conv.h"
+
+struct solaris_ipc_perm {
+ s32 uid;
+ s32 gid;
+ s32 cuid;
+ s32 cgid;
+ u32 mode;
+ u32 seq;
+ int key;
+ s32 pad[4];
+};
+
+struct solaris_shmid_ds {
+ struct solaris_ipc_perm shm_perm;
+ int shm_segsz;
+ u32 shm_amp;
+ unsigned short shm_lkcnt;
+ char __padxx[2];
+ s32 shm_lpid;
+ s32 shm_cpid;
+ u32 shm_nattch;
+ u32 shm_cnattch;
+ s32 shm_atime;
+ s32 shm_pad1;
+ s32 shm_dtime;
+ s32 shm_pad2;
+ s32 shm_ctime;
+ s32 shm_pad3;
+ unsigned short shm_cv;
+ char shm_pad4[2];
+ u32 shm_sptas;
+ s32 shm_pad5[2];
+};
+
+asmlinkage long solaris_shmsys(int cmd, u32 arg1, u32 arg2, u32 arg3)
+{
+ int (*sys_ipc)(unsigned,int,int,unsigned long,void *,long) =
+ (int (*)(unsigned,int,int,unsigned long,void *,long))SYS(ipc);
+ unsigned long old_fs;
+ unsigned long raddr;
+ int ret;
+
+ switch (cmd) {
+ case 0: /* shmat */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ipc(SHMAT, arg1, arg3 & ~0x4000, (unsigned long)&raddr, (void *)A(arg2), 0);
+ set_fs(old_fs);
+ if (ret >= 0) return (u32)raddr;
+ else return ret;
+ case 1: /* shmctl */
+ switch (arg2) {
+ case 3: /* SHM_LOCK */
+ case 4: /* SHM_UNLOCK */
+ return sys_ipc(SHMCTL, arg1, (arg2 == 3) ? SHM_LOCK : SHM_UNLOCK, 0, NULL, 0);
+ case 10: /* IPC_RMID */
+ return sys_ipc(SHMCTL, arg1, IPC_RMID, 0, NULL, 0);
+ case 11: /* IPC_SET */
+ {
+ struct shmid_ds s;
+
+ if (get_user (s.shm_perm.uid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.uid)) ||
+ __get_user (s.shm_perm.gid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.gid)) ||
+ __get_user (s.shm_perm.mode, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.mode)))
+ return -EFAULT;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ipc(SHMCTL, arg1, IPC_SET, 0, &s, 0);
+ set_fs(old_fs);
+ return ret;
+ }
+ case 12: /* IPC_STAT */
+ {
+ struct shmid_ds s;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ipc(SHMCTL, arg1, IPC_SET, 0, &s, 0);
+ set_fs(old_fs);
+ if (get_user (s.shm_perm.uid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.uid)) ||
+ __get_user (s.shm_perm.gid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.gid)) ||
+ __get_user (s.shm_perm.cuid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.cuid)) ||
+ __get_user (s.shm_perm.cgid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.cgid)) ||
+ __get_user (s.shm_perm.mode, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.mode)) ||
+ __get_user (s.shm_perm.seq, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.seq)) ||
+ __get_user (s.shm_perm.key, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.key)) ||
+ __get_user (s.shm_segsz, &(((struct solaris_shmid_ds *)A(arg3))->shm_segsz)) ||
+ __get_user (s.shm_lpid, &(((struct solaris_shmid_ds *)A(arg3))->shm_lpid)) ||
+ __get_user (s.shm_cpid, &(((struct solaris_shmid_ds *)A(arg3))->shm_cpid)) ||
+ __get_user (s.shm_nattch, &(((struct solaris_shmid_ds *)A(arg3))->shm_nattch)) ||
+ __get_user (s.shm_atime, &(((struct solaris_shmid_ds *)A(arg3))->shm_atime)) ||
+ __get_user (s.shm_dtime, &(((struct solaris_shmid_ds *)A(arg3))->shm_dtime)) ||
+ __get_user (s.shm_ctime, &(((struct solaris_shmid_ds *)A(arg3))->shm_ctime)))
+ return -EFAULT;
+ return ret;
+ }
+ default: return -EINVAL;
+ }
+ case 2: /* shmdt */
+ return sys_ipc(SHMDT, 0, 0, 0, (void *)A(arg1), 0);
+ case 3: /* shmget */
+ return sys_ipc(SHMGET, arg1, arg2, arg3, NULL, 0);
+ }
+ return -EINVAL;
+}
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
new file mode 100644
index 000000000..fdabd0e26
--- /dev/null
+++ b/arch/sparc64/solaris/misc.c
@@ -0,0 +1,463 @@
+/* $Id: misc.c,v 1.4 1997/09/04 14:57:31 jj Exp $
+ * misc.c: Miscelaneous syscall emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+#include <linux/utsname.h>
+#include <linux/limits.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/oplib.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+
+#include "conv.h"
+
+/* Conversion from Linux to Solaris errnos. 0-34 are identity mapped.
+ Some Linux errnos (EPROCLIM, EDOTDOT, ERREMOTE, EUCLEAN, ENOTNAM,
+ ENAVAIL, EISNAM, EREMOTEIO, ENOMEDIUM, EMEDIUMTYPE) have no Solaris
+ equivalents. I return EINVAL in that case, which is very wrong. If
+ someone suggest a better value for them, you're welcomed.
+ On the other side, Solaris ECANCELED and ENOTSUP have no Linux equivalents,
+ but that doesn't matter here. --jj */
+int solaris_err_table[] = {
+/* 0 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+/* 10 */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+/* 20 */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+/* 30 */ 30, 31, 32, 33, 34, 22, 150, 149, 95, 96,
+/* 40 */ 97, 98, 99, 120, 121, 122, 123, 124, 125, 126,
+/* 50 */ 127, 128, 129, 130, 131, 132, 133, 134, 143, 144,
+/* 60 */ 145, 146, 90, 78, 147, 148, 93, 22, 94, 49,
+/* 70 */ 151, 66, 60, 62, 63, 35, 77, 36, 45, 46,
+/* 80 */ 64, 22, 67, 68, 69, 70, 71, 74, 22, 82,
+/* 90 */ 89, 92, 79, 81, 37, 38, 39, 40, 41, 42,
+/* 100 */ 43, 44, 50, 51, 52, 53, 54, 55, 56, 57,
+/* 110 */ 87, 61, 84, 65, 83, 80, 91, 22, 22, 22,
+/* 120 */ 22, 22, 88, 86, 85, 22, 22,
+};
+
+asmlinkage u32 solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
+{
+ u32 (*sunos_mmap)(u32,u32,u32,u32,u32,u32) =
+ (u32 (*)(u32,u32,u32,u32,u32,u32))SUNOS(71);
+ u32 ret;
+
+ ret = sunos_mmap(addr,len,prot,flags,fd,off);
+ /* sunos_mmap sets personality to PER_BSD */
+ current->personality = PER_SVR4;
+ return ret;
+}
+
+asmlinkage int solaris_brk(u32 brk)
+{
+ int (*sunos_brk)(u32) = (int (*)(u32))SUNOS(17);
+
+ return sunos_brk(brk);
+}
+
+#define set_utsfield(to, from, dotchop, countfrom) { \
+ char *p; \
+ int i, len = (countfrom) ? \
+ ((sizeof(to) > sizeof(from) ? \
+ sizeof(from) : sizeof(to))) : sizeof(to); \
+ copy_to_user_ret(to, from, len, -EFAULT); \
+ if (dotchop) \
+ for (p=from,i=0; *p && *p != '.' && --len; p++,i++); \
+ else \
+ i = len - 1; \
+ __put_user_ret('\0', (char *)(to+i), -EFAULT); \
+}
+
+struct sol_uname {
+ char sysname[9];
+ char nodename[9];
+ char release[9];
+ char version[9];
+ char machine[9];
+};
+
+struct sol_utsname {
+ char sysname[257];
+ char nodename[257];
+ char release[257];
+ char version[257];
+ char machine[257];
+};
+
+static char *machine(void)
+{
+ switch (sparc_cpu_model) {
+ case sun4: return "sun4";
+ case sun4c: return "sun4c";
+ case sun4e: return "sun4e";
+ case sun4m: return "sun4m";
+ case sun4d: return "sun4d";
+ case sun4u: return "sun4u";
+ default: return "sparc";
+ }
+}
+
+static char *platform(char *buffer)
+{
+ int i;
+ struct {
+ char *platform;
+ int id_machtype;
+ } platforms [] = {
+ { "sun4", (SM_SUN4 | SM_4_110) },
+ { "sun4", (SM_SUN4 | SM_4_260) },
+ { "sun4", (SM_SUN4 | SM_4_330) },
+ { "sun4", (SM_SUN4 | SM_4_470) },
+ { "SUNW,Sun_4_60", (SM_SUN4C | SM_4C_SS1) },
+ { "SUNW,Sun_4_40", (SM_SUN4C | SM_4C_IPC) },
+ { "SUNW,Sun_4_65", (SM_SUN4C | SM_4C_SS1PLUS) },
+ { "SUNW,Sun_4_20", (SM_SUN4C | SM_4C_SLC) },
+ { "SUNW,Sun_4_75", (SM_SUN4C | SM_4C_SS2) },
+ { "SUNW,Sun_4_25", (SM_SUN4C | SM_4C_ELC) },
+ { "SUNW,Sun_4_50", (SM_SUN4C | SM_4C_IPX) },
+ { "SUNW,Sun_4_600", (SM_SUN4M | SM_4M_SS60) },
+ { "SUNW,SPARCstation-5", (SM_SUN4M | SM_4M_SS50) },
+ { "SUNW,SPARCstation-20", (SM_SUN4M | SM_4M_SS40) }
+ };
+
+ *buffer = 0;
+ prom_getproperty(prom_root_node, "name", buffer, 256);
+ if (*buffer) {
+ char *p;
+
+ for (p = buffer; *p; p++)
+ if (*p == '/' || *p == ' ') *p = '_';
+ return buffer;
+ }
+ for (i = 0; i < sizeof (platforms)/sizeof (platforms[0]); i++)
+ if (platforms[i].id_machtype == idprom->id_machtype)
+ return platforms[i].platform;
+ return "sun4c";
+}
+
+static char *serial(char *buffer)
+{
+ int node = prom_getchild(prom_root_node);
+
+ node = prom_searchsiblings(node, "options");
+ *buffer = 0;
+ prom_getproperty(node, "system-board-serial#", buffer, 256);
+ if (!*buffer)
+ return "4512348717234";
+ else
+ return buffer;
+}
+
+asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2)
+{
+ switch (which) {
+ case 0: /* old uname */
+ /* Lets cheat */
+ set_utsfield(((struct sol_uname *)A(buf))->sysname,
+ "SunOS", 1, 0);
+ set_utsfield(((struct sol_uname *)A(buf))->nodename,
+ system_utsname.nodename, 1, 1);
+ set_utsfield(((struct sol_uname *)A(buf))->release,
+ "2.6", 0, 0);
+ set_utsfield(((struct sol_uname *)A(buf))->version,
+ "Generic", 0, 0);
+ set_utsfield(((struct sol_uname *)A(buf))->machine,
+ machine(), 0, 0);
+ return 0;
+ case 2: /* ustat */
+ return -ENOSYS;
+ case 3: /* fusers */
+ return -ENOSYS;
+ default:
+ return -ENOSYS;
+ }
+}
+
+asmlinkage int solaris_utsname(u32 buf)
+{
+ /* Why should we not lie a bit? */
+ set_utsfield(((struct sol_utsname *)A(buf))->sysname,
+ "SunOS", 0, 0);
+ set_utsfield(((struct sol_utsname *)A(buf))->nodename,
+ system_utsname.nodename, 1, 1);
+ set_utsfield(((struct sol_utsname *)A(buf))->release,
+ "5.6", 0, 0);
+ set_utsfield(((struct sol_utsname *)A(buf))->version,
+ "Generic", 0, 0);
+ set_utsfield(((struct sol_utsname *)A(buf))->machine,
+ machine(), 0, 0);
+ return 0;
+}
+
+#define SI_SYSNAME 1 /* return name of operating system */
+#define SI_HOSTNAME 2 /* return name of node */
+#define SI_RELEASE 3 /* return release of operating system */
+#define SI_VERSION 4 /* return version field of utsname */
+#define SI_MACHINE 5 /* return kind of machine */
+#define SI_ARCHITECTURE 6 /* return instruction set arch */
+#define SI_HW_SERIAL 7 /* return hardware serial number */
+#define SI_HW_PROVIDER 8 /* return hardware manufacturer */
+#define SI_SRPC_DOMAIN 9 /* return secure RPC domain */
+#define SI_PLATFORM 513 /* return platform identifier */
+
+asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count)
+{
+ char *p, *q, *r;
+ char buffer[256];
+ int len;
+
+ /* Again, we cheat :)) */
+ switch (cmd) {
+ case SI_SYSNAME: r = "SunOS"; break;
+ case SI_HOSTNAME:
+ r = buffer + 256;
+ for (p = system_utsname.nodename, q = buffer;
+ q < r && *p && *p != '.'; *q++ = *p++);
+ *q = 0;
+ r = buffer;
+ break;
+ case SI_RELEASE: r = "5.6"; break;
+ case SI_MACHINE: r = machine(); break;
+ case SI_ARCHITECTURE: r = "sparc"; break;
+ case SI_HW_PROVIDER: r = "Sun_Microsystems"; break;
+ case SI_HW_SERIAL: r = serial(buffer); break;
+ case SI_PLATFORM: r = platform(buffer); break;
+ case SI_SRPC_DOMAIN: r = ""; break;
+ case SI_VERSION: r = "Generic"; break;
+ default: return -EINVAL;
+ }
+ len = strlen(r) + 1;
+ if (count < len) {
+ copy_to_user_ret((char *)A(buf), r, count - 1, -EFAULT);
+ __put_user_ret(0, (char *)A(buf) + count - 1, -EFAULT);
+ } else
+ copy_to_user_ret((char *)A(buf), r, len, -EFAULT);
+ return len;
+}
+
+#define SOLARIS_CONFIG_NGROUPS 2
+#define SOLARIS_CONFIG_CHILD_MAX 3
+#define SOLARIS_CONFIG_OPEN_FILES 4
+#define SOLARIS_CONFIG_POSIX_VER 5
+#define SOLARIS_CONFIG_PAGESIZE 6
+#define SOLARIS_CONFIG_CLK_TCK 7
+#define SOLARIS_CONFIG_XOPEN_VER 8
+#define SOLARIS_CONFIG_PROF_TCK 10
+#define SOLARIS_CONFIG_NPROC_CONF 11
+#define SOLARIS_CONFIG_NPROC_ONLN 12
+#define SOLARIS_CONFIG_AIO_LISTIO_MAX 13
+#define SOLARIS_CONFIG_AIO_MAX 14
+#define SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX 15
+#define SOLARIS_CONFIG_DELAYTIMER_MAX 16
+#define SOLARIS_CONFIG_MQ_OPEN_MAX 17
+#define SOLARIS_CONFIG_MQ_PRIO_MAX 18
+#define SOLARIS_CONFIG_RTSIG_MAX 19
+#define SOLARIS_CONFIG_SEM_NSEMS_MAX 20
+#define SOLARIS_CONFIG_SEM_VALUE_MAX 21
+#define SOLARIS_CONFIG_SIGQUEUE_MAX 22
+#define SOLARIS_CONFIG_SIGRT_MIN 23
+#define SOLARIS_CONFIG_SIGRT_MAX 24
+#define SOLARIS_CONFIG_TIMER_MAX 25
+#define SOLARIS_CONFIG_PHYS_PAGES 26
+#define SOLARIS_CONFIG_AVPHYS_PAGES 27
+
+asmlinkage int solaris_sysconf(int id)
+{
+ switch (id) {
+ case SOLARIS_CONFIG_NGROUPS: return NGROUPS_MAX;
+ case SOLARIS_CONFIG_CHILD_MAX: return CHILD_MAX;
+ case SOLARIS_CONFIG_OPEN_FILES: return OPEN_MAX;
+ case SOLARIS_CONFIG_POSIX_VER: return 199309;
+ case SOLARIS_CONFIG_PAGESIZE: return PAGE_SIZE;
+ case SOLARIS_CONFIG_XOPEN_VER: return 3;
+ case SOLARIS_CONFIG_CLK_TCK:
+ case SOLARIS_CONFIG_PROF_TCK:
+ return prom_getintdefault(
+ linux_cpus[smp_processor_id()].prom_node,
+ "clock-frequency", 167000000);
+#ifdef __SMP__
+ case SOLARIS_CONFIG_NPROC_CONF: return NCPUS;
+ case SOLARIS_CONFIG_NPROC_ONLN: return smp_num_cpus;
+#else
+ case SOLARIS_CONFIG_NPROC_CONF: return 1;
+ case SOLARIS_CONFIG_NPROC_ONLN: return 1;
+#endif
+ case SOLARIS_CONFIG_SIGRT_MIN: return 37;
+ case SOLARIS_CONFIG_SIGRT_MAX: return 44;
+ case SOLARIS_CONFIG_PHYS_PAGES:
+ case SOLARIS_CONFIG_AVPHYS_PAGES:
+ {
+ struct sysinfo s;
+
+ si_meminfo(&s);
+ if (id == SOLARIS_CONFIG_PHYS_PAGES)
+ return s.totalram >>= PAGE_SHIFT;
+ else
+ return s.freeram >>= PAGE_SHIFT;
+ }
+ /* XXX support these as well -jj */
+ case SOLARIS_CONFIG_AIO_LISTIO_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_AIO_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_DELAYTIMER_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_MQ_OPEN_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_MQ_PRIO_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_RTSIG_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_SEM_NSEMS_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_SEM_VALUE_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_SIGQUEUE_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_TIMER_MAX: return -EINVAL;
+ default: return -EINVAL;
+ }
+}
+
+asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid)
+{
+ int ret;
+
+ switch (cmd) {
+ case 0: /* getpgrp */
+ return current->pgrp;
+ case 1: /* setpgrp */
+ {
+ int (*sys_setpgid)(pid_t,pid_t) =
+ (int (*)(pid_t,pid_t))SYS(setpgid);
+
+ /* can anyone explain me the difference between
+ Solaris setpgrp and setsid? */
+ ret = sys_setpgid(0, 0);
+ if (ret) return ret;
+ current->tty = NULL;
+ return current->pgrp;
+ }
+ case 2: /* getsid */
+ {
+ int (*sys_getsid)(pid_t) = (int (*)(pid_t))SYS(getsid);
+ return sys_getsid(pid);
+ }
+ case 3: /* setsid */
+ {
+ int (*sys_setsid)(void) = (int (*)(void))SYS(setsid);
+ return sys_setsid();
+ }
+ case 4: /* getpgid */
+ {
+ int (*sys_getpgid)(pid_t) = (int (*)(pid_t))SYS(getpgid);
+ return sys_getpgid(pid);
+ }
+ case 5: /* setpgid */
+ {
+ int (*sys_setpgid)(pid_t,pid_t) =
+ (int (*)(pid_t,pid_t))SYS(setpgid);
+ return sys_setpgid(pid,pgid);
+ }
+ }
+ return -EINVAL;
+}
+
+asmlinkage int do_sol_unimplemented(struct pt_regs *regs)
+{
+ printk ("Unimplemented Solaris syscall %d %08x %08x %08x %08x\n",
+ (int)regs->u_regs[UREG_G1],
+ (int)regs->u_regs[UREG_I0],
+ (int)regs->u_regs[UREG_I1],
+ (int)regs->u_regs[UREG_I2],
+ (int)regs->u_regs[UREG_I3]);
+ return -ENOSYS;
+}
+
+asmlinkage void solaris_register(void)
+{
+ lock_kernel();
+ current->personality = PER_SVR4;
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_DEC_USE_COUNT(current->exec_domain->module);
+ current->exec_domain = lookup_exec_domain(current->personality);
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_INC_USE_COUNT(current->exec_domain->module);
+ unlock_kernel();
+}
+
+extern long solaris_to_linux_signals[], linux_to_solaris_signals[];
+
+struct exec_domain solaris_exec_domain = {
+ "Solaris",
+ (lcall7_func)NULL,
+ 1, 1, /* PER_SVR4 personality */
+ solaris_to_linux_signals,
+ linux_to_solaris_signals,
+#ifdef MODULE
+ &__this_module,
+#else
+ NULL,
+#endif
+ NULL
+};
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Jakub Jelinek (jj@sunsite.mff.cuni.cz)");
+MODULE_DESCRIPTION("Solaris binary emulation module");
+
+#ifdef __sparc_v9__
+extern u32 tl0_solaris[8];
+#define update_ttable(x) \
+ tl0_solaris[3] = (((long)(x) - (long)tl0_solaris - 3) >> 2) | 0x40000000; \
+ __asm__ __volatile__ ("membar #StoreStore; flush %0" : : "r" (&tl0_solaris[3]))
+#else
+#endif
+
+extern u32 solaris_sparc_syscall[];
+extern u32 solaris_syscall[];
+extern int init_socksys(void);
+extern void cleanup_socksys(void);
+
+int init_module(void)
+{
+ int ret;
+ register_exec_domain(&solaris_exec_domain);
+ if ((ret = init_socksys())) {
+ unregister_exec_domain(&solaris_exec_domain);
+ return ret;
+ }
+ update_ttable(solaris_sparc_syscall);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ update_ttable(solaris_syscall);
+ cleanup_socksys();
+ unregister_exec_domain(&solaris_exec_domain);
+}
+
+#else
+int init_solaris_emul(void)
+{
+ register_exec_domain(&solaris_exec_domain);
+ init_socksys();
+}
+#endif
+
+#ifdef DEBUG_SOLARIS
+void entry_printk(int sysno, struct pt_regs *regs)
+{
+ printk ("Entering %d\n", sysno);
+ printk ("%08x %08x %08x %08x\n", (int)regs->u_regs[UREG_I0],
+ (int)regs->u_regs[UREG_I1],
+ (int)regs->u_regs[UREG_I2],
+ (int)regs->u_regs[UREG_I3]);
+}
+
+void exit_printk(unsigned long ret)
+{
+ printk ("Returning %016lx\n", ret);
+}
+#endif
diff --git a/arch/sparc64/solaris/signal.c b/arch/sparc64/solaris/signal.c
new file mode 100644
index 000000000..6d3081c03
--- /dev/null
+++ b/arch/sparc64/solaris/signal.c
@@ -0,0 +1,419 @@
+/* $Id: signal.c,v 1.2 1997/09/03 12:29:19 jj Exp $
+ * signal.c: Signal emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/svr4.h>
+#include <asm/string.h>
+
+#include "conv.h"
+#include "signal.h"
+
+#define _S(nr) (1L<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+long linux_to_solaris_signals[] = {
+ 0,
+ SOLARIS_SIGHUP, SOLARIS_SIGINT,
+ SOLARIS_SIGQUIT, SOLARIS_SIGILL,
+ SOLARIS_SIGTRAP, SOLARIS_SIGIOT,
+ SOLARIS_SIGEMT, SOLARIS_SIGFPE,
+ SOLARIS_SIGKILL, SOLARIS_SIGBUS,
+ SOLARIS_SIGSEGV, SOLARIS_SIGSYS,
+ SOLARIS_SIGPIPE, SOLARIS_SIGALRM,
+ SOLARIS_SIGTERM, SOLARIS_SIGURG,
+ SOLARIS_SIGSTOP, SOLARIS_SIGTSTP,
+ SOLARIS_SIGCONT, SOLARIS_SIGCLD,
+ SOLARIS_SIGTTIN, SOLARIS_SIGTTOU,
+ SOLARIS_SIGPOLL, SOLARIS_SIGXCPU,
+ SOLARIS_SIGXFSZ, SOLARIS_SIGVTALRM,
+ SOLARIS_SIGPROF, SOLARIS_SIGWINCH,
+ SOLARIS_SIGUSR1, SOLARIS_SIGUSR1,
+ SOLARIS_SIGUSR2, -1,
+};
+
+long solaris_to_linux_signals[] = {
+ 0,
+ SIGHUP, SIGINT, SIGQUIT, SIGILL,
+ SIGTRAP, SIGIOT, SIGEMT, SIGFPE,
+ SIGKILL, SIGBUS, SIGSEGV, SIGSYS,
+ SIGPIPE, SIGALRM, SIGTERM, SIGUSR1,
+ SIGUSR2, SIGCHLD, -1, SIGWINCH,
+ SIGURG, SIGPOLL, SIGSTOP, SIGTSTP,
+ SIGCONT, SIGTTIN, SIGTTOU, SIGVTALRM,
+ SIGPROF, SIGXCPU, SIGXFSZ, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+};
+
+static inline long mapsig(long sig)
+{
+ if ((unsigned long)sig > SOLARIS_NSIGNALS)
+ return -EINVAL;
+ return solaris_to_linux_signals[sig];
+}
+
+asmlinkage int solaris_kill(int pid, int sig)
+{
+ int (*sys_kill)(int,int) =
+ (int (*)(int,int))SYS(kill);
+ int s = mapsig(sig);
+
+ if (s < 0) return s;
+ return sys_kill(pid, s);
+}
+
+static long sig_handler(int sig, u32 arg, int one_shot)
+{
+ struct sigaction sa, old;
+ int ret;
+ unsigned long old_fs = get_fs();
+ int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) =
+ (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction);
+
+ sa.sa_mask = 0L;
+ sa.sa_restorer = NULL;
+ sa.sa_handler = (__sighandler_t)A(arg);
+ sa.sa_flags = 0;
+ if (one_shot) sa.sa_flags = SA_ONESHOT | SA_NOMASK;
+ set_fs (KERNEL_DS);
+ ret = sys_sigaction(sig, &sa, &old);
+ set_fs (old_fs);
+ if (ret < 0) return ret;
+ return (u32)(long)old.sa_handler;
+}
+
+static inline long solaris_signal(int sig, u32 arg)
+{
+ return sig_handler (sig, arg, 1);
+}
+
+static long solaris_sigset(int sig, u32 arg)
+{
+ if (arg != 2) /* HOLD */ {
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked &= ~_S(sig);
+ spin_unlock_irq(&current->sigmask_lock);
+ return sig_handler (sig, arg, 0);
+ } else {
+ sigset_t n = _S(sig) & _BLOCKABLE;
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked |= n;
+ spin_unlock_irq(&current->sigmask_lock);
+ return 0;
+ }
+}
+
+static inline long solaris_sighold(int sig)
+{
+ return solaris_sigset(sig, 2);
+}
+
+static inline long solaris_sigrelse(int sig)
+{
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked &= ~_S(sig);
+ spin_unlock_irq(&current->sigmask_lock);
+ return 0;
+}
+
+static inline long solaris_sigignore(int sig)
+{
+ return sig_handler (sig, (u32)SIG_IGN, 0);
+}
+
+static inline long solaris_sigpause(int sig)
+{
+ printk ("Need to support solaris sigpause\n");
+ return -ENOSYS;
+}
+
+asmlinkage long solaris_sigfunc(int sig, u32 arg)
+{
+ int func = sig & ~0xff;
+
+ sig = mapsig(sig & 0xff);
+ if (sig < 0) return sig;
+ switch (func) {
+ case 0: return solaris_signal(sig, arg);
+ case 0x100: return solaris_sigset(sig, arg);
+ case 0x200: return solaris_sighold(sig);
+ case 0x400: return solaris_sigrelse(sig);
+ case 0x800: return solaris_sigignore(sig);
+ case 0x1000: return solaris_sigpause(sig);
+ }
+ return -EINVAL;
+}
+
+typedef struct {
+ u32 __sigbits[4];
+} sol_sigset_t;
+
+static inline int mapin(u32 *p, sigset_t *q)
+{
+ int i;
+ u32 x;
+ int sig;
+
+ *q = 0L;
+ x = p[0];
+ for (i = 1; i <= SOLARIS_NSIGNALS; i++) {
+ if (x & 1) {
+ sig = solaris_to_linux_signals[i];
+ if (sig == -1)
+ return -EINVAL;
+ *q |= 1L << (sig - 1);
+ }
+ x >>= 1;
+ if (i == 32)
+ x = p[1];
+ }
+ return 0;
+}
+
+static inline int mapout(sigset_t *q, u32 *p)
+{
+ int i;
+ sigset_t x;
+ int sig;
+
+ p[0] = 0;
+ p[1] = 0;
+ x = *q;
+ for (i = 1; i <= 32; i++, x >>= 1) {
+ if (x & 1) {
+ sig = linux_to_solaris_signals[i];
+ if (sig == -1)
+ return -EINVAL;
+ if (sig > 32)
+ p[1] |= 1L << (sig - 33);
+ else
+ p[0] |= 1L << (sig - 1);
+ }
+ }
+ return 0;
+
+}
+
+asmlinkage int solaris_sigprocmask(int how, u32 in, u32 out)
+{
+ sigset_t in_s, *ins, out_s, *outs;
+ unsigned long old_fs = get_fs();
+ int ret;
+ int (*sys_sigprocmask)(int,sigset_t *,sigset_t *) =
+ (int (*)(int,sigset_t *,sigset_t *))SYS(sigprocmask);
+
+ ins = NULL; outs = NULL;
+ if (in) {
+ u32 tmp[2];
+
+ if (copy_from_user (tmp, (sol_sigset_t *)A(in), 2*sizeof(u32)))
+ return -EFAULT;
+ ins = &in_s;
+ if (mapin (tmp, ins)) return -EINVAL;
+ }
+ if (out) outs = &out_s;
+ set_fs (KERNEL_DS);
+ ret = sys_sigprocmask((how == 3) ? SIG_SETMASK : how, ins, outs);
+ set_fs (old_fs);
+ if (ret) return ret;
+ if (out) {
+ u32 tmp[4];
+
+ tmp[2] = 0; tmp[3] = 0;
+ if (mapout (outs, tmp)) return -EINVAL;
+ if (copy_to_user((sol_sigset_t *)A(out), tmp, 4*sizeof(u32)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage long do_sol_sigsuspend(u32 mask)
+{
+ sigset_t s;
+ u32 tmp[2];
+
+ if (copy_from_user (tmp, (sol_sigset_t *)A(mask), 2*sizeof(u32)))
+ return -EFAULT;
+ if (mapin (tmp, &s)) return -EINVAL;
+ return (long)s;
+}
+
+struct sol_sigaction {
+ int sa_flags;
+ u32 sa_handler;
+ u32 sa_mask[4];
+ int sa_resv[2];
+};
+
+asmlinkage int solaris_sigaction(int sig, u32 act, u32 old)
+{
+ u32 tmp, tmp2[4];
+ struct sigaction s, s2;
+ int ret;
+ unsigned long old_fs = get_fs();
+ int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) =
+ (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction);
+
+ sig = mapsig(sig);
+ if (sig < 0) {
+ /* We cheat a little bit for Solaris only signals */
+ if (old && clear_user((struct sol_sigaction *)A(old), sizeof(struct sol_sigaction)))
+ return -EFAULT;
+ return 0;
+ }
+ if (act) {
+ if (get_user (tmp, &((struct sol_sigaction *)A(act))->sa_flags))
+ return -EFAULT;
+ s.sa_flags = 0;
+ if (tmp & SOLARIS_SA_ONSTACK) s.sa_flags |= SA_STACK;
+ if (tmp & SOLARIS_SA_RESTART) s.sa_flags |= SA_RESTART;
+ if (tmp & SOLARIS_SA_NODEFER) s.sa_flags |= SA_NOMASK;
+ if (tmp & SOLARIS_SA_RESETHAND) s.sa_flags |= SA_ONESHOT;
+ if (tmp & SOLARIS_SA_NOCLDSTOP) s.sa_flags |= SA_NOCLDSTOP;
+ if (get_user (tmp, &((struct sol_sigaction *)A(act))->sa_handler) ||
+ copy_from_user (tmp2, &((struct sol_sigaction *)A(act))->sa_mask, 2*sizeof(u32)))
+ return -EFAULT;
+ s.sa_handler = (__sighandler_t)A(tmp);
+ if (mapin (tmp2, &s.sa_mask)) return -EINVAL;
+ s.sa_restorer = 0;
+ }
+ set_fs(KERNEL_DS);
+ ret = sys_sigaction(sig, act ? &s : NULL, old ? &s2 : NULL);
+ set_fs(old_fs);
+ if (ret) return ret;
+ if (old) {
+ if (mapout (&s2.sa_mask, tmp2)) return -EINVAL;
+ tmp = 0; tmp2[2] = 0; tmp2[3] = 0;
+ if (s2.sa_flags & SA_STACK) tmp |= SOLARIS_SA_ONSTACK;
+ if (s2.sa_flags & SA_RESTART) tmp |= SOLARIS_SA_RESTART;
+ if (s2.sa_flags & SA_NOMASK) tmp |= SOLARIS_SA_NODEFER;
+ if (s2.sa_flags & SA_ONESHOT) tmp |= SOLARIS_SA_RESETHAND;
+ if (s2.sa_flags & SA_NOCLDSTOP) tmp |= SOLARIS_SA_NOCLDSTOP;
+ if (put_user (tmp, &((struct sol_sigaction *)A(old))->sa_flags) ||
+ __put_user ((u32)(long)s2.sa_handler, &((struct sol_sigaction *)A(old))->sa_handler) ||
+ copy_to_user (&((struct sol_sigaction *)A(old))->sa_mask, tmp2, 4*sizeof(u32)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage int solaris_sigpending(int which, u32 set)
+{
+ sigset_t s;
+ u32 tmp[4];
+ switch (which) {
+ case 1: /* sigpending */
+ lock_kernel();
+ s = current->blocked & current->signal;
+ unlock_kernel();
+ break;
+ case 2: /* sigfillset - I just set signals which have linux equivalents */
+ s = 0x7fffffff;
+ break;
+ default: return -EINVAL;
+ }
+ if (mapout (&s, tmp)) return -EINVAL;
+ tmp[2] = 0; tmp[3] = 0;
+ if (copy_to_user ((u32 *)A(set), tmp, sizeof(tmp)))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage int solaris_wait(u32 stat_loc)
+{
+ int (*sys_wait4)(pid_t,unsigned int *, int, struct rusage *) =
+ (int (*)(pid_t,unsigned int *, int, struct rusage *))SYS(wait4);
+ int ret, status;
+
+ ret = sys_wait4(-1, (unsigned int *)A(stat_loc), WUNTRACED, NULL);
+ if (ret >= 0 && stat_loc) {
+ if (get_user (status, (unsigned int *)A(stat_loc)))
+ return -EFAULT;
+ if (((status - 1) & 0xffff) < 0xff)
+ status = linux_to_solaris_signals[status & 0x7f] & 0x7f;
+ else if ((status & 0xff) == 0x7f)
+ status = (linux_to_solaris_signals[(status >> 8) & 0xff] << 8) | 0x7f;
+ if (__put_user (status, (unsigned int *)A(stat_loc)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+asmlinkage int solaris_waitid(int idtype, s32 pid, u32 info, int options)
+{
+ int (*sys_wait4)(pid_t,unsigned int *, int, struct rusage *) =
+ (int (*)(pid_t,unsigned int *, int, struct rusage *))SYS(wait4);
+ int opts, status, ret;
+
+ switch (idtype) {
+ case 0: /* P_PID */ break;
+ case 1: /* P_PGID */ pid = -pid; break;
+ case 7: /* P_ALL */ pid = -1; break;
+ default: return -EINVAL;
+ }
+ opts = 0;
+ if (options & SOLARIS_WUNTRACED) opts |= WUNTRACED;
+ if (options & SOLARIS_WNOHANG) opts |= WNOHANG;
+ current->state = TASK_RUNNING;
+ ret = sys_wait4(pid, (unsigned int *)A(info), opts, NULL);
+ if (ret < 0) return ret;
+ if (info) {
+ struct sol_siginfo *s = (struct sol_siginfo *)A(info);
+
+ if (get_user (status, (unsigned int *)A(info))) return -EFAULT;
+ __put_user_ret (SOLARIS_SIGCLD, &s->si_signo, -EFAULT);
+ __put_user_ret (ret, &s->_data._proc._pid, -EFAULT);
+ switch (status & 0xff) {
+ case 0: ret = SOLARIS_CLD_EXITED;
+ status = (status >> 8) & 0xff;
+ break;
+ case 0x7f:
+ status = (status >> 8) & 0xff;
+ switch (status) {
+ case SIGSTOP:
+ case SIGTSTP: ret = SOLARIS_CLD_STOPPED;
+ default: ret = SOLARIS_CLD_EXITED;
+ }
+ status = linux_to_solaris_signals[status];
+ break;
+ default:
+ if (status & 0x80) ret = SOLARIS_CLD_DUMPED;
+ else ret = SOLARIS_CLD_KILLED;
+ status = linux_to_solaris_signals[status & 0x7f];
+ break;
+ }
+ __put_user_ret (ret, &s->si_code, -EFAULT);
+ __put_user_ret (status, &s->_data._proc._pdata._cld._status, -EFAULT);
+ }
+ return 0;
+}
+
+extern int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs);
+extern int svr4_getcontext(svr4_ucontext_t *c, struct pt_regs *regs);
+
+asmlinkage int solaris_context(struct pt_regs *regs)
+{
+ switch ((unsigned)regs->u_regs[UREG_I0]) {
+ case 0: /* getcontext */
+ return svr4_getcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
+ case 1: /* setcontext */
+ return svr4_setcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
+ default:
+ return -EINVAL;
+
+ }
+}
+
+asmlinkage int solaris_sigaltstack(u32 ss, u32 oss)
+{
+/* XXX Implement this soon */
+ return 0;
+}
diff --git a/arch/sparc64/solaris/signal.h b/arch/sparc64/solaris/signal.h
new file mode 100644
index 000000000..2e948c788
--- /dev/null
+++ b/arch/sparc64/solaris/signal.h
@@ -0,0 +1,109 @@
+/* $Id: signal.h,v 1.2 1997/09/03 12:29:21 jj Exp $
+ * signal.h: Signal emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#define SOLARIS_SIGHUP 1
+#define SOLARIS_SIGINT 2
+#define SOLARIS_SIGQUIT 3
+#define SOLARIS_SIGILL 4
+#define SOLARIS_SIGTRAP 5
+#define SOLARIS_SIGIOT 6
+#define SOLARIS_SIGEMT 7
+#define SOLARIS_SIGFPE 8
+#define SOLARIS_SIGKILL 9
+#define SOLARIS_SIGBUS 10
+#define SOLARIS_SIGSEGV 11
+#define SOLARIS_SIGSYS 12
+#define SOLARIS_SIGPIPE 13
+#define SOLARIS_SIGALRM 14
+#define SOLARIS_SIGTERM 15
+#define SOLARIS_SIGUSR1 16
+#define SOLARIS_SIGUSR2 17
+#define SOLARIS_SIGCLD 18
+#define SOLARIS_SIGPWR 19
+#define SOLARIS_SIGWINCH 20
+#define SOLARIS_SIGURG 21
+#define SOLARIS_SIGPOLL 22
+#define SOLARIS_SIGSTOP 23
+#define SOLARIS_SIGTSTP 24
+#define SOLARIS_SIGCONT 25
+#define SOLARIS_SIGTTIN 26
+#define SOLARIS_SIGTTOU 27
+#define SOLARIS_SIGVTALRM 28
+#define SOLARIS_SIGPROF 29
+#define SOLARIS_SIGXCPU 30
+#define SOLARIS_SIGXFSZ 31
+#define SOLARIS_SIGWAITING 32
+#define SOLARIS_SIGLWP 33
+#define SOLARIS_SIGFREEZE 34
+#define SOLARIS_SIGTHAW 35
+#define SOLARIS_SIGCANCEL 36
+#define SOLARIS_SIGRTMIN 37
+#define SOLARIS_SIGRTMAX 44
+#define SOLARIS_NSIGNALS 44
+
+
+#define SOLARIS_SA_ONSTACK 1
+#define SOLARIS_SA_RESETHAND 2
+#define SOLARIS_SA_RESTART 4
+#define SOLARIS_SA_SIGINFO 8
+#define SOLARIS_SA_NODEFER 16
+#define SOLARIS_SA_NOCLDWAIT 0x10000
+#define SOLARIS_SA_NOCLDSTOP 0x20000
+
+struct sol_siginfo {
+ int si_signo;
+ int si_code;
+ int si_errno;
+ union {
+ char pad[128-3*sizeof(int)];
+ struct {
+ s32 _pid;
+ union {
+ struct {
+ s32 _uid;
+ s32 _value;
+ } _kill;
+ struct {
+ s32 _utime;
+ int _status;
+ s32 _stime;
+ } _cld;
+ } _pdata;
+ } _proc;
+ struct { /* SIGSEGV, SIGBUS, SIGILL and SIGFPE */
+ u32 _addr;
+ int _trapno;
+ } _fault;
+ struct { /* SIGPOLL, SIGXFSZ */
+ int _fd;
+ s32 _band;
+ } _file;
+ } _data;
+};
+
+#define SOLARIS_WUNTRACED 0x04
+#define SOLARIS_WNOHANG 0x40
+#define SOLARIS_WEXITED 0x01
+#define SOLARIS_WTRAPPED 0x02
+#define SOLARIS_WSTOPPED WUNTRACED
+#define SOLARIS_WCONTINUED 0x08
+#define SOLARIS_WNOWAIT 0x80
+
+#define SOLARIS_TRAP_BRKPT 1
+#define SOLARIS_TRAP_TRACE 2
+#define SOLARIS_CLD_EXITED 1
+#define SOLARIS_CLD_KILLED 2
+#define SOLARIS_CLD_DUMPED 3
+#define SOLARIS_CLD_TRAPPED 4
+#define SOLARIS_CLD_STOPPED 5
+#define SOLARIS_CLD_CONTINUED 6
+#define SOLARIS_POLL_IN 1
+#define SOLARIS_POLL_OUT 2
+#define SOLARIS_POLL_MSG 3
+#define SOLARIS_POLL_ERR 4
+#define SOLARIS_POLL_PRI 5
+#define SOLARIS_POLL_HUP 6
+
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
new file mode 100644
index 000000000..984b1bdb5
--- /dev/null
+++ b/arch/sparc64/solaris/socksys.c
@@ -0,0 +1,127 @@
+/* $Id: socksys.c,v 1.1 1997/09/03 12:29:27 jj Exp $
+ * socksys.c: /dev/inet/ stuff for Solaris emulation.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+
+#include <asm/uaccess.h>
+#include <asm/termios.h>
+
+#include "conv.h"
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd,
+ unsigned long arg);
+
+static int af_inet_protocols[] = {
+IPPROTO_ICMP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP,
+IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW,
+0, 0, 0, 0, 0, 0,
+};
+
+static struct file_operations socksys_file_ops = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* open */
+ NULL, /* release */
+};
+
+static int socksys_open(struct inode * inode, struct file * filp)
+{
+ int family, type, protocol, fd;
+ int (*sys_socket)(int,int,int) =
+ (int (*)(int,int,int))SUNOS(97);
+
+ family = ((MINOR(inode->i_rdev) >> 4) & 0xf);
+ switch (family) {
+ case AF_UNIX:
+ type = SOCK_STREAM;
+ protocol = 0;
+ break;
+ case AF_INET:
+ protocol = af_inet_protocols[MINOR(inode->i_rdev) & 0xf];
+ switch (protocol) {
+ case IPPROTO_TCP: type = SOCK_STREAM; break;
+ case IPPROTO_UDP: type = SOCK_DGRAM; break;
+ default: type = SOCK_RAW; break;
+ }
+ break;
+ default:
+ type = SOCK_RAW;
+ protocol = 0;
+ break;
+ }
+ fd = sys_socket(family, type, protocol);
+ if (fd < 0) return fd;
+ return 0;
+}
+
+static int socksys_release(struct inode * inode, struct file * filp)
+{
+ return 0;
+}
+
+static unsigned int socksys_poll(struct file * filp, poll_table * wait)
+{
+ return 0;
+}
+
+static struct file_operations socksys_fops = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ socksys_open, /* open */
+ socksys_release,/* release */
+};
+
+__initfunc(int
+init_socksys(void))
+{
+ int ret;
+ int (*sys_socket)(int,int,int) =
+ (int (*)(int,int,int))SUNOS(97);
+ int (*sys_close)(unsigned int) =
+ (int (*)(unsigned int))SYS(close);
+
+ ret = register_chrdev (30, "socksys", &socksys_fops);
+ if (ret < 0) {
+ printk ("Couldn't register socksys character device\n");
+ return ret;
+ }
+ ret = sys_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (ret < 0) {
+ printk ("Couldn't create socket\n");
+ return ret;
+ }
+ socksys_file_ops = *current->files->fd[ret]->f_op;
+ sys_close(ret);
+ socksys_file_ops.poll = socksys_poll;
+ socksys_file_ops.release = socksys_release;
+ return 0;
+}
+
+void
+cleanup_socksys(void)
+{
+ if (unregister_chrdev (30, "socksys"))
+ printk ("Couldn't unregister socksys character device\n");
+}
diff --git a/arch/sparc64/solaris/systbl.S b/arch/sparc64/solaris/systbl.S
new file mode 100644
index 000000000..c425fb721
--- /dev/null
+++ b/arch/sparc64/solaris/systbl.S
@@ -0,0 +1,289 @@
+/* $Id: systbl.S,v 1.5 1997/09/04 15:46:24 jj Exp $
+ * systbl.S: System call entry point table for Solaris compatibility.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+
+#include <asm/unistd.h>
+
+/* Fall back to sys_call_table32 entry */
+#define CHAIN(name) __NR_##name
+
+/* Pass pt_regs pointer as first argument */
+#define REGS(name) name+1
+
+/* Hack till all be implemented */
+#define solaris_getmsg solaris_unimplemented
+#define solaris_getpmsg solaris_unimplemented
+#define solaris_hrtsys solaris_unimplemented
+#define solaris_msgsys solaris_unimplemented
+#define solaris_putmsg solaris_unimplemented
+#define solaris_putpmsg solaris_unimplemented
+#define solaris_semsys solaris_unimplemented
+
+ .data
+ .align 1024
+ .globl solaris_sys_table
+solaris_sys_table:
+ .word solaris_unimplemented /* nosys 0 */
+ .word CHAIN(exit) /* exit d 1 */
+ .word CHAIN(fork) /* fork 2 */
+ .word CHAIN(read) /* read dpd 3 */
+ .word CHAIN(write) /* write dpd 4 */
+ .word solaris_open /* open soo 5 */
+ .word CHAIN(close) /* close d 6 */
+ .word solaris_wait /* wait xxx 7 */
+ .word CHAIN(creat) /* creat so 8 */
+ .word CHAIN(link) /* link ss 9 */
+ .word CHAIN(unlink) /* unlink s 10 */
+ .word solaris_unimplemented /* exec sxx 11 */
+ .word CHAIN(chdir) /* chdir s 12 */
+ .word CHAIN(time) /* time 13 */
+ .word solaris_mknod /* mknod sox 14 */
+ .word CHAIN(chmod) /* chmod so 15 */
+ .word solaris_chown /* chown sdd 16 */
+ .word solaris_brk /* brk/break x 17 */
+ .word solaris_stat /* stat sp 18 */
+ .word CHAIN(lseek) /* seek/lseek ddd 19 */
+ .word solaris_getpid /* getpid 20 */
+ .word solaris_unimplemented /* mount 21 */
+ .word CHAIN(umount) /* umount s 22 */
+ .word CHAIN(setuid) /* setuid d 23 */
+ .word solaris_getuid /* getuid 24 */
+ .word CHAIN(stime) /* stime d 25 */
+#if 0
+ .word solaris_ptrace /* ptrace xdxx 26 */
+#else
+ .word CHAIN(ptrace) /* ptrace xdxx 26 */
+#endif
+ .word CHAIN(alarm) /* alarm d 27 */
+ .word solaris_fstat /* fstat dp 28 */
+ .word CHAIN(pause) /* pause 29 */
+ .word CHAIN(utime) /* utime xx 30 */
+ .word solaris_unimplemented /* stty 31 */
+ .word solaris_unimplemented /* gtty 32 */
+ .word solaris_access /* access so 33 */
+ .word CHAIN(nice) /* nice d 34 */
+ .word solaris_statfs /* statfs spdd 35 */
+ .word CHAIN(sync) /* sync 36 */
+ .word solaris_kill /* kill dd 37 */
+ .word solaris_fstatfs /* fstatfs dpdd 38 */
+ .word solaris_procids /* pgrpsys ddd 39 */
+ .word solaris_unimplemented /* xenix 40 */
+ .word CHAIN(dup) /* dup d 41 */
+ .word CHAIN(pipe) /* pipe 42 */
+ .word CHAIN(times) /* times p 43 */
+ .word CHAIN(profil) /* prof xxxx 44 */
+ .word solaris_unimplemented /* lock/plock 45 */
+ .word CHAIN(setgid) /* setgid d 46 */
+ .word solaris_getgid /* getgid 47 */
+ .word solaris_sigfunc /* sigfunc xx 48 */
+ .word REGS(solaris_msgsys) /* msgsys dxddd 49 */
+ .word solaris_unimplemented /* syssun/3b 50 */
+ .word CHAIN(acct) /* acct/sysacct x 51 */
+ .word solaris_shmsys /* shmsys ddxo 52 */
+ .word REGS(solaris_semsys) /* semsys dddx 53 */
+ .word solaris_ioctl /* ioctl dxx 54 */
+ .word solaris_unimplemented /* uadmin xxx 55 */
+ .word solaris_unimplemented /* reserved:exch 56 */
+ .word solaris_utssys /* utssys x 57 */
+ .word CHAIN(fsync) /* fsync d 58 */
+ .word CHAIN(execve) /* execv spp 59 */
+ .word CHAIN(umask) /* umask o 60 */
+ .word CHAIN(chroot) /* chroot s 61 */
+ .word solaris_fcntl /* fcntl dxx 62 */
+ .word solaris_ulimit /* ulimit xx 63 */
+ .word solaris_unimplemented /* ? 64 */
+ .word solaris_unimplemented /* ? 65 */
+ .word solaris_unimplemented /* ? 66 */
+ .word solaris_unimplemented /* ? 67 */
+ .word solaris_unimplemented /* ? 68 */
+ .word solaris_unimplemented /* ? 69 */
+ .word solaris_unimplemented /* advfs 70 */
+ .word solaris_unimplemented /* unadvfs 71 */
+ .word solaris_unimplemented /* rmount 72 */
+ .word solaris_unimplemented /* rumount 73 */
+ .word solaris_unimplemented /* rfstart 74 */
+ .word solaris_unimplemented /* ? 75 */
+ .word solaris_unimplemented /* rdebug 76 */
+ .word solaris_unimplemented /* rfstop 77 */
+ .word solaris_unimplemented /* rfsys 78 */
+ .word CHAIN(rmdir) /* rmdir s 79 */
+ .word CHAIN(mkdir) /* mkdir so 80 */
+ .word CHAIN(getdents) /* getdents dxd 81 */
+ .word solaris_unimplemented /* libattach 82 */
+ .word solaris_unimplemented /* libdetach 83 */
+ .word CHAIN(sysfs) /* sysfs dxx 84 */
+ .word REGS(solaris_getmsg) /* getmsg dxxx 85 */
+ .word REGS(solaris_putmsg) /* putmsg dxxd 86 */
+ .word CHAIN(poll) /* poll xdd 87 */
+ .word solaris_lstat /* lstat sp 88 */
+ .word CHAIN(symlink) /* symlink ss 89 */
+ .word CHAIN(readlink) /* readlink spd 90 */
+ .word CHAIN(setgroups) /* setgroups dp 91 */
+ .word CHAIN(getgroups) /* getgroups dp 92 */
+ .word CHAIN(fchmod) /* fchmod do 93 */
+ .word CHAIN(fchown) /* fchown ddd 94 */
+ .word solaris_sigprocmask /* sigprocmask dxx 95 */
+ .word solaris_sigsuspend /* sigsuspend x 96 */
+ .word solaris_sigaltstack /* sigaltstack xx 97 */
+ .word solaris_sigaction /* sigaction dxx 98 */
+ .word solaris_sigpending /* sigpending dd 99 */
+ .word REGS(solaris_context) /* context 100 */
+ .word solaris_unimplemented /* evsys 101 */
+ .word solaris_unimplemented /* evtrapret 102 */
+ .word solaris_statvfs /* statvfs sp 103 */
+ .word solaris_fstatvfs /* fstatvfs dp 104 */
+ .word solaris_unimplemented /* unknown 105 */
+ .word solaris_unimplemented /* nfssys 106 */
+ .word solaris_waitid /* waitid ddxd 107 */
+ .word solaris_unimplemented /* sigsendsys ddd 108 */
+ .word REGS(solaris_hrtsys) /* hrtsys xxx 109 */
+ .word solaris_unimplemented /* acancel dxd 110 */
+ .word solaris_unimplemented /* async 111 */
+ .word solaris_unimplemented /* priocntlsys 112 */
+ .word solaris_pathconf /* pathconf sd 113 */
+ .word solaris_unimplemented /* mincore xdx 114 */
+ .word solaris_mmap /* mmap xxxxdx 115 */
+ .word CHAIN(mprotect) /* mprotect xdx 116 */
+ .word CHAIN(munmap) /* munmap xd 117 */
+ .word solaris_fpathconf /* fpathconf dd 118 */
+ .word CHAIN(fork) /* fork 119 */
+ .word solaris_unimplemented /* fchdir d 120 */
+ .word CHAIN(readv) /* readv dxd 121 */
+ .word CHAIN(writev) /* writev dxd 122 */
+ .word solaris_xstat /* xstat dsx 123 */
+ .word solaris_lxstat /* lxstat dsx 124 */
+ .word solaris_fxstat /* fxstat ddx 125 */
+ .word solaris_xmknod /* xmknod dsox 126 */
+ .word solaris_unimplemented /* syslocal d 127 */
+ .word solaris_unimplemented /* setrlimit 128 */
+ .word solaris_unimplemented /* getrlimit 129 */
+ .word CHAIN(chown) /* lchown sdd 130 */
+ .word solaris_unimplemented /* memcntl 131 */
+ .word solaris_getpmsg /* getpmsg dxxxx 132 */
+ .word solaris_putpmsg /* putpmsg dxxdd 133 */
+ .word CHAIN(rename) /* rename ss 134 */
+ .word solaris_utsname /* uname x 135 */
+ .word solaris_unimplemented /* setegid 136 */
+ .word solaris_sysconf /* sysconfig d 137 */
+ .word solaris_unimplemented /* adjtime 138 */
+ .word solaris_sysinfo /* systeminfo dsd 139 */
+ .word solaris_unimplemented /* ? 140 */
+ .word solaris_unimplemented /* seteuid 141 */
+ .word solaris_unimplemented /* ? 142 */
+ .word solaris_unimplemented /* ? 143 */
+ .word solaris_unimplemented /* secsys dx 144 */
+ .word solaris_unimplemented /* filepriv sdxd 145 */
+ .word solaris_unimplemented /* procpriv dxd 146 */
+ .word solaris_unimplemented /* devstat sdx 147 */
+ .word solaris_unimplemented /* aclipc ddddx 148 */
+ .word solaris_unimplemented /* fdevstat ddx 149 */
+ .word solaris_unimplemented /* flvlfile ddx 150 */
+ .word solaris_unimplemented /* lvlfile sdx 151 */
+ .word solaris_unimplemented /* ? 152 */
+ .word solaris_unimplemented /* fchroot d 153 */
+ .word solaris_unimplemented /* lvlproc dx 154 */
+ .word solaris_unimplemented /* ? 155 */
+ .word CHAIN(gettimeofday) /* gettimeofday xx 156 */
+ .word CHAIN(getitimer) /* getitimer dx 157 */
+ .word CHAIN(setitimer) /* setitimer dxx 158 */
+ .word solaris_unimplemented /* lwp-xxx 159 */
+ .word solaris_unimplemented /* lwp-xxx 160 */
+ .word solaris_unimplemented /* lwp-xxx 161 */
+ .word solaris_unimplemented /* lwp-xxx 162 */
+ .word solaris_unimplemented /* lwp-xxx 163 */
+ .word solaris_unimplemented /* lwp-xxx 164 */
+ .word solaris_unimplemented /* lwp-xxx 165 */
+ .word solaris_unimplemented /* lwp-xxx 166 */
+ .word solaris_unimplemented /* lwp-xxx 167 */
+ .word solaris_unimplemented /* lwp-xxx 168 */
+ .word solaris_unimplemented /* lwp-xxx 169 */
+ .word solaris_unimplemented /* lwp-xxx 170 */
+ .word solaris_unimplemented /* lwp-xxx 171 */
+ .word solaris_unimplemented /* lwp-xxx 172 */
+ .word solaris_pread /* pread dpdd 173 */
+ .word solaris_pwrite /* pwrite dpdd 174 */
+ .word REGS(solaris_llseek) /* llseek dLd 175 */
+ .word solaris_unimplemented /* lwpself 176 */
+ .word solaris_unimplemented /* lwpinfo 177 */
+ .word solaris_unimplemented /* lwpprivate 178 */
+ .word solaris_unimplemented /* processorbind 179 */
+ .word solaris_unimplemented /* processorexbind 180 */
+ .word solaris_unimplemented /* 181 */
+ .word solaris_unimplemented /* sync_mailbox 182 */
+ .word solaris_unimplemented /* prepblock 183 */
+ .word solaris_unimplemented /* block 184 */
+ .word solaris_acl /* acl sddp 185 */
+ .word solaris_unimplemented /* unblock 186 */
+ .word solaris_unimplemented /* cancelblock 187 */
+ .word solaris_unimplemented /* ? 188 */
+ .word solaris_unimplemented /* xxxxx 189 */
+ .word solaris_unimplemented /* xxxxxe 190 */
+ .word solaris_unimplemented /* 191 */
+ .word solaris_unimplemented /* 192 */
+ .word solaris_unimplemented /* 193 */
+ .word solaris_unimplemented /* 194 */
+ .word solaris_unimplemented /* 195 */
+ .word solaris_unimplemented /* 196 */
+ .word solaris_unimplemented /* 197 */
+ .word solaris_unimplemented /* 198 */
+ .word CHAIN(nanosleep) /* nanosleep dd 199 */
+ .word solaris_facl /* facl dddp 200 */
+ .word solaris_unimplemented /* 201 */
+ .word solaris_unimplemented /* 202 */
+ .word solaris_unimplemented /* 203 */
+ .word solaris_unimplemented /* 204 */
+ .word solaris_unimplemented /* 205 */
+ .word solaris_unimplemented /* 206 */
+ .word solaris_unimplemented /* 207 */
+ .word solaris_unimplemented /* 208 */
+ .word solaris_unimplemented /* 209 */
+ .word solaris_unimplemented /* 210 */
+ .word solaris_unimplemented /* 211 */
+ .word solaris_unimplemented /* 212 */
+ .word solaris_unimplemented /* 213 */
+ .word solaris_unimplemented /* 214 */
+ .word solaris_unimplemented /* 215 */
+ .word solaris_unimplemented /* 216 */
+ .word solaris_unimplemented /* 217 */
+ .word solaris_unimplemented /* 218 */
+ .word solaris_unimplemented /* 219 */
+ .word solaris_unimplemented /* 220 */
+ .word solaris_unimplemented /* 221 */
+ .word solaris_unimplemented /* 222 */
+ .word solaris_unimplemented /* 223 */
+ .word solaris_unimplemented /* 224 */
+ .word solaris_unimplemented /* 225 */
+ .word solaris_unimplemented /* 226 */
+ .word solaris_unimplemented /* 227 */
+ .word solaris_unimplemented /* 228 */
+ .word solaris_unimplemented /* 229 */
+ .word solaris_unimplemented /* 230 */
+ .word solaris_unimplemented /* 231 */
+ .word solaris_unimplemented /* 232 */
+ .word solaris_unimplemented /* 233 */
+ .word solaris_unimplemented /* 234 */
+ .word solaris_unimplemented /* 235 */
+ .word solaris_unimplemented /* 236 */
+ .word solaris_unimplemented /* 237 */
+ .word solaris_unimplemented /* 238 */
+ .word solaris_unimplemented /* 239 */
+ .word solaris_unimplemented /* 240 */
+ .word solaris_unimplemented /* 241 */
+ .word solaris_unimplemented /* 242 */
+ .word solaris_unimplemented /* 243 */
+ .word solaris_unimplemented /* 244 */
+ .word solaris_unimplemented /* 245 */
+ .word solaris_unimplemented /* 246 */
+ .word solaris_unimplemented /* 247 */
+ .word solaris_unimplemented /* 248 */
+ .word solaris_unimplemented /* 249 */
+ .word solaris_unimplemented /* 250 */
+ .word solaris_unimplemented /* 251 */
+ .word solaris_unimplemented /* 252 */
+ .word solaris_unimplemented /* 253 */
+ .word solaris_unimplemented /* 254 */
+ .word solaris_unimplemented /* 255 */
+
diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds
index eac8314ca..661acc098 100644
--- a/arch/sparc64/vmlinux.lds
+++ b/arch/sparc64/vmlinux.lds
@@ -52,12 +52,14 @@ SECTIONS
. += 8192;
empty_bad_pte_table = .;
. += 8192;
+ empty_bad_page = .;
+ . += 8192;
+ . += 0x40;
empty_null_pmd_table = .;
. += 8192;
+ . += 0x40;
empty_null_pte_table = .;
. += 8192;
- empty_bad_page = .;
- . += 8192;
}
_end = . ;
PROVIDE (end = .);