]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.44 2.1.44
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:27 +0000 (15:13 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:27 +0000 (15:13 -0500)
299 files changed:
CREDITS
Documentation/binfmt_misc.txt
Documentation/m68k/amiboot.txt
Documentation/networking/ax25.txt
Documentation/networking/x25.txt
arch/alpha/defconfig
arch/alpha/kernel/osf_sys.c
arch/i386/defconfig
arch/i386/kernel/irq.c
arch/i386/kernel/setup.c
arch/m68k/amiga/amifb.c
arch/m68k/amiga/config.c
arch/m68k/amiga/cyberfb.c
arch/m68k/atari/atakeyb.c
arch/m68k/boot/amiga/bootstrap.c
arch/m68k/boot/amiga/linuxboot.c
arch/m68k/config.in
arch/m68k/console/fbcon.c
arch/m68k/defconfig
arch/m68k/kernel/console.c
arch/m68k/mm/memory.c
arch/mips/Makefile
arch/mips/defconfig
arch/mips/jazz/g364.c
arch/mips/kernel/gdb-stub.c
arch/mips/kernel/head.S
arch/mips/kernel/irixelf.c
arch/mips/kernel/irq.c
arch/mips/kernel/r2300_fpu.S
arch/mips/kernel/r4k_fpu.S
arch/mips/kernel/r6000_fpu.S
arch/mips/kernel/signal.c
arch/mips/kernel/syscalls.h
arch/mips/kernel/sysirix.c
arch/mips/kernel/sysmips.c
arch/mips/kernel/time.c
arch/mips/lib/checksum.c
arch/mips/mm/r2300.c
arch/mips/mm/r4xx0.c
arch/mips/sgi/kernel/indy_int.c
arch/mips/sgi/kernel/indy_timer.c
arch/mips/sgi/kernel/setup.c
arch/mips/sgi/kernel/system.c
arch/mips/tools/offset.c
arch/sparc/kernel/cpu.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/mm/Makefile
arch/sparc/mm/srmmu.c
arch/sparc/mm/turbosparc.S [new file with mode: 0644]
arch/sparc/prom/bootstr.c
arch/sparc/prom/tree.c
arch/sparc64/Makefile
arch/sparc64/config.in
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/binfmt_aout32.c [new file with mode: 0644]
arch/sparc64/kernel/cpu.c
arch/sparc64/kernel/devices.c
arch/sparc64/kernel/dtlb_miss.S
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/etrap.S
arch/sparc64/kernel/hack.S [deleted file]
arch/sparc64/kernel/head.S
arch/sparc64/kernel/ioport.c
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/rtrap.S
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/signal32.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sunos_ioctl32.c [new file with mode: 0644]
arch/sparc64/kernel/sys32.S [new file with mode: 0644]
arch/sparc64/kernel/sys_sparc.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/sys_sunos32.c [new file with mode: 0644]
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/ttable.S
arch/sparc64/kernel/unaligned.c
arch/sparc64/kernel/winfixup.S
arch/sparc64/lib/Makefile
arch/sparc64/lib/VIS.h [new file with mode: 0644]
arch/sparc64/lib/VISbzero.S [new file with mode: 0644]
arch/sparc64/lib/VIScopy.S [new file with mode: 0644]
arch/sparc64/lib/VISmemset.S [new file with mode: 0644]
arch/sparc64/lib/blockops.S
arch/sparc64/lib/checksum.S
arch/sparc64/lib/copy_from_user.S [deleted file]
arch/sparc64/lib/copy_to_user.S [deleted file]
arch/sparc64/lib/memcpy.S [deleted file]
arch/sparc64/lib/memset.S [deleted file]
arch/sparc64/mm/Makefile
arch/sparc64/mm/fault.c
arch/sparc64/mm/generic.c
arch/sparc64/mm/init.c
arch/sparc64/mm/modutil.c [new file with mode: 0644]
arch/sparc64/mm/ultra.S [new file with mode: 0644]
arch/sparc64/prom/bootstr.c
arch/sparc64/prom/misc.c
arch/sparc64/prom/p1275.c
arch/sparc64/vmlinux.lds
drivers/block/floppy.c
drivers/char/psaux.c
drivers/char/pty.c
drivers/char/random.c
drivers/char/rtc.c
drivers/char/sysrq.c
drivers/char/tty_io.c
drivers/char/vc_screen.c
drivers/isdn/avmb1/capiutil.c
drivers/net/Config.in
drivers/net/cops.c
drivers/net/cops_ffdrv.h
drivers/net/cops_ltdrv.h
drivers/pnp/parport_procfs.c
drivers/sbus/char/cgsix.c
drivers/sbus/char/openprom.c
drivers/sbus/char/sunfb.c
drivers/sbus/char/sunkbd.c
drivers/sbus/char/sunmouse.c
drivers/sbus/char/sunserial.c
drivers/scsi/BusLogic.h
drivers/scsi/amiga7xx.c
drivers/scsi/ppa.c
drivers/scsi/sr_ioctl.c
drivers/sound/dev_table.h
fs/affs/namei.c
fs/autofs/autofs_i.h
fs/autofs/dir.c
fs/autofs/dirhash.c
fs/autofs/inode.c
fs/autofs/root.c
fs/autofs/symlink.c
fs/autofs/waitq.c
fs/binfmt_elf.c
fs/binfmt_misc.c
fs/buffer.c
fs/dcache.c
fs/dquot.c
fs/ext2/balloc.c
fs/ext2/dir.c
fs/ext2/file.c
fs/ext2/namei.c
fs/ext2/super.c
fs/ext2/symlink.c
fs/fat/misc.c
fs/inode.c
fs/minix/namei.c
fs/namei.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/symlink.c
fs/open.c
fs/proc/arbitrary.c
fs/proc/array.c
fs/proc/base.c
fs/proc/fd.c
fs/proc/generic.c
fs/proc/inode.c
fs/proc/kmsg.c
fs/proc/link.c
fs/proc/mem.c
fs/proc/net.c
fs/proc/omirr.c
fs/proc/openpromfs.c
fs/proc/root.c
fs/proc/scsi.c
fs/readdir.c
fs/stat.c
fs/super.c
include/asm-alpha/pgtable.h
include/asm-i386/pgtable.h
include/asm-m68k/hardirq.h
include/asm-m68k/pgtable.h
include/asm-mips/atomic.h
include/asm-mips/byteorder.h
include/asm-mips/checksum.h
include/asm-mips/offset.h
include/asm-mips/pgtable.h
include/asm-mips/r4kcache.h
include/asm-mips/sigcontext.h
include/asm-mips/uaccess.h
include/asm-ppc/pgtable.h
include/asm-sparc/asi.h
include/asm-sparc/ioctls.h
include/asm-sparc/mbus.h
include/asm-sparc/oplib.h
include/asm-sparc/pgtable.h
include/asm-sparc/turbosparc.h [new file with mode: 0644]
include/asm-sparc64/asm_offsets.h
include/asm-sparc64/atomic.h
include/asm-sparc64/bitops.h
include/asm-sparc64/checksum.h
include/asm-sparc64/delay.h
include/asm-sparc64/fpumacro.h
include/asm-sparc64/head.h
include/asm-sparc64/ioctls.h
include/asm-sparc64/mmu_context.h
include/asm-sparc64/page.h
include/asm-sparc64/pgtable.h
include/asm-sparc64/processor.h
include/asm-sparc64/psrcompat.h
include/asm-sparc64/pstate.h
include/asm-sparc64/ptrace.h
include/asm-sparc64/reg.h
include/asm-sparc64/sigcontext.h
include/asm-sparc64/string.h
include/asm-sparc64/system.h
include/asm-sparc64/uaccess.h
include/asm-sparc64/uctx.h [new file with mode: 0644]
include/asm-sparc64/vaddrs.h
include/linux/binfmts.h
include/linux/console_struct.h
include/linux/dalloc.h
include/linux/ext2_fs.h
include/linux/fs.h
include/linux/ghash.h [new file with mode: 0644]
include/linux/proc_fs.h
include/linux/rose.h
include/linux/sched.h
include/linux/selection.h
include/linux/simp.h [new file with mode: 0644]
include/linux/slab.h
include/linux/tty.h
include/linux/x25.h
include/net/ax25.h
include/net/lapb.h
include/net/netrom.h
include/net/rose.h
include/net/x25.h
kernel/exit.c
kernel/fork.c
kernel/ksyms.c
kernel/module.c
kernel/sysctl.c
mm/mmap.c
mm/slab.c
mm/swapfile.c
mm/vmalloc.c
net/Makefile
net/README
net/ax25/af_ax25.c
net/ax25/ax25_addr.c
net/ax25/ax25_dev.c
net/ax25/ax25_ds_in.c
net/ax25/ax25_ds_subr.c
net/ax25/ax25_ds_timer.c
net/ax25/ax25_iface.c
net/ax25/ax25_in.c
net/ax25/ax25_ip.c
net/ax25/ax25_out.c
net/ax25/ax25_route.c
net/ax25/ax25_std_in.c
net/ax25/ax25_std_subr.c
net/ax25/ax25_std_timer.c
net/ax25/ax25_subr.c
net/ax25/ax25_timer.c
net/ax25/ax25_uid.c
net/ax25/sysctl_net_ax25.c
net/core/sysctl_net_core.c
net/ipv4/tcp_ipv4.c
net/lapb/lapb_iface.c
net/lapb/lapb_in.c
net/lapb/lapb_out.c
net/lapb/lapb_subr.c
net/lapb/lapb_timer.c
net/netrom/af_netrom.c
net/netrom/nr_dev.c
net/netrom/nr_in.c
net/netrom/nr_out.c
net/netrom/nr_route.c
net/netrom/nr_subr.c
net/netrom/nr_timer.c
net/netrom/sysctl_net_netrom.c
net/rose/af_rose.c
net/rose/rose_dev.c
net/rose/rose_in.c
net/rose/rose_link.c
net/rose/rose_out.c
net/rose/rose_route.c
net/rose/rose_subr.c
net/rose/rose_timer.c
net/rose/sysctl_net_rose.c
net/socket.c
net/unix/sysctl_net_unix.c
net/x25/af_x25.c
net/x25/sysctl_net_x25.c
net/x25/x25_dev.c
net/x25/x25_facilities.c
net/x25/x25_in.c
net/x25/x25_link.c
net/x25/x25_out.c
net/x25/x25_route.c
net/x25/x25_subr.c
net/x25/x25_timer.c

diff --git a/CREDITS b/CREDITS
index 33d2c8b892892c706e594c1c6ba4ad00924b27a6..ba5c57c529784f2e0268a13d720dc71ef24ef927 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1055,8 +1055,9 @@ S: FIN-00330 Helsingfors
 S: Finland
 
 N: Jonathan Naylor
-E: jsn@cs.nott.ac.uk
+E: g4klx@g4klx.demon.co.uk
 E: g4klx@amsat.org
+W: http://zone.pspt.fi/~jsn/
 D: AX.25, NET/ROM and ROSE amateur radio protocol suites
 D: CCITT X.25 PLP and LAPB.
 S: 24 Castle View Drive
index 81d49b2bcaa2b52af67ccb8cb982ac811b89c6d7..4fc550e9101591a3209c229a42733ba6db254df0 100644 (file)
@@ -1,5 +1,5 @@
        Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
-       ====================================================================
+       =====================================================================
 
 This Kernel feature allows to invoke almost (for restrictions see below) every
 program by simply typing it's name in the shell.
@@ -47,15 +47,18 @@ A few examples (assumed you are in /proc/sys/fs/binfmt_misc):
 - enable Java(TM)-support (like binfmt_java):
   echo ":Java:M::\xca\xfe\xba\xbe::/usr/local/bin/java:" > register
   echo :Applet:M::\<\!--applet::/usr/local/bin/appletviewer: > register
+
 - enable support for em86 (like binfmt_em86, for Alpha AXP only):
   echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
   echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
+
 - enable support for packed DOS applications (pre-configured dosemu hdimages):
   echo ":DEXE:M::\x0eDEX::/usr/bin/dosexec:" > register
+
 - enable support for DOS/Windows executables (using mzloader and dosemu/wine):
   echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register
   echo ":DOS:E::com::/usr/sbin/mzloader:" > register
-
+  echo ":DOS2:E::exe::/usr/sbin/mzloader:" > register
 
 You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable)
 or 1 (to enable) to /proc/sys/fs/binfmt_misc/status or /proc/.../the_name.
@@ -68,13 +71,12 @@ or /proc/sys/fs/binfmt_misc/status.
 HINTS:
 ======
 
-If your interpreter does not look at the PATH to determine the full name of the
-program, you need to invoke a wrapper-script (like the following for java) first:
+If you want to pass special arguments to your interpreter, you can
+write a wrapper script for it.
 
-#!/bin/sh
-FOO=`which $1` || exit 1
-shift
-/usr/local/bin/java $FOO ${1+$@}
+Your interpreter should NOT look in the PATH for the filename; the
+kernel passes it the full filename to use.  Using the PATH can cause
+unexpected behaviour and be a security hazard.
 
 
 There is a web page about binfmt_misc at
index c119c6357b495f3cc175870b8df55bf7cc25b45b..c6b369e28a87de33c556916255ef043d029f4bc3 100644 (file)
@@ -1,9 +1,9 @@
 
-               Linux/m68k Amiga Bootstrap version 5.5
+               Linux/m68k Amiga Bootstrap version 5.6
                --------------------------------------
 
 Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
-Last revised: March 27, 1997
+Last revised: June 12, 1997
 
 
 0. Introduction
@@ -22,7 +22,7 @@ and the Installation Guide
 first. Although the Installation Guide is getting a bit outdated, it's still a
 good starting point.
 
-Amiboot 5.5 is meant for Linux/m68k 2.0.x, 2.1.x or higher (kernel bootinfo
+Amiboot 5.6 is meant for Linux/m68k 2.0.x, 2.1.x or higher (kernel bootinfo
 interface versions 1.x and 2.x). Please use an older version for older kernels.
 
 
index 937b9efe6839240f03cc429f80dab7a7bb1abcf8..7572cf7332d09bce0c7a2ba6608b88da794fcaaa 100644 (file)
@@ -1,6 +1,6 @@
 To use the amateur radio protocols within Linux you will need to get a
 suitable copy of the AX.25 Utilities. More detailed information about these
-and associated programs can be found on http://www.cs.nott.ac.uk/~jsn/.
+and associated programs can be found on http://zone.pspt.fi/~jsn/.
 
 For more information about the AX.25, NET/ROM and ROSE protocol stacks, see
 the AX25-HOWTO written by Terry Dawson <terry@perf.no.itg.telstra.com.au>
@@ -13,4 +13,4 @@ of the message, the subject field is ignored.
 
 Jonathan G4KLX
 
-jsn@cs.nott.ac.uk
+g4klx@g4klx.demon.co.uk
index 09681d565f6c09330fb5b93f24c778c77877054b..67f17e64419ef31be03e191cc0fa8fa8e780998b 100644 (file)
@@ -41,5 +41,4 @@ The contents of the Subject line are ignored.
 
 Jonathan
 
-jsn@cs.nott.ac.uk
 g4klx@g4klx.demon.co.uk
index 0c3c65d285098c9b740d99cf522422de8ecbc889..6b21f96df9b53c8bb0deb7f402d7c6e50b69387c 100644 (file)
@@ -83,6 +83,7 @@ CONFIG_INET=y
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
 
 #
 # (it is safe to leave these untouched)
@@ -194,20 +195,22 @@ CONFIG_DE4X5=y
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_DCACHE_PRELOAD is not set
+# CONFIG_OMIRR is not set
+# CONFIG_TRANS_NAMES is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
-CONFIG_NFS_FS=y
-# CONFIG_ROOT_NFS is not set
+# CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
 # CONFIG_SMB_FS is not set
-CONFIG_ISO9660_FS=y
+# CONFIG_ISO9660_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
@@ -245,3 +248,4 @@ CONFIG_PSMOUSE=y
 # Kernel hacking
 #
 # CONFIG_PROFILE is not set
+# CONFIG_MAGIC_SYSRQ is not set
index 3b3d8574b944ecb5878ca2aa0ede799f1f79a610..96ecca700bcd46b4d84929219d3f7e1d82853fb2 100644 (file)
@@ -295,7 +295,7 @@ asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long b
        retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
        if (retval)
                goto out;
-       retval = namei(NAM_FOLLOW_LINK, path, &inode);
+       retval = namei(path, &inode);
        if (retval)
                goto out;
        retval = -ENOSYS;
@@ -376,7 +376,7 @@ static int getdev(const char *name, int rdonly, struct inode **ino)
        struct file_operations *fops;
        int retval;
 
-       retval = namei(NAM_FOLLOW_LINK, name, &inode);
+       retval = namei(name, &inode);
        if (retval)
                return retval;
        if (!S_ISBLK(inode->i_mode)) {
@@ -876,6 +876,9 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
        return -EOPNOTSUPP;
 }
 
+/* Dummy functions for now */
+#define wrfpcr(x)      do { } while (0)
+#define rdfpcr()       0
 
 asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
                                        unsigned long nbytes,
index fd248746dc548b8557a99f2ffed259121b39a764..3fab47288c6d8788a0f8bea507bfd36278f4ef17 100644 (file)
@@ -195,11 +195,11 @@ CONFIG_EEXPRESS_PRO100=y
 # CONFIG_DCACHE_PRELOAD is not set
 # CONFIG_OMIRR is not set
 # CONFIG_TRANS_NAMES is not set
-CONFIG_MINIX_FS=y
+# CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
@@ -208,7 +208,7 @@ CONFIG_NFS_FS=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
-CONFIG_ISO9660_FS=y
+# CONFIG_ISO9660_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
index c6183993193d511bda4eaf06e886634b35936899..2e0f3e0843e19c5e4dffc6346543dae232582324 100644 (file)
@@ -208,7 +208,7 @@ static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
        math_error();
 }
 
-static struct irqaction irq13 = { math_error_irq, 0, 0, "math error", NULL, NULL };
+static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL };
 
 /*
  * IRQ2 is cascade interrupt to second interrupt controller
index f62744d11cd0388df24bb8dafc7068f86d04cec9..feebfed90953e2d82df5321d694a8a22018b8770 100644 (file)
@@ -219,7 +219,7 @@ __initfunc(void setup_arch(char **cmdline_p,
        request_region(0x40,0x20,"timer");
        request_region(0x80,0x10,"dma page reg");
        request_region(0xc0,0x20,"dma2");
-       request_region(0xf0,0x10,"npu");
+       request_region(0xf0,0x10,"fpu");
 }
 
 static const char * i486model(unsigned int nr)
index 15e424ea71f579a494a0f501263a81f143c64cc6..eb72970d7e5b21c3f66a4d6af37d0154901e4307 100644 (file)
@@ -1307,7 +1307,6 @@ static void ami_rebuild_copper(void);
         */
 
 extern unsigned short ami_intena_vals[];
-extern void amiga_init_sound(void);
 
        /*
         * Support for Graphics Boards
@@ -1810,11 +1809,6 @@ __initfunc(struct fb_info *amiga_fb_init(long *mem_start))
        int err, tag, i;
        u_long chipptr;
 
-       /*
-        * Our beloved beeper
-        */
-       amiga_init_sound();
-
        /*
         * Check for a Graphics Board
         */
index e360163062380120337015f92c8327379fb6c868..1571e1a0fe2c50e86af59f086aabce14d536bef2 100644 (file)
@@ -85,6 +85,7 @@ static void amiga_serial_console_write(const char *s, unsigned int count);
 static void amiga_debug_init(void);
 
 extern void amiga_video_setup(char *, int *);
+extern void amiga_init_sound(void);
 
 static struct console amiga_console_driver = {
     NULL, NULL, amiga_wait_key
@@ -799,14 +800,18 @@ void amiga_serial_gets(char *s, int len)
 
 __initfunc(static void amiga_debug_init(void))
 {
-    if (!strcmp( m68k_debug_device, "ser" )) {
-        /* no initialization required (?) */
-       amiga_console_driver.write = amiga_serial_console_write;
-    } else if (!strcmp( m68k_debug_device, "mem" )) {
-       amiga_savekmsg_init();
-       amiga_console_driver.write = amiga_mem_console_write;
-    }
-    register_console(&amiga_console_driver);
+       if (!strcmp( m68k_debug_device, "ser" )) {
+               /* no initialization required (?) */
+               amiga_console_driver.write = amiga_serial_console_write;
+       } else if (!strcmp( m68k_debug_device, "mem" )) {
+               amiga_savekmsg_init();
+               amiga_console_driver.write = amiga_mem_console_write;
+       }
+       register_console(&amiga_console_driver);
+
+       /* our beloved beeper */
+       if (AMIGAHW_PRESENT(AMI_AUDIO))
+               amiga_init_sound();
 }
 
 
index 31e2a460858aa5f12ffab9e2847fe9e0df3e340a..b7802a67c5661ca10041b9000bc42e8ea9842c1d 100644 (file)
@@ -671,7 +671,7 @@ Cyber_WaitQueue (0x8000);
  * Rectangle Fill Solid
  */
 void Cyber_RectFill (u_short x, u_short y, u_short width, u_short height,
-                     u_short mode, u_short color)
+                     u_short mode, u_short fcolor)
 {
 u_short blitcmd = S3_FILLEDRECT;
 
index d5d45be01e8fb4d2dc626de98baf5604950d18ed..e09743e791820d727aeab2b6136472e0c850a366 100644 (file)
@@ -419,7 +419,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
                     * break_flag...
                     * */
                    int keyval = plain_map[scancode], keytyp;
-
+                   
                    set_bit( scancode, broken_keys );
                    self_test_last_rcv = jiffies;
                    keyval = plain_map[scancode];
index b109466ed06f95e7d9446d7b380a5527864251a7..41ac75ada88c1165b255f36cc26b844e048ab6f9 100644 (file)
 #include <stdarg.h>
 #include <string.h>
 #include <sys/file.h>
-#include <sys/types.h>
 #include <unistd.h>
 
 /* required Linux/m68k include files */
+#define __KERNEL_STRICT_NAMES          /* This is ugly, I know */
+#define _LINUX_POSIX_TYPES_H
+#include <asm/posix_types.h>
 #include <linux/a.out.h>
 #include <linux/elf.h>
 #include <asm/amigahw.h>
index 23b7fa9d0a98553ccae6a35c916730b57947c358..74b873bf2a453aaedec6f535acbfa7b19aad2486 100644 (file)
  *  for more details.
  *
  *  History:
+ *     11 Jun 1997 Fix for unpadded gzipped ramdisks with bootinfo interface
+ *                 version 1.0
  *     27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo
  *                 interface version 1.0 (Geert)
- *     03 Feb 1997 Implemented kernel decompression (Geert, based on Roman's
+ *      3 Feb 1997 Implemented kernel decompression (Geert, based on Roman's
  *                 code for ataboot)
  *     30 Dec 1996 Reverted the CPU detection to the old scheme
  *                 New boot parameter override scheme (Geert)
@@ -55,7 +57,6 @@
 #include <stddef.h>
 #include <string.h>
 #include <errno.h>
-#include <sys/types.h>
 
 #include <linux/a.out.h>
 #include <linux/elf.h>
 #undef custom
 #define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR)))
 
+/* a.out linkage conventions */
+#undef SYMBOL_NAME_STR
+#define SYMBOL_NAME_STR(X) "_"#X
+
 /* temporary stack size */
 #define TEMP_STACKSIZE (256)
 
@@ -130,10 +135,9 @@ static int add_bi_record(u_short tag, u_short size, const void *data);
 static int add_bi_string(u_short tag, const u_char *s);
 static int check_bootinfo_version(const char *memptr);
 static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
-                        u_long start_mem, u_long mem_size, u_long rd_size,
-                        u_long kernel_size) __attribute__ ((noreturn));
+                        u_long start_mem, u_long kernel_size, u_long rd_dest,
+                        u_long rd_size) __attribute__ ((noreturn));
 asmlinkage u_long maprommed(void);
-asmlinkage u_long check346(void);
 #ifdef ZKERNEL
 static int load_zkernel(int fd);
 static int KRead(int fd, void *buf, int cnt);
@@ -682,7 +686,7 @@ u_long linuxboot(const struct linuxboot_args *args)
     if (debugflag) {
        if (bi.ramdisk.size)
            Printf("RAM disk at 0x%08lx, size is %ldK\n",
-                  (u_long)memptr+kernel_size, bi.ramdisk.size>>10);
+                  (u_long)memptr+kernel_size+bi_size, bi.ramdisk.size>>10);
 
        if (elf_kernel) {
            PutChar('\n');
@@ -703,11 +707,11 @@ u_long linuxboot(const struct linuxboot_args *args)
        Printf("\nKernel entry is 0x%08lx\n", elf_kernel ? kexec_elf.e_entry :
                                                           kexec.a_entry);
 
-       Printf("ramdisk dest top is 0x%08lx\n", start_mem+mem_size);
+       Printf("ramdisk dest is 0x%08lx\n", bi.ramdisk.addr);
        Printf("ramdisk lower limit is 0x%08lx\n",
-              (u_long)(memptr+kernel_size));
+              (u_long)memptr+kernel_size+bi_size);
        Printf("ramdisk src top is 0x%08lx\n",
-              (u_long)(memptr+kernel_size)+rd_size);
+              (u_long)memptr+kernel_size+bi_size+rd_size);
 
        Puts("\nType a key to continue the Linux/m68k boot...");
        GetChar();
@@ -743,7 +747,7 @@ u_long linuxboot(const struct linuxboot_args *args)
 
     /* execute the copy-and-go code (from CHIP RAM) */
     start_kernel(startfunc, (char *)stack+TEMP_STACKSIZE, memptr, start_mem,
-                mem_size, rd_size, kernel_size);
+                kernel_size, bi.ramdisk.addr, rd_size);
 
     /* Clean up and exit in case of a failure */
 Fail:
@@ -1065,6 +1069,7 @@ static int create_compat_bootinfo(void)
        compat_bootinfo.memory[i].size = bi.memory[i].size;
     }
     if (bi.ramdisk.size) {
+       bi.ramdisk.addr &= 0xfffffc00;
        compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
        compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
     } else {
@@ -1151,14 +1156,14 @@ static int check_bootinfo_version(const char *memptr)
      */
 
 static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
-                        u_long start_mem, u_long mem_size, u_long rd_size,
-                        u_long kernel_size)
+                        u_long start_mem, u_long kernel_size, u_long rd_dest,
+                        u_long rd_size)
 {
     register void (*a0)() __asm("a0") = startfunc;
     register char *a2 __asm("a2") = stackp;
     register char *a3 __asm("a3") = memptr;
     register u_long a4 __asm("a4") = start_mem;
-    register u_long d0 __asm("d0") = mem_size;
+    register u_long d0 __asm("d0") = rd_dest;
     register u_long d1 __asm("d1") = rd_size;
     register u_long d2 __asm("d2") = kernel_size;
     register u_long d3 __asm("d3") = bi_size;
@@ -1182,7 +1187,7 @@ static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
      *
      *     a3 = memptr
      *     a4 = start_mem
-     *     d0 = mem_size
+     *     d0 = rd_dest
      *     d1 = rd_size
      *     d2 = kernel_size
      *     d3 = bi_size
@@ -1210,18 +1215,16 @@ SYMBOL_NAME_STR(copyall) ":
        dbra    d7,1b           |     *dest++ = *src++
 
                                | /* copy the ramdisk to the top of memory */
-                               | /* (from back to front) */
-       movel   a4,a1           | dest = (u_long *)(start_mem+mem_size);
-       addl    d0,a1
-       movel   a3,a2           | limit = (u_long *)(memptr+kernel_size +
-       addl    d2,a2           |                    bi_size);
-       addl    d3,a2
-       movel   a2,a0           | src = (u_long *)((u_long)limit+rd_size);
-       addl    d1,a0
+       movel   a3,a0           | src = (u_long *)(memptr+kernel_size+bi_size);
+       addl    d2,a0
+       addl    d3,a0
+       movel   d0,a1           | dest = (u_long *)rd_dest;
+       movel   a0,a2           | limit = (u_long *)(memptr+kernel_size+
+       addl    d1,a2           |                    bi_size+rd_size);
 1:     cmpl    a0,a2
-       beqs    2f              | while (src > limit)
-       moveb   a0@-,a1@-       |     *--dest = *--src;
-       bras    1b
+       jeq     2f              | while (src > limit)
+       moveb   a0@+,a1@+       |     *dest++ = *src++;
+       jra     1b
 2:
                                | /* jump to start of kernel */
        movel   a4,a0           | jump_to (start_mem);
index df6a45a9d12331cdb0a57cc448c618548d5bf650..b963687aecb0a22c654daa25e60e7f993010f5db 100644 (file)
@@ -52,6 +52,10 @@ bool 'System V IPC' CONFIG_SYSVIPC
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+fi
+
 if [ "$CONFIG_AMIGA" = "y" ]; then
   bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
   bool 'Amiga OCS chipset support' CONFIG_AMIFB_OCS
@@ -153,6 +157,7 @@ if [ "$CONFIG_AMIGA" = "y" ]; then
     bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
     bool 'A4091 SCSI support' CONFIG_A4091_SCSI
     bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
+    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
   fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
@@ -273,5 +278,6 @@ bool 'Kernel profiling support' CONFIG_PROFILE
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 bool 'Remote debugging support' CONFIG_KGDB
 endmenu
index 62457c0cbaf2522a733e8a419dfa723cb33c3d18..5065e576958f88ba98792b80461bd9e5ece1e0fc 100644 (file)
@@ -97,7 +97,6 @@ extern int console_blanked;
 #undef CONFIG_FBCON_CYBER
 #undef CONFIG_FBCON_RETINAZ3
 
-
 /* Monochrome is default */
 
 #define CONFIG_FBCON_MONO
@@ -450,14 +449,17 @@ static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
                         int count, int yy, int xx);
 static void rev_char_cyber(struct display *p, int xx, int yy);
 
-extern void Cyber_WaitQueue(u_short fifo);
+extern void Cyber_WaitQueue(unsigned short fifo);
 extern void Cyber_WaitBlit(void);
-extern void Cyber_BitBLT(u_short curx, u_short cury, u_short destx,
-                         u_short desty, u_short width, u_short height,
-                         u_short mode);
-extern void Cyber_RectFill(u_short xx, u_short yy, u_short width, u_short height,
-                           u_short mode, u_short color);
-extern void Cyber_MoveCursor(u_short xx, u_short yy);
+extern void Cyber_BitBLT(unsigned short curx, unsigned short cury,
+                        unsigned short destx, unsigned short desty,
+                        unsigned short width, unsigned short height,
+                         unsigned short mode);
+extern void Cyber_RectFill(unsigned short xx, unsigned short yy,
+                          unsigned short width, unsigned short
+                          height, unsigned short mode,
+                          unsigned short fcolor); 
+extern void Cyber_MoveCursor(unsigned short xx, unsigned short yy);
 #endif /* CONFIG_FBCON_CYBER */
 
 #ifdef CONFIG_FBCON_RETINAZ3
@@ -3835,7 +3837,7 @@ static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy,
 
        c &= 0xff;
 
-       dest = p->screen_base+y*p->fontheight*p->next_line+8*x;
+       dest = p->screen_base + yy * p->fontheight * p->next_line + 8 * xx;
        cdat = p->fontdata+(c*p->fontheight);
        fg = disp->fgcol;
        bg = disp->bgcol;
@@ -3874,7 +3876,7 @@ static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
        u_char c, d;
        u_char fg, bg;
 
-       dest0 = p->screen_base+y*p->fontheight*p->next_line+8*x;
+       dest0 = p->screen_base + yy * p->fontheight * p->next_line + 8 * xx;
        fg = disp->fgcol;
        bg = disp->bgcol;
        revs = conp->vc_reverse;
@@ -3918,7 +3920,7 @@ static void rev_char_cyber(struct display *p, int xx, int yy)
        fg = disp->fgcol;
        bg = disp->bgcol;
 
-       dest = p->screen_base+y*p->fontheight*p->next_line+8*x;
+       dest = p->screen_base + yy * p->fontheight * p->next_line + 8 * xx;
    Cyber_WaitBlit();
        for (rows = p->fontheight; rows--; dest += p->next_line) {
                *dest = (*dest == fg) ? bg : fg;
index 65f71d5a9abd2e6cc2344ce4fea43eb142fb6975..18763c58bfbea96f07f016c17a00d3662591ec31 100644 (file)
@@ -152,6 +152,9 @@ CONFIG_NETDEVICES=y
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_DCACHE_PRELOAD is not set
+# CONFIG_OMIRR is not set
+# CONFIG_TRANS_NAMES is not set
 CONFIG_MINIX_FS=y
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=y
index 31608e904f604836e4f93bf75110b11d991a627f..204f4d3cc55e96c86ab79c7e42c89e49f5acac09 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
+#include <linux/console.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
@@ -164,9 +165,12 @@ extern void set_palette(void);
 void poke_blanked_console(void);
 void do_blank_screen(int);
 
+#if 0
+/* Make sure there are no references left to this variables.  */
 unsigned long  video_num_lines;
 unsigned long  video_num_columns;
 unsigned long  video_size_row;
+#endif
 
 static int printable = 0;                      /* Is console ready for printing? */
 unsigned long video_font_height;       /* Height of current screen font */
index dea7695e849f0406733db3b879d1109fe8794900..a135143b25c0bd788c0d9c940dbd1206e6ace0f1 100644 (file)
@@ -555,16 +555,18 @@ void cache_clear (unsigned long paddr, int len)
        int tmp;
 
        /*
-        * cwe need special treatment for the first page, in case it
-        * is not page-aligned.
+        * We need special treatment for the first page, in case it
+        * is not page-aligned. Page align the addresses to work
+        * around bug I17 in the 68060.
         */
        if ((tmp = -paddr & (PAGE_SIZE - 1))) {
-           pushcl040(paddr);
+           pushcl040(paddr & PAGE_MASK);
            if ((len -= tmp) <= 0)
                return;
            paddr += tmp;
        }
        tmp = PAGE_SIZE;
+       paddr &= PAGE_MASK;
        while ((len -= tmp) >= 0) {
            clear040(paddr);
            paddr += tmp;
@@ -600,6 +602,13 @@ void cache_push (unsigned long paddr, int len)
         * the '060!
         */
        len += paddr & (PAGE_SIZE - 1);
+
+       /*
+        * Work around bug I17 in the 68060 affecting some instruction
+        * lines not being invalidated properly.
+        */
+       paddr &= PAGE_MASK;
+
        do {
            pushcli040(paddr);
            paddr += tmp;
@@ -638,6 +647,13 @@ void cache_push_v (unsigned long vaddr, int len)
 
        /* on 68040, push cache lines for pages in the range */
        len += vaddr & (PAGE_SIZE - 1);
+
+       /*
+        * Work around bug I17 in the 68060 affecting some instruction
+        * lines not being invalidated properly.
+        */
+       vaddr &= PAGE_MASK;
+
        do {
            pushv040(vaddr);
            vaddr += tmp;
index 4266aa991ddb88d15f777a3c476cf1b9c5e70097..7eb56f4bf98eafcc6ba9633b1ff5e975846fdd21 100644 (file)
@@ -1,6 +1,4 @@
 #
-# $Id: Makefile,v 1.5 1997/06/16 00:34:01 ralf Exp $
-#
 # arch/mips/Makefile
 #
 # This file is included by the global makefile so that you can add your own
 # Copyright (C) 1994, 1995, 1996 by Ralf Baechle
 # DECStation modifications by Paul M. Antoine, 1996
 #
+# $Id: Makefile,v 1.7 1997/06/30 15:52:03 ralf Exp $
+#
 
+#
+# Select the object file format to substitute into the linker script.
+#
 ifdef CONFIG_CPU_LITTLE_ENDIAN
-CROSS_COMPILE  = mipsel-
+CROSS_COMPILE = mipsel-linux-
 ifdef CONFIG_MIPS_ECOFF
-oformat                = ecoff-littlemips
+oformat               = ecoff-littlemips
 else
-oformat                = a.out-mips-big-linux
+oformat               = elf32-littlemips
 endif
 else
-CROSS_COMPILE  = mips-
+CROSS_COMPILE = mips-linux-
 ifdef CONFIG_MIPS_ECOFF
-oformat                = ecoff-bigmips
+oformat               = ecoff-bigmips
 else
-oformat                = a.out-mips-big-linux
-endif
+oformat               = elf32-bigmips
 endif
-
-ifdef CONFIG_EXTRA_ELF_COMPILER
-CROSS_COMPILE  := $(CROSS_COMPILE)linuxelf-
-else
-CROSS_COMPILE  := $(CROSS_COMPILE)linux-
 endif
 
 LINKFLAGS      = -static -N
@@ -95,11 +92,6 @@ CORE_FILES    += arch/mips/algor/algor.o
 SUBDIRS       += arch/mips/algor
 #LOADADDR      += 0x80000000
 endif
-ifdef CONFIG_ACER_PICA_61
-CORE_FILES    += arch/mips/jazz/jazz.o
-SUBDIRS       += arch/mips/jazz
-LOADADDR      += 0x80000000
-endif
 ifdef CONFIG_DECSTATION
 CORE_FILES    += arch/mips/dec/dec.o
 SUBDIRS       += arch/mips/dec
@@ -116,17 +108,15 @@ CORE_FILES    += arch/mips/deskstation/deskstation.o
 SUBDIRS       += arch/mips/deskstation
 LOADADDR      += 0x80000000
 endif
-ifdef CONFIG_MIPS_MAGNUM_3000
-LOADADDR      += 0x80000000
-endif
-ifdef CONFIG_MIPS_MAGNUM_4000
+#
+# Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
+#
+ifdef CONFIG_MIPS_JAZZ
 CORE_FILES    += arch/mips/jazz/jazz.o
 SUBDIRS       += arch/mips/jazz
 LOADADDR      += 0x80000000
 endif
-ifdef CONFIG_OLIVETTI_M700
-CORE_FILES    += arch/mips/jazz/jazz.o
-SUBDIRS       += arch/mips/jazz
+ifdef CONFIG_MIPS_MAGNUM_3000
 LOADADDR      += 0x80000000
 endif
 ifdef CONFIG_SNI_RM200_PCI
index 33f54a301f992e4dda527bb4fd25c644ca23c869..9c6fb90739c051ba6d360d90dff5fa2bb772f178 100644 (file)
@@ -153,6 +153,9 @@ CONFIG_PCNET32=y
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_DCACHE_PRELOAD is not set
+# CONFIG_OMIRR is not set
+# CONFIG_TRANS_NAMES is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_FAT_FS is not set
index 92e13052282a1594dbc28bba3e9d6ec0662682f8..1503cc559ffe7916e34fa7e25fd1dc96e9f39645 100644 (file)
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bootinfo.h>
 #include <asm/types.h>
 
-#include "../../../drivers/char/kbd_kern.h"
-#include "../../../drivers/char/vt_kern.h"
-#include "../../../drivers/char/consolemap.h"
-#include "../../../drivers/char/selection.h"
-#include "../../../drivers/char/console_struct.h"
-
 extern void register_console(void (*proc)(const char *));
 extern void console_print(const char *);
 unsigned video_res_x;
index 255ec222863585b1985d9a51f17bbd9ef5a1da1f..452e419e3bae5bd6a1ecbfb62823614144852a6b 100644 (file)
@@ -11,6 +11,8 @@
  *  Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
  *
  *  Copyright (C) 1995 Andreas Busse
+ *
+ * $Id: gdb-stub.c,v 1.4 1997/06/30 15:52:25 ralf Exp $
  */
 
 /*
@@ -328,7 +330,7 @@ void set_debug_traps(void)
        unsigned long flags;
        unsigned char c;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
                set_except_vector(ht->tt, trap_low);
   
index 27c700a95c2a0c200e487cde5d9f84077596f750..3251c89d9bec19ed965e815ebe25c9f8b10a508e 100644 (file)
@@ -347,6 +347,8 @@ probe_done:
 
        jal     prom_init /* prom_init(argc, argv, envp); */
         nop
+       jal     sgi_sysinit
+        nop
 #endif
        /* Get the very one tags we need early in the boot process */
        nop
@@ -405,7 +407,6 @@ probe_done:
        mfc0    t0, CP0_STATUS
        li      t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX)
        and     t0, t1
-       li      t1, ST0_CU0
        or      t0, ST0_CU0
        mtc0    t0, CP0_STATUS
 
index d994155d05b1f191eda5997285eab0d947d3f42d..fc0d542fc154fffbd4a3a61eef818ad16ccd0aab 100644 (file)
@@ -465,7 +465,7 @@ static inline int look_for_irix_interpreter(char **name,
                        goto losing;
 
                old_fs = get_fs(); set_fs(get_ds());
-               retval = namei(*name, interpreter_inode);
+               retval = namei(NAM_FOLLOW_LINK, *name, interpreter_inode);
                set_fs(old_fs);
                if(retval < 0)
                        goto losing;
@@ -973,6 +973,7 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt)
  */
 static int dump_write(struct file *file, const void *addr, int nr)
 {
+       file->f_inode->i_status |= ST_MODIFIED;
        return file->f_op->write(file->f_inode, file, addr, nr) == nr;
 }
 
index 0896ed1c7e749e0d7b6dddf7e0e93e17c54fad85..89631b41614f0b944fa19abda71c2462a4d4fd70 100644 (file)
@@ -10,6 +10,8 @@
  * should be easier.
  *
  * Mips support by Ralf Baechle and Andreas Busse
+ *
+ * $Id: irq.c,v 1.6 1997/06/30 15:52:34 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -78,8 +80,7 @@ void disable_irq(unsigned int irq_nr)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
        mask_irq(irq_nr);
        restore_flags(flags);
 }
@@ -87,8 +88,7 @@ void disable_irq(unsigned int irq_nr)
 void enable_irq(unsigned int irq_nr)
 {
        unsigned long flags;
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
        unmask_irq(irq_nr);
        restore_flags(flags);
 }
@@ -226,8 +226,7 @@ int setup_x86_irq(int irq, struct irqaction * new)
        if (new->flags & SA_SAMPLE_RANDOM)
                rand_initialize_irq(irq);
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
        *p = new;
 
        if (!shared) {
@@ -287,8 +286,7 @@ void free_irq(unsigned int irq, void *dev_id)
                        continue;
 
                /* Found it - now free it */
-               save_flags(flags);
-               cli();
+               save_and_cli(flags);
                *p = action->next;
                if (!irq[irq_action]) {
                        mask_irq(irq);
index 2cea754077e994e78747f020915e15f906d6d062..c2a0453c4faa40d865a5e9ccbb880247ce70c683 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: r2300_fpu.S,v 1.1 1997/06/06 09:32:55 ralf Exp $
+/*
  * r2300_fpu.S: Save/restore floating point context for signal handlers.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,12 +9,14 @@
  *
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: r2300_fpu.S,v 1.2 1997/06/25 16:57:15 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
+#include <asm/offset.h>
 #include <asm/regdef.h>
-#include <asm/sigcontext.h>
 
        .set    mips3
        .set    noreorder
index 1bc4538dbdcc7c7a9c0dc9f7be177ddc2fe35ff2..b020266d175a154180236b19c0c0491fc65f1b2a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: r4k_fpu.S,v 1.1 1997/06/06 09:33:04 ralf Exp $
+/*
  * r4k_fpu.S: Save/restore floating point context for signal handlers.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,12 +9,14 @@
  *
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: r4k_fpu.S,v 1.2 1997/06/25 16:57:18 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
+#include <asm/offset.h>
 #include <asm/regdef.h>
-#include <asm/sigcontext.h>
 
        .set    noreorder
        .set    mips3
index 215e05027af195a87b7c4c06b254c3463fce1de7..6fb8f122eb55e9b2b8e299f28d290a258aa38b0b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: r6000_fpu.S,v 1.1 1997/06/06 09:33:14 ralf Exp $
+/*
  * r6000_fpu.S: Save/restore floating point context for signal handlers.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,12 +9,14 @@
  *
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: r6000_fpu.S,v 1.2 1997/06/25 16:57:19 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
+#include <asm/offset.h>
 #include <asm/regdef.h>
-#include <asm/sigcontext.h>
 
        .set    noreorder
        /* Save floating point context */
index 4f975af1ae25947d0a1392fcf837fc75d83ff5b8..8c6cde991b30ab9b4c8ecec43945731a0fee871c 100644 (file)
@@ -3,6 +3,8 @@
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1994, 1995, 1996  Ralf Baechle
+ *
+ * $Id: signal.c,v 1.7 1997/06/25 19:25:08 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/sched.h>
@@ -69,24 +71,36 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
            (regs->regs[29] & (SZREG - 1)))
                goto badframe;
 
-       current->blocked = context->sc_sigset & _BLOCKABLE;
-       regs->cp0_epc = context->sc_pc;
+       current->blocked = context->sc_sigset & _BLOCKABLE; /* XXX */
+       regs->cp0_epc = context->sc_pc; /* XXX */
 
+/*
+ * Disabled because we only use the lower 32 bit of the registers.
+ */
+#if 0
        /*
         * We only allow user processes in 64bit mode (n32, 64 bit ABI) to
         * restore the upper half of registers.
         */
-       if (read_32bit_cp0_register(CP0_STATUS) & ST0_UX)
+       if (read_32bit_cp0_register(CP0_STATUS) & ST0_UX) {
                for(i = 31;i >= 0;i--)
                        __get_user(regs->regs[i], &context->sc_regs[i]);
-       else
+               __get_user(regs->hi, &context->sc_mdhi);
+               __get_user(regs->lo, &context->sc_mdlo);
+       } else
+#endif
+       {
+               long long reg;
                for(i = 31;i >= 0;i--) {
-                       __get_user(regs->regs[i], &context->sc_regs[i]);
-                       regs->regs[i] = (int) regs->regs[i];
+                       __get_user(reg, &context->sc_regs[i]);
+                       regs->regs[i] = (int) reg;
                }
+               __get_user(reg, &context->sc_mdhi);
+               regs->hi = (int) reg;
+               __get_user(reg, &context->sc_mdlo);
+               regs->lo = (int) reg;
+       }
 
-       __get_user(regs->hi, &context->sc_mdhi);
-       __get_user(regs->lo, &context->sc_mdlo);
        restore_fp_context(context);
 
        /*
index 60f58297d982807bb4a933e999a837454d1f32ca..c448ce99eee7d2af3f527af60ac01cca33b6fb65 100644 (file)
@@ -6,6 +6,8 @@
  * for more details.
  *
  * Copyright (C) 1995, 1996 by Ralf Baechle
+ *
+ * $Id: syscalls.h,v 1.5 1997/06/25 17:08:35 ralf Exp $
  */
 
 /*
@@ -174,7 +176,6 @@ SYS(sys_mlock, 2)
 SYS(sys_munlock, 2)                            /* 4155 */
 SYS(sys_mlockall, 1)
 SYS(sys_munlockall, 0)
-SYS(sys_nfsservctl, 3)
 SYS(sys_sched_setparam,2)
 SYS(sys_sched_getparam,2)
 SYS(sys_sched_setscheduler,3)                  /* 4160 */
index 671eb5f730286b4f289cf45411065097abdc0cf2..2e8363f41460dd8829304a21f74ba6716ea20a75 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.1 1997/06/06 09:33:25 ralf Exp $
+/* $Id: sysirix.c,v 1.2 1997/06/17 15:24:26 ralf Exp $
  * sysirix.c: IRIX system call emulation.
  *
  * Copyright (C) 1996 David S. Miller
@@ -664,7 +664,7 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
        error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
        if (error)
                goto out;
-       error = namei(path,&inode);
+       error = namei(NAM_FOLLOW_LINK, path, &inode);
        if (error)
                goto out;
        if (!inode->i_sb->s_op->statfs) {
@@ -1390,7 +1390,7 @@ asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
        error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
        if(error)
                goto out;
-       error = namei(fname, &inode);
+       error = namei(NAM_FOLLOW_LINK, fname, &inode);
        if(error)
                goto out;
        if(!inode->i_sb->s_op->statfs) {
@@ -1489,8 +1489,8 @@ out:
        return error;
 }
 
-#define NOFOLLOW_LINKS  0
-#define FOLLOW_LINKS    1
+#define NOFOLLOW_LINKS  NAM_FOLLOW_TRAILSLASH
+#define FOLLOW_LINKS    NAM_FOLLOW_LINK
 
 static inline int chown_common(char *filename, uid_t user, gid_t group, int follow)
 {
@@ -1498,10 +1498,7 @@ static inline int chown_common(char *filename, uid_t user, gid_t group, int foll
        int error;
        struct iattr newattrs;
 
-       if(follow == NOFOLLOW_LINKS)
-               error = lnamei(filename,&inode);
-       else
-               error = namei(filename,&inode);
+       error = namei(follow, filename,&inode);
        if (error)
                return error;
        if (IS_RDONLY(inode)) {
@@ -1734,7 +1731,7 @@ asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
        error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
        if(error)
                goto out;
-       error = namei(fname, &inode);
+       error = namei(NAM_FOLLOW_LINK, fname, &inode);
        if(error)
                goto out;
        if(!inode->i_sb->s_op->statfs) {
index c5e394d565f9e142ecce7a362957d07d2ce81a1b..32dce029d2e55f27ed61109686408a216b8bcafd 100644 (file)
@@ -5,7 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: sysmips.c,v 1.4 1997/06/30 15:52:37 ralf Exp $
  */
 #include <linux/errno.h>
 #include <linux/linkage.h>
@@ -79,8 +81,7 @@ sys_sysmips(int cmd, int arg1, int arg2, int arg3)
                retval = verify_area(VERIFY_WRITE, p, sizeof(*p));
                if (retval)
                        goto out;
-               save_flags(flags);
-               cli();
+               save_and_cli(flags);
                retval = *p;
                *p = arg2;
                restore_flags(flags);
index fd57f6d0ec8252a2bedaee94d1a41daef922971e..e00ebc76d1b3d7ef008702a57378e9f61da1a00d 100644 (file)
@@ -5,6 +5,8 @@
  *
  * This file contains the time handling details for PC-style clocks as
  * found in some MIPS systems.
+ *
+ * $Id: time.c,v 1.4 1997/06/30 15:52:40 ralf Exp $
  */
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -134,8 +136,7 @@ void do_gettimeofday(struct timeval *tv)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
        *tv = xtime;
        tv->tv_usec += do_gettimeoffset();
 
index ee48f659a91d3ee435057b9216331d4e1870e228..208c0c3cc81eca01f35830be8711a0f37331a731 100644 (file)
  *             modify it under the terms of the GNU General Public License
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
+ *
+ * $Id: checksum.c,v 1.4 1997/07/03 09:43:16 ralf Exp $
  */
 #include <net/checksum.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
 #include <asm/string.h>
 #include <asm/uaccess.h>
 
@@ -36,7 +40,7 @@ static inline unsigned long do_csum(const unsigned char * buff, int len)
                goto out;
        odd = 1 & (unsigned long) buff;
        if (odd) {
-               result = *buff;
+               result = be16_to_cpu(*buff);
                len--;
                buff++;
        }
@@ -68,7 +72,7 @@ static inline unsigned long do_csum(const unsigned char * buff, int len)
                }
        }
        if (len & 1)
-               result += (*buff << 8);
+               result += le16_to_cpu(*buff);
        result = from32to16(result);
        if (odd)
                result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
index 276674c68ed102905fc983eb41991964234371b9..bbf8fbe1a474611fcffc90ca2f44f71c358b9e65 100644 (file)
@@ -1,7 +1,9 @@
-/* $Id: r2300.c,v 1.1 1997/06/06 09:35:14 ralf Exp $
+/*
  * r2300.c: R2000 and R3000 specific mmu/cache code.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: r2300.c,v 1.2 1997/06/30 15:52:51 ralf Exp $
  */
 
 #include <linux/kernel.h>
@@ -126,7 +128,7 @@ static inline void r2300_flush_tlb_all(void)
        unsigned long flags;
        int entry;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        write_32bit_cp0_register(CP0_ENTRYLO0, 0);
        for(entry = 0; entry < mips_tlb_entries; entry++) {
                write_32bit_cp0_register(CP0_INDEX, entry);
@@ -160,7 +162,7 @@ static void r2300_load_pgd(unsigned long pg_dir)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        write_32bit_cp0_register(CP0_ENTRYHI, TLB_ROOT);
        write_32bit_cp0_register(CP0_INDEX, 0);
        write_32bit_cp0_register(CP0_ENTRYLO0, ((pg_dir >> 6) | 0x00e0));
index 974343069adab65dbca9683e351140ef498023a9..c4eb3cd82d799355bd1d1d446fbba3974a826373 100644 (file)
@@ -2,6 +2,8 @@
  * r4xx0.c: R4000 processor variant specific MMU/Cache routines.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: r4xx0.c,v 1.4 1997/06/30 15:52:53 ralf Exp $
  */
 #include <linux/config.h>
 
@@ -101,6 +103,69 @@ static void r4k_clear_page_d32(unsigned long page)
 }
 
 
+/*
+ * This flavour of r4k_clear_page is for the R4600 V1.x.  Cite from the
+ * IDT R4600 V1.7 errata:
+ *
+ *  18. The CACHE instructions Hit_Writeback_Invalidate_D, Hit_Writeback_D,
+ *      Hit_Invalidate_D and Create_Dirty_Exclusive_D should only be
+ *      executed if there is no other dcache activity. If the dcache is
+ *      accessed for another instruction immeidately preceding when these
+ *      cache instructions are executing, it is possible that the dcache 
+ *      tag match outputs used by these cache instructions will be 
+ *      incorrect. These cache instructions should be preceded by at least
+ *      four instructions that are not any kind of load or store 
+ *      instruction.
+ *
+ *      This is not allowed:    lw
+ *                              nop
+ *                              nop
+ *                              nop
+ *                              cache       Hit_Writeback_Invalidate_D
+ *
+ *      This is allowed:        lw
+ *                              nop
+ *                              nop
+ *                              nop
+ *                              nop
+ *                              cache       Hit_Writeback_Invalidate_D
+ */
+static void r4k_clear_page_r4600_v1(unsigned long page)
+{
+       __asm__ __volatile__(
+               ".set\tnoreorder\n\t"
+               ".set\tnoat\n\t"
+               ".set\tmips3\n\t"
+               "daddiu\t$1,%0,%2\n"
+               "1:\tnop\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "cache\t%3,(%0)\n\t"
+               "sd\t$0,(%0)\n\t"
+               "sd\t$0,8(%0)\n\t"
+               "sd\t$0,16(%0)\n\t"
+               "sd\t$0,24(%0)\n\t"
+               "daddiu\t%0,64\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "cache\t%3,-32(%0)\n\t"
+               "sd\t$0,-32(%0)\n\t"
+               "sd\t$0,-24(%0)\n\t"
+               "sd\t$0,-16(%0)\n\t"
+               "bne\t$1,%0,1b\n\t"
+               "sd\t$0,-8(%0)\n\t"
+               ".set\tmips0\n\t"
+               ".set\tat\n\t"
+               ".set\treorder"
+               :"=r" (page)
+               :"0" (page),
+                "I" (PAGE_SIZE),
+                "i" (Create_Dirty_Excl_D)
+               :"$1","memory");
+}
+
 /*
  * This is still inefficient.  We only can do better if we know the
  * virtual address where the copy will be accessed.
@@ -222,6 +287,74 @@ static void r4k_copy_page_d32(unsigned long to, unsigned long from)
                 "i" (Create_Dirty_Excl_D));
 }
 
+/*
+ * Again a special version for the R4600 V1.x
+ */
+static void r4k_copy_page_r4600_v1(unsigned long to, unsigned long from)
+{
+       unsigned long dummy1, dummy2;
+       unsigned long reg1, reg2, reg3, reg4;
+
+       __asm__ __volatile__(
+               ".set\tnoreorder\n\t"
+               ".set\tnoat\n\t"
+               ".set\tmips3\n\t"
+               "daddiu\t$1,%0,%8\n"
+               "1:\tnop\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "\tcache\t%9,(%0)\n\t"
+               "lw\t%2,(%1)\n\t"
+               "lw\t%3,4(%1)\n\t"
+               "lw\t%4,8(%1)\n\t"
+               "lw\t%5,12(%1)\n\t"
+               "sw\t%2,(%0)\n\t"
+               "sw\t%3,4(%0)\n\t"
+               "sw\t%4,8(%0)\n\t"
+               "sw\t%5,12(%0)\n\t"
+               "lw\t%2,16(%1)\n\t"
+               "lw\t%3,20(%1)\n\t"
+               "lw\t%4,24(%1)\n\t"
+               "lw\t%5,28(%1)\n\t"
+               "sw\t%2,16(%0)\n\t"
+               "sw\t%3,20(%0)\n\t"
+               "sw\t%4,24(%0)\n\t"
+               "sw\t%5,28(%0)\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "cache\t%9,32(%0)\n\t"
+               "daddiu\t%0,64\n\t"
+               "daddiu\t%1,64\n\t"
+               "lw\t%2,-32(%1)\n\t"
+               "lw\t%3,-28(%1)\n\t"
+               "lw\t%4,-24(%1)\n\t"
+               "lw\t%5,-20(%1)\n\t"
+               "sw\t%2,-32(%0)\n\t"
+               "sw\t%3,-28(%0)\n\t"
+               "sw\t%4,-24(%0)\n\t"
+               "sw\t%5,-20(%0)\n\t"
+               "lw\t%2,-16(%1)\n\t"
+               "lw\t%3,-12(%1)\n\t"
+               "lw\t%4,-8(%1)\n\t"
+               "lw\t%5,-4(%1)\n\t"
+               "sw\t%2,-16(%0)\n\t"
+               "sw\t%3,-12(%0)\n\t"
+               "sw\t%4,-8(%0)\n\t"
+               "bne\t$1,%0,1b\n\t"
+               "sw\t%5,-4(%0)\n\t"
+               ".set\tmips0\n\t"
+               ".set\tat\n\t"
+               ".set\treorder"
+               :"=r" (dummy1), "=r" (dummy2),
+                "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4)
+               :"0" (to), "1" (from),
+                "I" (PAGE_SIZE),
+                "i" (Create_Dirty_Excl_D));
+}
+
 /*
  * If you think for one second that this stuff coming up is a lot
  * of bulky code eating too many kernel cache lines.  Think _again_.
@@ -239,7 +372,7 @@ static inline void r4k_flush_cache_all_s16d16i16(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache16(); blast_icache16(); blast_scache16();
        restore_flags(flags);
 }
@@ -248,7 +381,7 @@ static inline void r4k_flush_cache_all_s32d16i16(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache16(); blast_icache16(); blast_scache32();
        restore_flags(flags);
 }
@@ -257,7 +390,7 @@ static inline void r4k_flush_cache_all_s64d16i16(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache16(); blast_icache16(); blast_scache64();
        restore_flags(flags);
 }
@@ -266,7 +399,7 @@ static inline void r4k_flush_cache_all_s128d16i16(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache16(); blast_icache16(); blast_scache128();
        restore_flags(flags);
 }
@@ -275,7 +408,7 @@ static inline void r4k_flush_cache_all_s16d32i32(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache32(); blast_icache32(); blast_scache16();
        restore_flags(flags);
 }
@@ -284,7 +417,7 @@ static inline void r4k_flush_cache_all_s32d32i32(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache32(); blast_icache32(); blast_scache32();
        restore_flags(flags);
 }
@@ -293,7 +426,7 @@ static inline void r4k_flush_cache_all_s64d32i32(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache32(); blast_icache32(); blast_scache64();
        restore_flags(flags);
 }
@@ -302,7 +435,7 @@ static inline void r4k_flush_cache_all_s128d32i32(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache32(); blast_icache32(); blast_scache128();
        restore_flags(flags);
 }
@@ -311,7 +444,7 @@ static inline void r4k_flush_cache_all_d16i16(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache16(); blast_icache16();
        restore_flags(flags);
 }
@@ -320,7 +453,7 @@ static inline void r4k_flush_cache_all_d32i32(void)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        blast_dcache32(); blast_icache32();
        restore_flags(flags);
 }
@@ -350,7 +483,7 @@ r4k_flush_cache_range_s16d16i16(struct mm_struct *mm,
                        pte_t *pte;
                        int text;
 
-                       save_flags(flags); cli();
+                       save_and_cli(flags);
                        text = vma->vm_flags & VM_EXEC;
                        while(start < end) {
                                pgd = pgd_offset(mm, start);
@@ -395,7 +528,7 @@ r4k_flush_cache_range_s32d16i16(struct mm_struct *mm,
                        pte_t *pte;
                        int text;
 
-                       save_flags(flags); cli();
+                       save_and_cli(flags);
                        text = vma->vm_flags & VM_EXEC;
                        while(start < end) {
                                pgd = pgd_offset(mm, start);
@@ -439,7 +572,7 @@ static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm,
                        pte_t *pte;
                        int text;
 
-                       save_flags(flags); cli();
+                       save_and_cli(flags);
                        text = vma->vm_flags & VM_EXEC;
                        while(start < end) {
                                pgd = pgd_offset(mm, start);
@@ -483,7 +616,7 @@ static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm,
                        pte_t *pte;
                        int text;
 
-                       save_flags(flags); cli();
+                       save_and_cli(flags);
                        text = vma->vm_flags & VM_EXEC;
                        while(start < end) {
                                pgd = pgd_offset(mm, start);
@@ -527,7 +660,7 @@ static void r4k_flush_cache_range_s16d32i32(struct mm_struct *mm,
                        pte_t *pte;
                        int text;
 
-                       save_flags(flags); cli();
+                       save_and_cli(flags);
                        text = vma->vm_flags & VM_EXEC;
                        while(start < end) {
                                pgd = pgd_offset(mm, start);
@@ -571,7 +704,7 @@ static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm,
                        pte_t *pte;
                        int text;
 
-                       save_flags(flags); cli();
+                       save_and_cli(flags);
                        text = vma->vm_flags & VM_EXEC;
                        while(start < end) {
                                pgd = pgd_offset(mm, start);
@@ -615,7 +748,7 @@ static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm,
                        pte_t *pte;
                        int text;
 
-                       save_flags(flags); cli();
+                       save_and_cli(flags);
                        text = vma->vm_flags & VM_EXEC;
                        while(start < end) {
                                pgd = pgd_offset(mm, start);
@@ -659,7 +792,7 @@ static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm,
                        pte_t *pte;
                        int text;
 
-                       save_flags(flags); cli();
+                       save_and_cli(flags);
                        text = vma->vm_flags & VM_EXEC;
                        while(start < end) {
                                pgd = pgd_offset(mm, start);
@@ -689,7 +822,7 @@ static void r4k_flush_cache_range_d16i16(struct mm_struct *mm,
 #ifdef DEBUG_CACHE
                printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache16(); blast_icache16();
                restore_flags(flags);
        }
@@ -705,7 +838,7 @@ static void r4k_flush_cache_range_d32i32(struct mm_struct *mm,
 #ifdef DEBUG_CACHE
                printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache32(); blast_icache32();
                restore_flags(flags);
        }
@@ -836,7 +969,7 @@ static void r4k_flush_cache_page_s16d16i16(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -894,7 +1027,7 @@ static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -951,7 +1084,7 @@ static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -1009,7 +1142,7 @@ static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -1068,7 +1201,7 @@ static void r4k_flush_cache_page_s16d32i32(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -1126,7 +1259,7 @@ static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -1186,7 +1319,7 @@ static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -1246,7 +1379,7 @@ static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -1303,7 +1436,7 @@ static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -1362,7 +1495,7 @@ static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -1420,7 +1553,7 @@ static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma,
 #ifdef DEBUG_CACHE
        printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-       save_flags(flags); cli();
+       save_and_cli(flags);
        page &= PAGE_MASK;
        pgdp = pgd_offset(mm, page);
        pmdp = pmd_offset(pgdp, page);
@@ -1478,7 +1611,7 @@ static void r4k_flush_page_to_ram_s16d16i16(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache16_page(page);
                blast_scache16_page(page);
                restore_flags(flags);
@@ -1494,7 +1627,7 @@ static void r4k_flush_page_to_ram_s32d16i16(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache16_page(page);
                blast_scache32_page(page);
                restore_flags(flags);
@@ -1510,7 +1643,7 @@ static void r4k_flush_page_to_ram_s64d16i16(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache16_page(page);
                blast_scache64_page(page);
                restore_flags(flags);
@@ -1526,7 +1659,7 @@ static void r4k_flush_page_to_ram_s128d16i16(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache16_page(page);
                blast_scache128_page(page);
                restore_flags(flags);
@@ -1542,7 +1675,7 @@ static void r4k_flush_page_to_ram_s16d32i32(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache32_page(page);
                blast_scache16_page(page);
                restore_flags(flags);
@@ -1558,7 +1691,7 @@ static void r4k_flush_page_to_ram_s32d32i32(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache32_page(page);
                blast_scache32_page(page);
                restore_flags(flags);
@@ -1574,7 +1707,7 @@ static void r4k_flush_page_to_ram_s64d32i32(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache32_page(page);
                blast_scache64_page(page);
                restore_flags(flags);
@@ -1590,7 +1723,7 @@ static void r4k_flush_page_to_ram_s128d32i32(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache32_page(page);
                blast_scache128_page(page);
                restore_flags(flags);
@@ -1606,7 +1739,7 @@ static void r4k_flush_page_to_ram_d16i16(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache16_page(page);
                restore_flags(flags);
        }
@@ -1621,7 +1754,7 @@ static void r4k_flush_page_to_ram_d32i32(unsigned long page)
 #ifdef DEBUG_CACHE
                printk("cram[%08lx]", page);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache32_page(page);
                restore_flags(flags);
        }
@@ -1651,7 +1784,7 @@ static void r4k_flush_page_to_ram_d32i32_r4600(unsigned long page)
                 */
                *(volatile unsigned long *)KSEG1;
 
-               save_flags(flags); cli();
+               save_and_cli(flags);
                blast_dcache32_page(page);
                blast_dcache32_page(page ^ 0x2000);
 #ifdef CONFIG_SGI
@@ -1678,21 +1811,21 @@ static void r4k_flush_page_to_ram_d32i32_r4600(unsigned long page)
                        daddu   %0, 32
                        mtc0    $0, $12
                        nop; nop; nop; nop;
-                       mtc0    %3, $12
-                       nop; nop; nop; nop;
                        .set mips0
                        .set reorder"
                        : "=&r" (tmp1), "=&r" (tmp2),
-                         "=&r" (page), "=&r" (flags)
-                       : "2" (page & 0x0007f000), "3" (flags));
+                         "=&r" (page)
+                       : "2" (page & 0x0007f000));
                }
 #endif /* CONFIG_SGI */
+               restore_flags(flags);
        }
 }
 
 static void r4k_flush_cache_sigtramp(unsigned long addr)
 {
        addr &= ~(dc_lsize - 1);
+       __asm__ __volatile__("nop;nop;nop;nop");
        flush_dcache_line(addr);
        flush_dcache_line(addr + dc_lsize);
        flush_icache_line(addr);
@@ -1715,7 +1848,7 @@ static inline void r4k_flush_tlb_all(void)
        printk("[tlball]");
 #endif
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        /* Save old context and create impossible VPN2 value */
        old_ctx = (get_entryhi() & 0xff);
        set_entryhi(KSEG0);
@@ -1746,7 +1879,7 @@ static void r4k_flush_tlb_mm(struct mm_struct *mm)
 #ifdef DEBUG_TLB
                printk("[tlbmm<%d>]", mm->context);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                get_new_mmu_context(mm, asid_cache);
                if(mm == current->mm)
                        set_entryhi(mm->context & 0xff);
@@ -1765,7 +1898,7 @@ static void r4k_flush_tlb_range(struct mm_struct *mm, unsigned long start,
                printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff),
                       start, end);
 #endif
-               save_flags(flags); cli();
+               save_and_cli(flags);
                size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
                size = (size + 1) >> 1;
                if(size <= NTLB_ENTRIES_HALF) {
@@ -1814,7 +1947,7 @@ static void r4k_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 #endif
                newpid = (vma->vm_mm->context & 0xff);
                page &= (PAGE_MASK << 1);
-               save_flags(flags); cli();
+               save_and_cli(flags);
                oldpid = (get_entryhi() & 0xff);
                set_entryhi(page | newpid);
                BARRIER;
@@ -1886,7 +2019,7 @@ static void r4k_update_mmu_cache(struct vm_area_struct * vma,
        }
 #endif
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        address &= (PAGE_MASK << 1);
        set_entryhi(address | (pid));
        pgdp = pgd_offset(vma->vm_mm, address);
@@ -1945,7 +2078,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma,
        pte_t *ptep;
        int idx;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        address &= (PAGE_MASK << 1);
        set_entryhi(address | (get_entryhi() & 0xff));
        pgdp = pgd_offset(vma->vm_mm, address);
@@ -2112,16 +2245,16 @@ static int probe_scache_eeprom(unsigned long config)
                        __asm__ __volatile__("
                        .set noreorder
                        .set mips3
-                       li      %0, 0x1
-                       dsll    %0, 31
-                       lui     %1, 0x9000
-                       dsll32  %1, 0
-                       or      %0, %1, %0
                        mfc0    %2, $12
                        nop; nop; nop; nop;
                        li      %1, 0x80
                        mtc0    %1, $12
                        nop; nop; nop; nop;
+                       li      %0, 0x1
+                       dsll    %0, 31
+                       lui     %1, 0x9000
+                       dsll32  %1, 0
+                       or      %0, %1, %0
                        sb      $0, 0(%0)
                        mtc0    $0, $12
                        nop; nop; nop; nop;
@@ -2189,7 +2322,7 @@ static int probe_scache(unsigned long config)
        /* This is such a bitch, you'd think they would make it
         * easy to do this.  Away you daemons of stupidity!
         */
-       save_flags(flags); cli();
+       save_and_cli(flags);
 
        /* Fill each size-multiple cache line with a valid tag. */
        pow2 = (64 * 1024);
@@ -2254,8 +2387,13 @@ static void setup_noscache_funcs(void)
                flush_page_to_ram = r4k_flush_page_to_ram_d16i16;
                break;
        case 32:
-               clear_page = r4k_clear_page_d32;
-               copy_page = r4k_copy_page_d32;
+               if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2010) {
+                       clear_page = r4k_clear_page_r4600_v1;
+                       copy_page = r4k_copy_page_r4600_v1;
+               } else {
+                       clear_page = r4k_clear_page_d32;
+                       copy_page = r4k_copy_page_d32;
+               }
                flush_cache_all = r4k_flush_cache_all_d32i32;
                flush_cache_mm = r4k_flush_cache_mm_d32i32;
                flush_cache_range = r4k_flush_cache_range_d32i32;
index 9f73cc58d3f20e47ee525875886128a2e405cf70..92b1cf0e44b4a3217ab2fee949ffa52153ef34b3 100644 (file)
@@ -1,8 +1,10 @@
-/* $Id: indy_int.c,v 1.1 1997/06/06 09:36:21 ralf Exp $
+/*
  * indy_int.c: Routines for generic manipulation of the INT[23] ASIC
  *             found on INDY workstations..
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: indy_int.c,v 1.2 1997/06/30 15:53:01 ralf Exp $
  */
 #include <linux/config.h>
 
@@ -67,8 +69,7 @@ void disable_local_irq(unsigned int irq_nr)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
        switch(irq_nr) {
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
                ioc_icontrol->imask0 &= ~(1 << irq_nr);
@@ -95,8 +96,7 @@ void disable_local_irq(unsigned int irq_nr)
 void enable_local_irq(unsigned int irq_nr)
 {
        unsigned long flags;
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
        switch(irq_nr) {
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
                ioc_icontrol->imask0 |= (1 << irq_nr);
@@ -408,8 +408,7 @@ void free_irq(unsigned int irq, void *dev_id)
                        continue;
 
                /* Found it - now free it */
-               save_flags(flags);
-               cli();
+               save_and_cli(flags);
                *p = action->next;
                restore_flags(flags);
                kfree(action);
index ce8fc60a96f77ed6c7aed2bb3b947e93f57b31cf..24a0d0148baa2bb09420557c815a012d49f1a2d3 100644 (file)
@@ -1,7 +1,9 @@
-/* $Id: indy_timer.c,v 1.1 1997/06/06 09:36:28 ralf Exp $
+/*
  * indy_timer.c: Setting up the clock on the INDY 8254 controller.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: indy_timer.c,v 1.2 1997/06/30 15:53:04 ralf Exp $
  */
 
 #include <linux/errno.h>
@@ -280,7 +282,7 @@ void do_gettimeofday(struct timeval *tv)
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       save_and_cli(flags);
        *tv = xtime;
        restore_flags(flags);
 }
index 64fa44c6379d8388d83840eb2b09abcc2bdc73f2..cec9f360095417f4ec9d8a84fe40e3d76f16fc5c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.1 1997/06/06 09:36:33 ralf Exp $
+/* $Id: setup.c,v 1.2 1997/06/30 15:26:24 ralf Exp $
  * setup.c: SGI specific setup, including init of the feature struct.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -59,8 +59,6 @@ void sgi_setup(void)
 
        /* register_console(sgi_print); */
 
-       sgi_sysinit();
-
        /* Init the INDY HPC I/O controller.  Need to call this before
         * fucking with the memory controller because it needs to know the
         * boardID and whether this is a Guiness or a FullHouse machine.
index b4d963882d2647329fb00badf28df2fea982ce41..c1f8538929e69c005ed313f6a3380edbdfeec308 100644 (file)
@@ -1,7 +1,9 @@
-/* $Id: system.c,v 1.1 1997/06/06 09:36:36 ralf Exp $
+/*
  * system.c: Probe the system type using ARCS prom interface library.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: system.c,v 1.2 1997/06/30 15:26:32 ralf Exp $
  */
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -88,6 +90,10 @@ static int string_to_cpu(char *s)
        return 0;
 }
 
+/*
+ * We' call this early before loadmmu().  If we do the other way around
+ * the firmware will crash and burn.
+ */
 void sgi_sysinit(void)
 {
        pcomponent *p, *toplev, *cpup = 0;
index a8660dcf6c6fb30e17a9051af38385ab443688be..3ea39e133be5653649437ee8b1d38abc7a142e3a 100644 (file)
@@ -124,4 +124,24 @@ void output_mm_defines(void)
        linefeed;
 }
 
+void output_sc_defines(void)
+{
+       text("/* Linux sigcontext offsets. */");
+       offset("#define SC_REGMASK    ", struct sigcontext, sc_regmask);
+       offset("#define SC_STATUS     ", struct sigcontext, sc_status);
+       offset("#define SC_PC         ", struct sigcontext, sc_pc);
+       offset("#define SC_REGS       ", struct sigcontext, sc_regs);
+       offset("#define SC_FPREGS     ", struct sigcontext, sc_fpregs);
+       offset("#define SC_OWNEDFP    ", struct sigcontext, sc_ownedfp);
+       offset("#define SC_FPC_CSR    ", struct sigcontext, sc_fpc_csr);
+       offset("#define SC_FPC_EIR    ", struct sigcontext, sc_fpc_eir);
+       offset("#define SC_SSFLAGS    ", struct sigcontext, sc_ssflags);
+       offset("#define SC_MDHI       ", struct sigcontext, sc_mdhi);
+       offset("#define SC_MDLO       ", struct sigcontext, sc_mdlo);
+       offset("#define SC_CAUSE      ", struct sigcontext, sc_cause);
+       offset("#define SC_BADVADDR   ", struct sigcontext, sc_badvaddr);
+       offset("#define SC_SIGSET     ", struct sigcontext, sc_sigset);
+       linefeed;
+}
+
 text("#endif /* !(_MIPS_OFFSET_H) */");
index f94ef8b91b7c8c71f6a4a3b470baa274aef03814..aeb5a46c816acf6714c988fb4c6c468da799385e 100644 (file)
@@ -76,6 +76,7 @@ struct cpu_iu_info linux_sparc_chips[] = {
   { 0, 0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"},
   /* borned STP1012PGA */
   { 0, 4, "Fujitsu  MB86904"},
+  { 0, 5, "Fujitsu TurboSparc MB86907"},
   /* SparcStation2, SparcServer 490 & 690 */
   { 1, 0, "LSI Logic Corporation - L64811"},
   /* SparcStation2 */
index 38896ab22846ab7786d58495c3f02876cf4304bf..cf4146c4aa8132bb1537f84aa8e32fbc3fa6be93 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.59 1997/05/08 17:45:20 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.60 1997/06/17 13:25:13 jj Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -59,6 +59,7 @@ 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 char saved_command_line[];
 
 extern void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
@@ -200,7 +201,7 @@ EXPORT_SYMBOL(prom_getproplen);
 EXPORT_SYMBOL(prom_getproperty);
 EXPORT_SYMBOL(prom_node_has_property);
 EXPORT_SYMBOL(prom_setprop);
-EXPORT_SYMBOL(prom_getbootargs);
+EXPORT_SYMBOL(saved_command_line);
 EXPORT_SYMBOL(prom_apply_obio_ranges);
 EXPORT_SYMBOL(prom_getname);
 EXPORT_SYMBOL(prom_feval);
index f7b9b367ce71f9e5f72a69e69a42bc4171afaef6..84cd1d2e2f671ff5c05f2562377a24ba11bf62a7 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.25 1997/05/03 05:09:11 davem Exp $
+# $Id: Makefile,v 1.26 1997/06/24 15:48:06 jj Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -9,7 +9,8 @@
 
 O_TARGET := mm.o
 O_OBJS   := fault.o init.o sun4c.o srmmu.o hypersparc.o viking.o \
-           tsunami.o loadmmu.o generic.o asyncd.o extable.o
+           tsunami.o loadmmu.o generic.o asyncd.o extable.o \
+           turbosparc.o
 
 include $(TOPDIR)/Rules.make
 
@@ -18,6 +19,9 @@ ifdef SMP
 hypersparc.o: hypersparc.S
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S
 
+turbosparc.o: turbosparc.S
+       $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o turbosparc.o turbosparc.S
+
 viking.o: viking.S
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o viking.o viking.S
 
@@ -29,6 +33,9 @@ else
 hypersparc.o: hypersparc.S
        $(CC) -D__ASSEMBLY__ -ansi -c -o hypersparc.o hypersparc.S
 
+turbosparc.o: turbosparc.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o turbosparc.o turbosparc.S
+
 viking.o: viking.S
        $(CC) -D__ASSEMBLY__ -ansi -c -o viking.o viking.S
 
index 7420b98cb2ca06f15a067d8ba3ee8c8e34f27e84..3b997055116a7b33215b97c2995736641b8ffca4 100644 (file)
@@ -1,9 +1,10 @@
-/* $Id: srmmu.c,v 1.147 1997/05/20 07:58:42 jj Exp $
+/* $Id: srmmu.c,v 1.148 1997/06/24 15:48:02 jj Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
  * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru)
  * Copyright (C) 1996 Eddie C. Dost    (ecd@skynet.be)
+ * Copyright (C) 1997 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/config.h>
@@ -36,6 +37,7 @@
 #include <asm/ross.h>
 #include <asm/tsunami.h>
 #include <asm/swift.h>
+#include <asm/turbosparc.h>
 
 enum mbus_module srmmu_modtype;
 unsigned int hwbug_bitmask;
@@ -2595,6 +2597,78 @@ __initfunc(static void init_swift(void))
        poke_srmmu = poke_swift;
 }
 
+/* turbosparc.S */
+extern void turbosparc_flush_cache_all();
+extern void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
+
+static void poke_turbosparc(void)
+{
+       unsigned long mreg = srmmu_get_mmureg();
+       unsigned long ccreg;
+
+       /* Clear any crap from the cache or else... */
+       turbosparc_flush_cache_all();
+       mreg &= ~(TURBOSPARC_ICENABLE | TURBOSPARC_DCENABLE); /* Temporarily disable I & D caches */
+       mreg &= ~(TURBOSPARC_PCENABLE);         /* Don't check parity */
+       srmmu_set_mmureg(mreg);
+       
+       ccreg = turbosparc_get_ccreg();
+
+#ifdef TURBOSPARC_WRITEBACK
+       ccreg |= (TURBOSPARC_SNENABLE);         /* Do DVMA snooping in Dcache */
+       ccreg &= ~(TURBOSPARC_uS2 | TURBOSPARC_WTENABLE);
+                       /* Write-back D-cache, emulate VLSI 
+                        * abortion number three, not number one */
+#else
+       /* For now let's play safe, optimize later */
+       ccreg |= (TURBOSPARC_SNENABLE | TURBOSPARC_WTENABLE);
+                       /* Do DVMA snooping in Dcache, Write-thru D-cache */
+       ccreg &= ~(TURBOSPARC_uS2);
+                       /* Emulate VLSI abortion number three, not number one */
+#endif                  
+       switch (ccreg & 7) {
+       case 0: /* No SE cache */
+       case 7: /* Test mode */
+               break;
+       default:
+               ccreg |= (TURBOSPARC_SCENABLE);
+       }
+       turbosparc_set_ccreg (ccreg);
+
+       mreg |= (TURBOSPARC_ICENABLE | TURBOSPARC_DCENABLE); /* I & D caches on */
+       mreg |= (TURBOSPARC_ICSNOOP);           /* Icache snooping on */
+       srmmu_set_mmureg(mreg);
+}
+
+__initfunc(static void init_turbosparc(void))
+{
+       srmmu_name = "Fujitsu TurboSparc";
+       srmmu_modtype = TurboSparc;
+
+       flush_cache_all = turbosparc_flush_cache_all;
+       flush_cache_mm = hypersparc_flush_cache_mm;
+       flush_cache_page = hypersparc_flush_cache_page;
+       flush_cache_range = hypersparc_flush_cache_range;
+
+       flush_tlb_all = hypersparc_flush_tlb_all;
+       flush_tlb_mm = hypersparc_flush_tlb_mm;
+       flush_tlb_page = hypersparc_flush_tlb_page;
+       flush_tlb_range = hypersparc_flush_tlb_range;
+
+#ifdef TURBOSPARC_WRITEBACK
+       flush_page_to_ram = hypersparc_flush_page_to_ram;
+       flush_chunk = hypersparc_flush_chunk;
+#else
+       flush_page_to_ram = swift_flush_page_to_ram;
+       flush_chunk = swift_flush_chunk;
+#endif
+
+       flush_sig_insns = turbosparc_flush_sig_insns;
+       flush_page_for_dma = hypersparc_flush_page_for_dma;
+
+       poke_srmmu = poke_turbosparc;
+}
+
 static void poke_tsunami(void)
 {
        unsigned long mreg = srmmu_get_mmureg();
@@ -2785,9 +2859,33 @@ __initfunc(static void get_srmmu_type(void))
                };
                return;
        }
+       
+       /* Now Fujitsu TurboSparc. It might happen that it is
+          in Swift emulation mode, so we will check later... */
+       if (psr_typ == 0 && psr_vers == 5) {
+               init_turbosparc();
+               return;
+       }
 
        /* Next check for Fujitsu Swift. */
        if(psr_typ == 0 && psr_vers == 4) {
+               int cpunode;
+               char node_str[128];
+
+               /* Look if it is not a TurboSparc emulating Swift... */
+               cpunode = prom_getchild(prom_root_node);
+               while((cpunode = prom_getsibling(cpunode)) != 0) {
+                       prom_getstring(cpunode, "device_type", node_str, sizeof(node_str));
+                       if(!strcmp(node_str, "cpu")) {
+                               if (!prom_getintdefault(cpunode, "psr-implementation", 1) &&
+                                   prom_getintdefault(cpunode, "psr-version", 1) == 5) {
+                                       init_turbosparc();
+                                       return;
+                               }
+                               break;
+                       }
+               }
+               
                init_swift();
                return;
        }
diff --git a/arch/sparc/mm/turbosparc.S b/arch/sparc/mm/turbosparc.S
new file mode 100644 (file)
index 0000000..fa5e5a9
--- /dev/null
@@ -0,0 +1,46 @@
+/* $Id: turbosparc.S,v 1.1 1997/06/24 15:48:05 jj Exp $
+ * turbosparc.S: High speed Hypersparc mmu/cache operations.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#include <asm/pgtsrmmu.h>
+
+#define WINDOW_FLUSH(tmp1, tmp2)                                       \
+       mov     0, tmp1;                                                \
+98:    ld      [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2;     \
+       orcc    %g0, tmp2, %g0;                                         \
+       add     tmp1, 1, tmp1;                                          \
+       bne     98b;                                                    \
+        save   %sp, -64, %sp;                                          \
+99:    subcc   tmp1, 1, tmp1;                                          \
+       bne     99b;                                                    \
+        restore %g0, %g0, %g0;
+
+       .text
+       .align  4
+
+       .globl  turbosparc_flush_cache_all
+       .globl  turbosparc_flush_sig_insns
+
+turbosparc_flush_cache_all:
+       WINDOW_FLUSH(%g4, %g5)
+       sethi   %hi(vac_cache_size), %g4
+       ld      [%g4 + %lo(vac_cache_size)], %g5
+       sethi   %hi(vac_line_size), %g1
+       ld      [%g1 + %lo(vac_line_size)], %g2
+1:     
+       subcc   %g5, %g2, %g5
+       bne     1b
+        sta    %g0, [%g5] ASI_M_DATAC_TAG
+       retl
+        sta    %g0, [%g0] ASI_M_IC_FLCLEAR
+
+turbosparc_flush_sig_insns:
+       retl
+        nop
index 1722d9fdcea03b44f439408edc42d45056aec483..e7bd9b06d8528db1f4ddb7ba5c6720edf89d51b8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bootstr.c,v 1.12 1996/12/18 06:46:54 tridge Exp $
+/* $Id: bootstr.c,v 1.14 1997/06/19 16:28:49 jj Exp $
  * bootstr.c:  Boot string/argument acquisition from the PROM.
  *
  * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,13 +7,14 @@
 #include <linux/config.h>
 #include <linux/string.h>
 #include <asm/oplib.h>
+#include <linux/init.h>
 
 #define BARG_LEN  256
-static char barg_buf[BARG_LEN];
-static char fetched = 0;
+static char barg_buf[BARG_LEN] __initdata = { 0 };
+static char fetched __initdata = 0;
 
-char *
-prom_getbootargs(void)
+__initfunc(char *
+prom_getbootargs(void))
 {
        int iter;
        char *cp, *arg;
index 251b2ee6a0c8927662add99cf8db72d90a72e36a..295ce53555250c101764955baa0dbdc46c17b1b7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.18 1997/05/14 20:45:03 davem Exp $
+/* $Id: tree.c,v 1.19 1997/06/27 14:52:54 jj Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
@@ -231,7 +231,7 @@ int prom_getname (int node, char *buffer, int len)
 
 /* Return the first property type for node 'node'.
  */
-char * prom_firstprop(int node)
+char * prom_firstprop(int node, char *buffer)
 {
        unsigned long flags;
        char *ret;
@@ -248,7 +248,7 @@ char * prom_firstprop(int node)
  * at node 'node' .  Returns NULL string if no more
  * property types for this node.
  */
-char * prom_nextprop(int node, char *oprop)
+char * prom_nextprop(int node, char *oprop, char *buffer)
 {
        char *ret;
        unsigned long flags;
@@ -293,7 +293,7 @@ int prom_node_has_property(int node, char *prop)
        char *current_property = "";
 
        do {
-               current_property = prom_nextprop(node, current_property);
+               current_property = prom_nextprop(node, current_property, NULL);
                if(!strcmp(current_property, prop))
                   return 1;
        } while (*current_property);
index a70f9ebf81642d126683c4a589df1f8e0bb13f7c..3704091eb5f170c183abc71ac407826ff148de8e 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.16 1997/05/04 07:21:08 davem Exp $
+# $Id: Makefile,v 1.19 1997/06/26 12:48:45 jj Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -24,8 +24,8 @@ ELF2AOUT64    = elf2aout64
 # debugging of the kernel to get the proper debugging information.
 
 #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 
-CFLAGS := $(CFLAGS) -pipe \
-          -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
+CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
+       -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
 
 LINKFLAGS = -T arch/sparc64/vmlinux.lds
 
index 00f687c926666fb7339db62e2aeae41f33ffb639..fcbac5c1aff084f03cc032b2c636d9f068ae0594 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.7 1997/06/17 03:54:52 davem Exp $
+# $Id: config.in,v 1.9 1997/07/04 11:33:05 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -51,10 +51,10 @@ bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'Sysctl support' CONFIG_SYSCTL
 bool 'Kernel support for Linux/Sparc 32bit binary compatibility' CONFIG_SPARC32_COMPAT
-tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF
 if [ "$CONFIG_SPARC32_COMPAT" != "n" ]; then
   tristate 'Kernel support for 32-bit ELF binaries' CONFIG_BINFMT_ELF32
+  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
@@ -157,4 +157,5 @@ bool 'Kernel profiling support' CONFIG_PROFILE
 if [ "$CONFIG_PROFILE" = "y" ]; then
        int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP
 endmenu
index 6b08fd41bbf7caea0bee9ad2a0359d02893f6923..949ea1d0211d56e7add65e35019cc867bfb2b0e1 100644 (file)
@@ -5,12 +5,14 @@
 #
 # Code maturity level options
 #
-# CONFIG_EXPERIMENTAL is not set
+CONFIG_EXPERIMENTAL=y
 
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KERNELD is not set
 
 #
 # General setup
@@ -45,25 +47,31 @@ SUN_FB_CREATOR=y
 #
 # Misc Linux/SPARC drivers
 #
-# CONFIG_SUN_OPENPROMIO is not set
+CONFIG_SUN_OPENPROMIO=m
 CONFIG_SUN_MOSTEK_RTC=y
-# CONFIG_SUN_OPENPROMFS is not set
+# CONFIG_SUN_BPP is not set
+# CONFIG_SUN_VIDEOPIX is not set
+CONFIG_SUN_OPENPROMFS=m
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
 CONFIG_SPARC32_COMPAT=y
-CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_ELF32=y
+CONFIG_BINFMT_AOUT32=y
+CONFIG_BINFMT_JAVA=m
+CONFIG_BINFMT_MISC=m
 
 #
 # Floppy, IDE, and other block devices
 #
 # CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_LOOP=m
 
 #
 # Networking options
@@ -86,15 +94,22 @@ CONFIG_INET=y
 CONFIG_PATH_MTU_DISCOVERY=y
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
 
 #
 #  
 #
-CONFIG_IPX=y
+CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
-CONFIG_ATALK=y
+# CONFIG_IPX_PPROP_ROUTING is not set
+CONFIG_ATALK=m
 # CONFIG_IPDDP is not set
 # CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
 
 #
 # SCSI support
@@ -108,7 +123,7 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=m
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -120,7 +135,7 @@ CONFIG_SCSI_CONSTANTS=y
 # SCSI low-level drivers
 #
 CONFIG_SCSI_SUNESP=y
-# CONFIG_SCSI_QLOGICPTI is not set
+CONFIG_SCSI_QLOGICPTI=m
 
 #
 # Network device support
@@ -130,8 +145,8 @@ CONFIG_DUMMY=y
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 CONFIG_SUNLANCE=y
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNQE is not set
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNQE=m
 # CONFIG_MYRI_SBUS is not set
 
 #
@@ -152,7 +167,7 @@ CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_RNFS_BOOTP=y
 # CONFIG_RNFS_RARP is not set
-# CONFIG_NFSD is not set
+CONFIG_NFSD=m
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -162,7 +177,7 @@ CONFIG_ISO9660_FS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS_FS=m
 CONFIG_UFS_FS=y
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
@@ -171,3 +186,4 @@ CONFIG_SMD_DISKLABEL=y
 # Kernel hacking
 #
 # CONFIG_PROFILE is not set
+# CONFIG_EC_FLUSH_TRAP is not set
index c7bb1064afbbbe557a1adc67ec058aa60704f3a5..9e9013735c6ac957d32ac61a752b28a9b2217e97 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.23 1997/06/06 10:56:20 jj Exp $
+# $Id: Makefile,v 1.28 1997/07/05 09:52:20 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
-O_OBJS   := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o \
-           systbls.o traps.o entry.o devices.o auxio.o ioport.o \
-           irq.o ptrace.o time.o sys_sparc.o signal.o winfixup.o \
-           unaligned.o
+O_OBJS   := process.o setup.o cpu.o idprom.o \
+           systbls.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
 OX_OBJS  := sparc64_ksyms.o
 
 ifdef CONFIG_SPARC32_COMPAT
-  O_OBJS += sys_sparc32.o signal32.o ioctl32.o
+  O_OBJS += sys32.o sys_sparc32.o signal32.o ioctl32.o
 endif
 
 ifdef CONFIG_BINFMT_ELF32
   O_OBJS += binfmt_elf32.o
 endif
 
-head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S
+ifdef CONFIG_BINFMT_AOUT32
+  O_OBJS += binfmt_aout32.o
+endif
+
+head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \
+       winfixup.S entry.S
        $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
 
 #
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
new file mode 100644 (file)
index 0000000..ecd8d55
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ *  linux/fs/binfmt_aout.c
+ *
+ *  Copyright (C) 1991, 1992, 1996  Linus Torvalds
+ *
+ *  Hacked a bit by DaveM to make it work with 32-bit SunOS
+ *  binaries on the sparc64 port.
+ */
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/malloc.h>
+#include <linux/binfmts.h>
+#include <linux/personality.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs);
+static int load_aout32_library(int fd);
+static int aout32_core_dump(long signr, struct pt_regs * regs);
+
+extern void dump_thread(struct pt_regs *, struct user *);
+
+static struct linux_binfmt aout32_format = {
+       NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump
+};
+
+static void set_brk(unsigned long start, unsigned long end)
+{
+       start = PAGE_ALIGN(start);
+       end = PAGE_ALIGN(end);
+       if (end <= start)
+               return;
+       do_mmap(NULL, start, end - start,
+               PROT_READ | PROT_WRITE | PROT_EXEC,
+               MAP_FIXED | MAP_PRIVATE, 0);
+}
+
+/*
+ * These are the only things you should do on a core-file: use only these
+ * macros to write out all the necessary info.
+ */
+#define DUMP_WRITE(addr,nr) \
+while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
+
+#define DUMP_SEEK(offset) \
+if (file.f_op->llseek) { \
+       if (file.f_op->llseek(inode,&file,(offset),0) != (offset)) \
+               goto close_coredump; \
+} else file.f_pos = (offset)
+
+/*
+ * Routine writes a core dump image in the current directory.
+ * Currently only a stub-function.
+ *
+ * Note that setuid/setgid files won't make a core-dump if the uid/gid
+ * changed due to the set[u|g]id. It's enforced by the "current->dumpable"
+ * field, which also makes sure the core-dumps won't be recursive if the
+ * dumping of the process results in another error..
+ */
+
+static inline int
+do_aout32_core_dump(long signr, struct pt_regs * regs)
+{
+       struct inode * inode = NULL;
+       struct file file;
+       unsigned short fs;
+       int has_dumped = 0;
+       char corefile[6+sizeof(current->comm)];
+       unsigned long dump_start, dump_size;
+       struct user dump;
+#       define START_DATA(u)    (u.u_tsize)
+#       define START_STACK(u)   ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
+
+       if (!current->dumpable || current->mm->count != 1)
+               return 0;
+       current->dumpable = 0;
+
+/* See if we have enough room to write the upage.  */
+       if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
+               return 0;
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       memcpy(corefile,"core.",5);
+#if 0
+       memcpy(corefile+5,current->comm,sizeof(current->comm));
+#else
+       corefile[4] = '\0';
+#endif
+       if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+               inode = NULL;
+               goto end_coredump;
+       }
+       if (!S_ISREG(inode->i_mode))
+               goto end_coredump;
+       if (!inode->i_op || !inode->i_op->default_file_ops)
+               goto end_coredump;
+       if (get_write_access(inode))
+               goto end_coredump;
+       file.f_mode = 3;
+       file.f_flags = 0;
+       file.f_count = 1;
+       file.f_inode = inode;
+       file.f_pos = 0;
+       file.f_reada = 0;
+       file.f_op = inode->i_op->default_file_ops;
+       if (file.f_op->open)
+               if (file.f_op->open(inode,&file))
+                       goto done_coredump;
+       if (!file.f_op->write)
+               goto close_coredump;
+       has_dumped = 1;
+       current->flags |= PF_DUMPCORE;
+               strncpy(dump.u_comm, current->comm, sizeof(current->comm));
+       dump.signal = signr;
+       dump_thread(regs, &dump);
+
+/* If the size of the dump file exceeds the rlimit, then see what would happen
+   if we wrote the stack, but not the data area.  */
+       if ((dump.u_dsize+dump.u_ssize) >
+           current->rlim[RLIMIT_CORE].rlim_cur)
+               dump.u_dsize = 0;
+
+/* Make sure we have enough room to write the stack and data areas. */
+       if ((dump.u_ssize) >
+           current->rlim[RLIMIT_CORE].rlim_cur)
+               dump.u_ssize = 0;
+
+/* make sure we actually have a data and stack area to dump */
+       set_fs(USER_DS);
+       if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize))
+               dump.u_dsize = 0;
+       if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize))
+               dump.u_ssize = 0;
+
+       set_fs(KERNEL_DS);
+/* struct user */
+       DUMP_WRITE(&dump,sizeof(dump));
+/* now we start writing out the user space info */
+       set_fs(USER_DS);
+/* Dump the data area */
+       if (dump.u_dsize != 0) {
+               dump_start = START_DATA(dump);
+               dump_size = dump.u_dsize;
+               DUMP_WRITE(dump_start,dump_size);
+       }
+/* Now prepare to dump the stack area */
+       if (dump.u_ssize != 0) {
+               dump_start = START_STACK(dump);
+               dump_size = dump.u_ssize;
+               DUMP_WRITE(dump_start,dump_size);
+       }
+/* Finally dump the task struct.  Not be used by gdb, but could be useful */
+       set_fs(KERNEL_DS);
+       DUMP_WRITE(current,sizeof(*current));
+       inode->i_status |= ST_MODIFIED;
+close_coredump:
+       if (file.f_op->release)
+               file.f_op->release(inode,&file);
+done_coredump:
+       put_write_access(inode);
+end_coredump:
+       set_fs(fs);
+       iput(inode);
+       return has_dumped;
+}
+
+static int
+aout32_core_dump(long signr, struct pt_regs * regs)
+{
+       int retval;
+
+       MOD_INC_USE_COUNT;
+       retval = do_aout32_core_dump(signr, regs);
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+/*
+ * create_aout32_tables() parses the env- and arg-strings in new user
+ * memory and creates the pointer tables from them, and puts their
+ * addresses on the "stack", returning the new stack pointer value.
+ */
+#define A(x) ((unsigned long)x)
+static u32 *create_aout32_tables(char * p, struct linux_binprm * bprm)
+{
+       u32 *argv, *envp;
+       u32 *sp;
+       int argc = bprm->argc;
+       int envc = bprm->envc;
+
+       sp = (u32 *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
+
+       /* This imposes the proper stack alignment for a new process. */
+       sp = (u32 *) (((unsigned long) sp) & ~7);
+       if ((envc+argc+3)&1)
+               --sp;
+
+       sp -= envc+1;
+       envp = (u32 *) sp;
+       sp -= argc+1;
+       argv = (u32 *) sp;
+       put_user(argc,--sp);
+       current->mm->arg_start = (unsigned long) p;
+       while (argc-->0) {
+               char c;
+               put_user(((u32)A(p)),argv++);
+               do {
+                       get_user(c,p++);
+               } while (c);
+       }
+       put_user(NULL,argv);
+       current->mm->arg_end = current->mm->env_start = (unsigned long) p;
+       while (envc-->0) {
+               char c;
+               put_user(((u32)A(p)),envp++);
+               do {
+                       get_user(c,p++);
+               } while (c);
+       }
+       put_user(NULL,envp);
+       current->mm->env_end = (unsigned long) p;
+       return sp;
+}
+
+/*
+ * These are the functions used to load a.out style executables and shared
+ * libraries.  There is no binary dependent code anywhere else.
+ */
+
+static inline int do_load_aout32_binary(struct linux_binprm * bprm,
+                                       struct pt_regs * regs)
+{
+       struct exec ex;
+       struct file * file;
+       int fd;
+       unsigned long error;
+       unsigned long p = bprm->p;
+       unsigned long fd_offset;
+       unsigned long rlim;
+
+       ex = *((struct exec *) bprm->buf);              /* exec-header */
+       if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
+            N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
+           N_TRSIZE(ex) || N_DRSIZE(ex) ||
+           bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+               return -ENOEXEC;
+       }
+
+       current->personality = PER_LINUX;
+       fd_offset = N_TXTOFF(ex);
+
+       /* Check initial limits. This avoids letting people circumvent
+        * size limits imposed on them by creating programs with large
+        * arrays in the data or bss.
+        */
+       rlim = current->rlim[RLIMIT_DATA].rlim_cur;
+       if (rlim >= RLIM_INFINITY)
+               rlim = ~0;
+       if (ex.a_data + ex.a_bss > rlim)
+               return -ENOMEM;
+
+       /* OK, This is the point of no return */
+       flush_old_exec(bprm);
+       memcpy(&current->tss.core_exec, &ex, sizeof(struct exec));
+
+       current->mm->end_code = ex.a_text +
+               (current->mm->start_code = N_TXTADDR(ex));
+       current->mm->end_data = ex.a_data +
+               (current->mm->start_data = N_DATADDR(ex));
+       current->mm->brk = ex.a_bss +
+               (current->mm->start_brk = N_BSSADDR(ex));
+
+       current->mm->rss = 0;
+       current->mm->mmap = NULL;
+       current->suid = current->euid = current->fsuid = bprm->e_uid;
+       current->sgid = current->egid = current->fsgid = bprm->e_gid;
+       current->flags &= ~PF_FORKNOEXEC;
+       if (N_MAGIC(ex) == NMAGIC) {
+               /* Fuck me plenty... */
+               error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text,
+                               PROT_READ|PROT_WRITE|PROT_EXEC,
+                               MAP_FIXED|MAP_PRIVATE, 0);
+               read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+                         ex.a_text, 0);
+               error = do_mmap(NULL, N_DATADDR(ex), ex.a_data,
+                               PROT_READ|PROT_WRITE|PROT_EXEC,
+                               MAP_FIXED|MAP_PRIVATE, 0);
+               read_exec(bprm->inode, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
+                         ex.a_data, 0);
+               goto beyond_if;
+       }
+
+       if (N_MAGIC(ex) == OMAGIC) {
+               do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
+                       ex.a_text+ex.a_data + PAGE_SIZE - 1,
+                       PROT_READ|PROT_WRITE|PROT_EXEC,
+                       MAP_FIXED|MAP_PRIVATE, 0);
+               read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+                         ex.a_text+ex.a_data, 0);
+       } else {
+               if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
+                   (N_MAGIC(ex) != NMAGIC))
+                       printk(KERN_NOTICE "executable not page aligned\n");
+
+               fd = open_inode(bprm->inode, O_RDONLY);
+
+               if (fd < 0)
+                       return fd;
+               file = current->files->fd[fd];
+               if (!file->f_op || !file->f_op->mmap) {
+                       sys_close(fd);
+                       do_mmap(NULL, 0, ex.a_text+ex.a_data,
+                               PROT_READ|PROT_WRITE|PROT_EXEC,
+                               MAP_FIXED|MAP_PRIVATE, 0);
+                       read_exec(bprm->inode, fd_offset,
+                                 (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
+                       goto beyond_if;
+               }
+
+               error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
+                       PROT_READ | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
+                       fd_offset);
+
+               if (error != N_TXTADDR(ex)) {
+                       sys_close(fd);
+                       send_sig(SIGKILL, current, 0);
+                       return error;
+               }
+
+               error = do_mmap(file, N_DATADDR(ex), ex.a_data,
+                               PROT_READ | PROT_WRITE | PROT_EXEC,
+                               MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
+                               fd_offset + ex.a_text);
+               sys_close(fd);
+               if (error != N_DATADDR(ex)) {
+                       send_sig(SIGKILL, current, 0);
+                       return error;
+               }
+       }
+beyond_if:
+       if (current->exec_domain && current->exec_domain->module)
+               __MOD_DEC_USE_COUNT(current->exec_domain->module);
+       if (current->binfmt && current->binfmt->module)
+               __MOD_DEC_USE_COUNT(current->binfmt->module);
+       current->exec_domain = lookup_exec_domain(current->personality);
+       current->binfmt = &aout32_format;
+       if (current->exec_domain && current->exec_domain->module)
+               __MOD_INC_USE_COUNT(current->exec_domain->module);
+       if (current->binfmt && current->binfmt->module)
+               __MOD_INC_USE_COUNT(current->binfmt->module);
+
+       set_brk(current->mm->start_brk, current->mm->brk);
+
+       p = setup_arg_pages(p, bprm);
+
+       p = (unsigned long) create_aout32_tables((char *)p, bprm);
+       current->mm->start_stack = p;
+       start_thread32(regs, ex.a_entry, p);
+       if (current->flags & PF_PTRACED)
+               send_sig(SIGTRAP, current, 0);
+       return 0;
+}
+
+
+static int
+load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+       int retval;
+
+       MOD_INC_USE_COUNT;
+       retval = do_load_aout32_binary(bprm, regs);
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+static inline int
+do_load_aout32_library(int fd)
+{
+        struct file * file;
+       struct exec ex;
+       struct  inode * inode;
+       unsigned int len;
+       unsigned int bss;
+       unsigned int start_addr;
+       unsigned long error;
+
+       file = current->files->fd[fd];
+       inode = file->f_inode;
+
+       if (!file || !file->f_op)
+               return -EACCES;
+
+       /* Seek into the file */
+       if (file->f_op->llseek) {
+               if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
+                       return -ENOEXEC;
+       } else
+               file->f_pos = 0;
+
+       set_fs(KERNEL_DS);
+       error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex));
+       set_fs(USER_DS);
+       if (error != sizeof(ex))
+               return -ENOEXEC;
+
+       /* We come in here for the regular a.out style of shared libraries */
+       if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
+           N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
+           inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+               return -ENOEXEC;
+       }
+       if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
+           (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
+               printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
+               return -ENOEXEC;
+       }
+
+       if (N_FLAGS(ex)) return -ENOEXEC;
+
+       /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
+          this off to get the starting address for the page */
+
+       start_addr =  ex.a_entry & 0xfffff000;
+
+       /* Now use mmap to map the library into memory. */
+       error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
+                       PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+                       N_TXTOFF(ex));
+       if (error != start_addr)
+               return error;
+       len = PAGE_ALIGN(ex.a_text + ex.a_data);
+       bss = ex.a_text + ex.a_data + ex.a_bss;
+       if (bss > len) {
+               error = do_mmap(NULL, start_addr + len, bss-len,
+                               PROT_READ|PROT_WRITE|PROT_EXEC,
+                               MAP_PRIVATE|MAP_FIXED, 0);
+               if (error != start_addr + len)
+                       return error;
+       }
+       return 0;
+}
+
+static int
+load_aout32_library(int fd)
+{
+       int retval;
+
+       MOD_INC_USE_COUNT;
+       retval = do_load_aout32_library(fd);
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+
+__initfunc(int init_aout32_binfmt(void))
+{
+       return register_binfmt(&aout32_format);
+}
index 695ad680e91fa1356724a63a7331ab76a0d099c2..96dc599e83f5b2dc106211ceda7ee3567f54f798 100644 (file)
@@ -6,7 +6,9 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <asm/asi.h>
 #include <asm/system.h>
+#include <asm/fpumacro.h>
 
 struct cpu_iu_info {
   short manuf;
@@ -50,11 +52,20 @@ __initfunc(void cpu_probe(void))
        int manuf, impl;
        unsigned i, cpuid;
        long ver, fpu_vers;
-
-       cpuid = get_cpuid();
+       long fprs;
        
+#ifndef __SMP__
+       cpuid = 0;
+#else
+#error SMP not supported on sparc64 yet
+       /* cpuid = get_cpuid(); */
+#endif
+
+       fprs = fprs_read ();
+       fprs_write (FPRS_FEF);
        __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=r" (ver) : "r" (&fpu_vers));
-
+       fprs_write (fprs);
+       
        manuf = ((ver >> 48)&0xffff);
        impl = ((ver >> 32)&0xffff);
 
index 6aadd14e014eb76345c7178a6e91d5a00e86b72b..5e6705896048e4ab3f24ba2ec25408820e1bc678 100644 (file)
@@ -6,7 +6,6 @@
 
 #include <linux/kernel.h>
 #include <linux/tasks.h>
-#include <linux/config.h>
 #include <linux/init.h>
 
 #include <asm/page.h>
@@ -15,7 +14,7 @@
 #include <asm/smp.h>
 
 struct prom_cpuinfo linux_cpus[NCPUS];
-int linux_num_cpus;
+int linux_num_cpus = 0;
 
 extern void cpu_probe(void);
 
@@ -54,7 +53,7 @@ device_scan(unsigned long mem_start))
                };
                if(cpu_ctr == 0) {
                        printk("No CPU nodes found, cannot continue.\n");
-                       halt();
+                       prom_halt();
                }
                printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
        };
index 31b87f3de8e6a1b87fb6bb95c581aa90bb30c6c8..b034ef407e5ac51fc61b6c95c4b8a50fc9e5b72a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dtlb_miss.S,v 1.11 1997/04/10 01:59:35 davem Exp $
+/* $Id: dtlb_miss.S,v 1.12 1997/06/26 12:47:08 jj Exp $
  * dtlb_miss.S:        Data TLB miss code, this is included directly
  *              into the trap table.
  *
  *             }
  *             goto longer_processing;
  * } else {
- *             if(fault_address >= KERNBASE &&
- *                fault_address < VMALLOC_START) {
- *                     tlb_load(__pa(fault_address) | PAGE_KERNEL);
+ *             if(fault_address >= PAGE_OFFSET) {
+ *                     pte_val = PAGE_KERNEL;
+ *                     if (fault_address & 0x10000000000)
+ *                             pte_val = PAGE_KERNEL_IO;
+ *                     tlb_load(__pa(fault_address) | pte_val);
  *                     return_from_trap();
  *             } else {
  *                     pgd = pgd_offset(swapper_pg_dir, fault_address);
@@ -32,9 +34,9 @@
  * This is optimized for user TLB misses on purpose.
  */
 
-#define KERN_HIGHBITS  (_PAGE_VALID | _PAGE_SZ4MB)
+#define KERN_HIGHBITS  ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
 #define KERN_LOWBITS   (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#define KERN_LOWBITS_IO        (_PAGE_E | _PAGE_P | _PAGE_W)
+#define KERN_LOWBITS_IO        ((_PAGE_E | _PAGE_P | _PAGE_W) ^ KERN_LOWBITS)
 
                                /* ICACHE line 1 */
   /*0x00*/     ldxa            [%g0] ASI_DMMU, %g1             ! Get TAG_TARGET
 1:/*0x3c*/     retry                                                   ! Trap return
 
 3:                             /* ICACHE line 3 */
-  /*0x40*/     sllx            %g1, 43, %g5            ! This gets >= VMALLOC_START...
-  /*0x44*/     brlz,pn         %g5, 4f                 ! ...if now less than zero.
-  /*0x48*/      andncc         %g1, 0x3ff, %g0         ! Slick trick...
-  /*0x4c*/     be,pn           %xcc, 4f                ! Yes, it is some PROM mapping
-  /*0x50*/      srlx           %g5, 21, %g5            ! This is now physical page
-  /*0x54*/     sethi           %uhi(KERN_HIGHBITS), %g1        ! Construct PTE
-  /*0x58*/     sllx            %g1, 32, %g1                    ! Move priv bits up
-  /*0x5c*/     or              %g1, %g5, %g1                   ! Or in the page
+  /*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...
+  /*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?
+  /*0x5c*/      xor            %g1, (KERN_LOWBITS_IO), %g1     ! Aha, it is IO...
 
                                /* ICACHE line 4 */
-  /*0x60*/     or              %g1, (KERN_LOWBITS), %g1        ! Set low priv bits
+5:/*0x60*/     xor             %g1, %g5, %g1                   ! Slick trick II...
   /*0x64*/     stxa            %g1, [%g0] ASI_DTLB_DATA_IN     ! TLB load
   /*0x68*/     retry                                           ! Trap return
 4:/*0x6c*/     ldxa            [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
@@ -78,3 +80,4 @@
 
 #undef KERN_HIGHBITS
 #undef KERN_LOWBITS
+#undef KERN_LOWBITS_IO
index 0d95e1b75b25356adff2caad8abdc270897383ac..2f012e18498448196e7addc8db39c87b98ead875 100644 (file)
@@ -1,13 +1,12 @@
-/* $Id: entry.S,v 1.31 1997/06/02 06:33:25 davem Exp $
+/* $Id: entry.S,v 1.45 1997/07/05 09:52:25 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * 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,1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 
 #include <asm/head.h>
@@ -25,7 +24,6 @@
 #define NR_SYSCALLS 256      /* Each OS is different... */
 
        .text
-        .align  4
        .globl  sparc64_dtlb_prot_catch, sparc64_dtlb_refbit_catch
        .globl  sparc64_itlb_refbit_catch
 
         * to update the dirty bit) and since we left crap in the sfsr
         * it will not get updated properly.
         */
+       .align          32
 sparc64_dtlb_prot_catch:
        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
-       ldxa            [%g0 + TLB_SFSR] %asi, %g4
-       cmp             %g3, 1
        stxa            %g0, [%g0 + TLB_SFSR] %asi
+       membar          #Sync
+       cmp             %g3, 1
+
        bgu,a,pn        %icc, winfix_trampoline
         rdpr           %tpc, %g3
        ba,pt           %xcc, etrap
         rd             %pc, %g7
-       b,a,pt          %xcc, 1f
-
+       b,pt            %xcc, 1f
+        mov            1, %o2
 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
@@ -64,23 +65,24 @@ sparc64_dtlb_refbit_catch:
        wrpr            %g1, PSTATE_AG|PSTATE_MG, %pstate
        rdpr            %tl, %g3
        ldxa            [%g0 + TLB_TAG_ACCESS] %asi, %g5
+
        cmp             %g3, 1
-       clr             %g4                     ! sfsr not updated for tlb misses
-       bgu,a,pn        %icc, winfix_trampoline
+       bgu,pn          %icc, winfix_trampoline
         rdpr           %tpc, %g3
-       ba,pt           %xcc, etrap
+       b,pt            %xcc, etrap
         rd             %pc, %g7
-1:
-       mov             %l5, %o4                ! raw tag access
-       mov             %l4, %o5                ! raw sfsr
-       srlx            %l5, PAGE_SHIFT, %o3
-       clr             %o1                     ! text_fault == 0
-       sllx            %o3, PAGE_SHIFT, %o3    ! address
-       and             %l4, 0x4, %o2           ! write == sfsr.W
+       clr             %o2
+1:     srlx            %l5, PAGE_SHIFT, %o1
+       add             %sp, STACK_BIAS + REGWIN_SZ, %o0
+
        call            do_sparc64_fault
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o0        ! pt_regs ptr
-       ba,pt           %xcc, rtrap
+        sllx           %o1, PAGE_SHIFT, %o1
+       b,pt            %xcc, rtrap
         clr            %l6
+       nop
+       nop
+       nop
+       nop
 
 sparc64_itlb_refbit_catch:
        srlx            %g5, 9, %g4
@@ -90,35 +92,105 @@ sparc64_itlb_refbit_catch:
         mov            1, %g4
        rdpr            %pstate, %g1
        wrpr            %g1, PSTATE_AG|PSTATE_MG, %pstate
-       ba,pt           %xcc, etrap
-        rd             %pc, %g7
-
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
-       mov             1, %o1                                  ! text_fault == 1
-       clr             %o2                                     ! write == 0
-       clr             %o4                                     ! tag access (N/A)
-       clr             %o5                                     ! raw sfsr (N/A)
-       call            do_sparc64_fault
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o0        ! pt_regs ptr
-       ba,pt           %xcc, rtrap
-        clr            %l6
+       rdpr            %tpc, %g5
 
-2:
-       sllx            %g4, 63, %g4                            ! _PAGE_VALID
+       b,pt            %xcc, etrap
+        rd             %pc, %g7
+       b,pt            %xcc, 1b
+        clr            %o2
+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
-
-3:
-       sllx            %g4, 63, %g4                            ! _PAGE_VALID
+3:     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_ITLB_DATA_IN             ! TLB load
        retry
 
+       /* 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
+       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
+       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_exit
+        wr             %g0, 0, %gsr
+
+fpload_fromkstk:
+       or              %g2, %lo((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2
+       add             %g6, %g2, %g2
+       mov             SECONDARY_CONTEXT, %g3
+       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:
+       rdpr            %tstate, %g3
+       sethi           %hi(TSTATE_PEF), %g4
+       or              %g3, %g4, %g3           ! anal...
+       wrpr            %g3, %tstate
+       retry
+
        /* 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:
@@ -130,7 +202,7 @@ sparc64_itlb_refbit_catch:
         * With this method we can do most of the cross-call tlb/cache
         * flushing in very quickly.
         */
-       .align  4
+       .align  32
        .globl  do_ivec
 do_ivec:
        ldxa            [%g0] ASI_INTR_RECEIVE, %g1
@@ -139,16 +211,12 @@ do_ivec:
         mov            0x40, %g2
 
        /* Load up Interrupt Vector Data 0 register. */
-       sethi           %uhi(ivector_to_mask), %g4
        ldxa            [%g2] ASI_UDB_INTR_R, %g3
-       or              %g4, %ulo(ivector_to_mask), %g4
-       and             %g3, 0x7ff, %g3
-       sllx            %g4, 32, %g4
        sethi           %hi(ivector_to_mask), %g5
+       and             %g3, 0x7ff, %g3
+       orcc            %g5, %lo(ivector_to_mask), %g5
        sllx            %g3, 3, %g3
-       or              %g5, %lo(ivector_to_mask), %g5
-       add             %g5, %g4, %g4
-       ldx             [%g4 + %g3], %g2
+       ldx             [%g5 + %g3], %g2
        brz,pn          %g2, do_ivec_spurious
         nop
 
@@ -166,6 +234,7 @@ do_ivec_return:
 
 do_ivec_spurious:
        stxa            %g0, [%g0] ASI_INTR_RECEIVE
+       membar          #Sync
        rdpr            %pstate, %g1
        wrpr            %g1, PSTATE_IG | PSTATE_AG, %pstate
        ba,pt           %xcc, etrap
@@ -175,7 +244,36 @@ do_ivec_spurious:
        ba,pt           %xcc, rtrap
         clr            %l6
 
-       .globl  do_mna
+       .globl          getcc, setcc
+getcc:
+       ldx             [%o0 + PT_V9_TSTATE], %o1
+       srlx            %o1, 32, %o1
+       and             %o1, 0xf, %o1
+       retl
+        stx            %o1, [%o0 + PT_V9_G1]
+setcc:
+       ldx             [%o0 + PT_V9_TSTATE], %o1
+       ldx             [%o0 + PT_V9_G1], %o2
+       or              %g0, %ulo(TSTATE_ICC), %o3
+       sllx            %o3, 32, %o3
+       andn            %o1, %o3, %o1
+       sllx            %o2, 32, %o2
+       and             %o2, %o3, %o2
+       or              %o1, %o2, %o1
+       retl
+        stx            %o1, [%o0 + PT_V9_TSTATE]
+
+       /* XXX Here is stuff we still need to write... -DaveM XXX */
+       .globl          floppy_hardint, indirect_syscall, netbsd_syscall
+       .globl          solaris_syscall
+floppy_hardint:
+indirect_syscall:
+netbsd_syscall:
+solaris_syscall:
+       retl
+        nop
+
+       .globl          do_mna
 do_mna:
        rdpr            %tl, %g3
        cmp             %g3, 1
@@ -195,187 +293,211 @@ breakpoint_trap:
        ba,pt           %xcc, rtrap
         nop
 
-       .globl  sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
-       .globl  sys_sigsuspend, sys_sigreturn
-       .globl  sys32_execve, sys_ptrace
-
-sys_pipe:
-       sethi           %hi(sparc_pipe), %g1
-       add             %g1, %g4, %g1
-       jmpl            %g1 + %lo(sparc_pipe), %g0
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
-
-sys_nis_syscall:
-       sethi           %hi(c_sys_nis_syscall), %g1
-       add             %g1, %g4, %g1
-       jmpl            %g1 + %lo(c_sys_nis_syscall), %g0
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
-
-sys_execve:
-       sethi           %hi(sparc_execve), %g1
-       add             %g1, %g4, %g1
-       jmpl            %g1 + %lo(sparc_execve), %g0
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
-
-sys32_execve:
-       sethi           %hi(sparc32_execve), %g1
-       add             %g1, %g4, %g1
-       jmpl            %g1 + %lo(sparc32_execve), %g0
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
-
-sys_sigpause:
-       /* NOTE: %o0 has a correct value already */
-       call            do_sigpause
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o1
-       
-       ld              [%curptr + AOFF_task_flags], %l5
-       andcc           %l5, 0x20, %g0
-       be,pt           %icc, rtrap
-        clr            %l6
-       call            syscall_trace
+       /* SunOS uses syscall zero as the 'indirect syscall' it looks
+        * like indir_syscall(scall_num, arg0, arg1, arg2...);  etc.
+        * This is complete brain damage.
+        */
+       .globl  sunos_indir
+sunos_indir:
+       srl             %o0, 0, %o0
+       mov             %o7, %l4
+       cmp             %o0, NR_SYSCALLS
+       blu,a,pt        %icc, 1f
+        sll            %o0, 0x3, %o0
+       sethi           %hi(sunos_nosys), %l6
+       b,pt            %xcc, 2f
+        or             %l6, %lo(sunos_nosys), %l6
+1:     sethi           %hi(sunos_sys_table), %l7
+       or              %l7, %lo(sunos_sys_table), %l7
+       ldx             [%l7 + %o0], %l6
+2:     mov             %o1, %o0
+       mov             %o2, %o1
+       mov             %o3, %o2
+       mov             %o4, %o3
+       mov             %o5, %o4
+       call            %l6
+        mov            %l4, %o7
+
+       .globl  sunos_getpid
+sunos_getpid:
+       call    sys_getppid
         nop
-       ba,pt           %xcc, rtrap
-        clr            %l6
-
-sys_sigsuspend:
-       call            do_sigsuspend
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
-       
-       ld              [%curptr + AOFF_task_flags], %l5
-       andcc           %l5, 0x20, %g0
-       be,pt           %icc, rtrap
-        clr            %l6
-       call            syscall_trace
+       call    sys_getpid
+        stx    %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+       b,pt    %xcc, ret_sys_call
+        stx    %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+
+       /* SunOS getuid() returns uid in %o0 and euid in %o1 */
+       .globl  sunos_getuid
+sunos_getuid:
+       call    sys_geteuid
         nop
-       ba,pt           %xcc, rtrap
-        clr            %l6
-       
-sys_sigreturn:
-       call            do_sigreturn
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
-       
-       ld              [%curptr + AOFF_task_flags], %l5
-       andcc           %l5, 0x20, %g0
-       be,pt           %icc, rtrap
-        clr            %l6
-       call            syscall_trace
+       call    sys_getuid
+        stx    %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+       b,pt    %xcc, ret_sys_call
+        stx    %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+
+       /* SunOS getgid() returns gid in %o0 and egid in %o1 */
+       .globl  sunos_getgid
+sunos_getgid:
+       call    sys_getegid
         nop
-       ba,pt           %xcc, rtrap
-        clr            %l6
+       call    sys_getgid
+        stx    %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+       b,pt    %xcc, ret_sys_call
+        stx    %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
 
-sys_ptrace:
-       call            do_ptrace
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+       /* SunOS's execv() call only specifies the argv argument, the
+        * environment settings are the same as the calling processes.
+        */
+       .globl  sunos_execv
+sunos_execv:
+       sethi   %hi(sparc32_execve), %g1
+       stx     %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
+       jmpl    %g1 + %lo(sparc32_execve), %g0
+        add    %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+       .globl  sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
+       .globl  sys_sigsuspend, sys_sigreturn
+       .globl  sys32_execve, sys_ptrace
+       .align  32
+sys_pipe:      sethi           %hi(sparc_pipe), %g1
+               add             %sp, STACK_BIAS + REGWIN_SZ, %o0
+               jmpl            %g1 + %lo(sparc_pipe), %g0
+                nop
+sys_nis_syscall:sethi          %hi(c_sys_nis_syscall), %g1
+               add             %sp, STACK_BIAS + REGWIN_SZ, %o0
+               jmpl            %g1 + %lo(c_sys_nis_syscall), %g0
+                nop
+
+sys_execve:    sethi           %hi(sparc_execve), %g1
+               add             %sp, STACK_BIAS + REGWIN_SZ, %o0
+               jmpl            %g1 + %lo(sparc_execve), %g0
+                nop
+sys32_execve:  sethi           %hi(sparc32_execve), %g1
+               add             %sp, STACK_BIAS + REGWIN_SZ, %o0
+               jmpl            %g1 + %lo(sparc32_execve), %g0
+                nop
+
+               /* NOTE: %o0 has a correct value already */
+sys_sigpause:  call            do_sigpause
+                add            %sp, STACK_BIAS + REGWIN_SZ, %o1
+               ldx             [%curptr + AOFF_task_flags], %l5
+               andcc           %l5, 0x20, %g0
+               be,pt           %icc, rtrap
+                clr            %l6
+               call            syscall_trace
+                nop
+
+               ba,pt           %xcc, rtrap
+                clr            %l6
+linux_sparc_ni_syscall:
+               sethi           %hi(sys_ni_syscall), %l7
+               b,pt            %xcc,syscall_is_too_hard
+                or             %l7, %lo(sys_ni_syscall), %l7
+               nop
+
+               .align          32
+sys_sigsuspend:        call            do_sigsuspend
+                add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+               ldx             [%curptr + AOFF_task_flags], %l5
+               andcc           %l5, 0x20, %g0
+               be,pt           %icc, rtrap
+                clr            %l6
+               call            syscall_trace
+                nop
+
+               ba,pt           %xcc, rtrap
+                clr            %l6
        
-       ld              [%curptr + AOFF_task_flags], %l5
-       andcc           %l5, 0x20, %g0
-       be,pt           %icc, rtrap
-        clr            %l6
-       call            syscall_trace
-        nop
-       ba,pt           %xcc, rtrap
-        clr            %l6
+               .align          32
+sys_sigreturn: call            do_sigreturn
+                add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+               ldx             [%curptr + AOFF_task_flags], %l5
+               andcc           %l5, 0x20, %g0
+               be,pt           %icc, rtrap
+                clr            %l6
+               call            syscall_trace
+                nop
+
+               ba,pt           %xcc, rtrap
+                clr            %l6
+
+               .align          32
+sys_ptrace:    call            do_ptrace
+                add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+               ldx             [%curptr + AOFF_task_flags], %l5
+               andcc           %l5, 0x20, %g0
+               be,pt           %icc, rtrap
+                clr            %l6
+               call            syscall_trace
+                nop
+
+               ba,pt           %xcc, rtrap
+                clr            %l6
        
        /* This is how fork() was meant to be done, 12 instruction entry. -DaveM */
-       .globl  sys_fork, sys_vfork, sys_clone
+       .globl  sys_fork, sys_vfork, sys_clone, ret_from_syscall
+       .align  32
 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
-
-       /* Don't try this at home. */
-       stx             %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
-       call            do_fork
-        mov            %l5, %o7
-
-linux_sparc_ni_syscall:
-       sethi           %hi(sys_ni_syscall), %l7
-       or              %l7, %lo(sys_ni_syscall), %l7
-       ba,pt           %xcc,syscall_is_too_hard
-        add            %l7, %g4, %l7
-
-linux_fast_syscall:
-       andn            %l7, 3, %l7
-       mov             %i0, %o0
-       mov             %i1, %o1
-       mov             %i2, %o2
-       jmpl            %l7 + %g0, %g0
-        mov            %i3, %o3
+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
+ret_from_syscall:b,pt          %xcc, ret_sys_call
+                 ldx           [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+               nop
+               nop
 
 linux_syscall_trace:
-       call            syscall_trace
-        nop
-       mov             %i0, %o0
-       mov             %i1, %o1
-       mov             %i2, %o2
-       mov             %i3, %o3
-       ba,pt           %xcc, 2f
-        mov            %i4, %o4
-
-       .globl  ret_from_syscall
-ret_from_syscall:
-       ba,pt           %xcc, ret_sys_call
-        ldx            [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+               call            syscall_trace
+                nop
+               mov             %i0, %o0
+               mov             %i1, %o1
+               mov             %i2, %o2
+               mov             %i3, %o3
+               b,pt            %xcc, 2f
+                mov            %i4, %o4
 
        /* Linux native and SunOS system calls enter here... */
-       .align  4
-       .globl  linux_sparc_syscall
+       .align  32
+       .globl  linux_sparc_syscall, syscall_is_too_hard, ret_sys_call
 linux_sparc_syscall:
        /* Direct access to user regs, must faster. */
-       cmp             %g1, NR_SYSCALLS
-       add             %l7, %g4, %l7
-       bgeu,pn         %xcc, linux_sparc_ni_syscall
-        sll            %g1, 3, %l4
-       ldx             [%l7 + %l4], %l7
-       andcc           %l7, 1, %g0
-       bne,pn          %icc, linux_fast_syscall
-        /* Just do the next insn in the delay slot */
-
-       .globl  syscall_is_too_hard
+       cmp             %g1, NR_SYSCALLS                        ! IEU1  Group
+       bgeu,pn         %xcc, linux_sparc_ni_syscall            ! CTI
+        mov            %i0, %o0                                ! IEU0
+       sll             %g1, 3, %l4                             ! IEU0  Group
+       mov             %i1, %o1                                ! IEU1
+       ldx             [%l7 + %l4], %l7                        ! Load
 syscall_is_too_hard:
-#ifdef SYSCALL_TRACING /* Debugging... */
-       mov             %g1, %o0                                ! o0=scall, o1=ptregs
-       call            syscall_trace_entry
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o1
-#endif
-       mov             %i0, %o0
-       mov             %i1, %o1
-       mov             %i2, %o2
-
-       ldx             [%curptr + AOFF_task_flags], %l5
-       mov             %i3, %o3
-       mov             %i4, %o4
-       andcc           %l5, 0x20, %g0
-       bne,pn          %icc, linux_syscall_trace
-        mov            %i0, %l5
-2:
-       call            %l7
-        mov            %i5, %o5
-
-#ifdef SYSCALL_TRACING /* Debugging... */
-       call            syscall_trace_exit                      ! o0=sysret, o1=ptregs
-        add            %sp, STACK_BIAS + REGWIN_SZ, %o1
-#endif
+       mov             %i2, %o2                                ! IEU0  Group
+       ldx             [%curptr + AOFF_task_flags], %l5        ! Load
+
+       st              %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS]
+       mov             %i3, %o3                                ! IEU1
+       mov             %i4, %o4                                ! IEU0  Group
+       andcc           %l5, 0x20, %g0                          ! IEU1  2 bubbles
+       bne,pn          %icc, linux_syscall_trace               ! CTI   Group
+        mov            %i0, %l5                                ! IEU0
+2:     call            %l7                                     ! CTI   Group brk forced
+        mov            %i5, %o5                                ! IEU0
        stx             %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
 
-       .globl  ret_sys_call
 ret_sys_call:
        ldx             [%curptr + AOFF_task_flags], %l6
-       ldx             [%curptr + AOFF_task_tss + AOFF_thread_flags], %l2
+       sra             %o0, 0, %o0
        mov             %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
-       and             %l2, SPARC_FLAG_32BIT, %l2
        ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
-       brnz,a,pn       %l2, 1f
-        sra            %o0, 0, %o0
-1:
        cmp             %o0, -ENOIOCTLCMD
        sllx            %g2, 32, %g2
        bgeu,pn         %xcc, 1f
@@ -383,13 +505,12 @@ ret_sys_call:
 
        /* System call success, clear Carry condition code. */
        andn            %g3, %g2, %g3
-       clr             %l6
        stx             %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]      
        bne,pn          %icc, linux_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]
-       ba,pt           %xcc, rtrap
+       b,pt            %xcc, rtrap_clr_l6
         stx            %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
 1:
        /* System call failure, set Carry condition code.
@@ -403,10 +524,10 @@ ret_sys_call:
        bne,pn          %icc, linux_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]
-       ba,pt           %xcc, rtrap
+       b,pt            %xcc, rtrap
         stx            %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
-
 linux_syscall_trace2:
        call            syscall_trace
         add            %l1, 0x4, %l2                   /* npc = npc+4 */
@@ -414,4 +535,15 @@ linux_syscall_trace2:
        ba,pt           %xcc, rtrap
         stx            %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
 
-/* End of entry.S */
+       .align          32
+       .globl          __flushw_user
+__flushw_user:
+1:     save            %sp, -128, %sp
+       rdpr            %otherwin, %g1
+       brnz,pt         %g1, 1b
+        add            %g2, 1, %g2
+1:     sub             %g2, 1, %g2
+       brnz,pt         %g2, 1b
+        restore        %g0, %g0, %g0
+2:     retl
+        mov            %g3, %o7
index e3751c326757890211b1d1baf099a2e28ea3990b..4daf30e21babc0e500121e3112ea910ab46552bd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.22 1997/06/13 14:02:40 davem Exp $
+/* $Id: etrap.S,v 1.30 1997/06/30 10:31:37 jj Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/spitfire.h>
 #include <asm/head.h>
 
-       /* We assume that pstate, when entering this, has AG and
-        * IE bits set, MG and IG clear.
-        *
-        * We also guarentee for caller that AG %g4 and %g5 will have
-        * their values preserved and left in %l4 and %l5 respectively
-        * for him (fault handling needs this).
-        */
+#define                FPUREG_SZ               ((64 * 4) + (2 * 8))
+#define                TASK_REGOFF             ((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \
+                                        TRACEREG_SZ-REGWIN_SZ)
 
-       .text
-       .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,a,pn        %xcc, 1f
-        sub            %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
-       rd              %pic, %g3
+               .text
+               .align                  32
+               .globl                  etrap, etrap_irq, etraptl1
 
-       sethi           %hi((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
-       or              %g2, %lo((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
-       add             %g3, %g2, %g2
-1:     stx             %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]
-       rdpr            %tpc, %g1
-       rdpr            %tnpc, %g3
-       stx             %g1, [%g2 + REGWIN_SZ + PT_V9_TPC]
-       rd              %y, %g1
+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
 
-       stx             %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC]
-       stx             %g1, [%g2 + REGWIN_SZ + PT_V9_Y]
-       save            %g2, -STACK_BIAS, %sp   ! The ordering of these two instructions
-       rdpr            %pstate, %g1            ! is critical, see winfixup.S for details
-       bne,pn          %xcc, 2f
-        rdpr           %canrestore, %g3
-       rdpr            %wstate, %g6
-       wrpr            %g0, 7, %cleanwin
+               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
 
-       wrpr            %g0, 0, %canrestore
-       sll             %g6, 3, %g6
-       wrpr            %g3, 0, %otherwin
-       wrpr            %g6, %wstate
-       sethi           %uhi(KERNBASE), %g3
-       sllx            %g3, 32, %g3
-       mov             PRIMARY_CONTEXT, %g2
-       ldxa            [%g2] ASI_DMMU, %g6
-       stxa            %g0, [%g2] ASI_DMMU     ! XXX fixup cache if this stays...
-       mov             SECONDARY_CONTEXT, %g2
-       stxa            %g6, [%g2] ASI_DMMU
+               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
 
-       flush           %g3
-2:     wrpr            %g0, 0x0, %tl
-       mov             %g1, %l1
-       mov             %g4, %l4
-       mov             %g5, %l5
-       mov             %g7, %l2
-       wrpr            %l1, PSTATE_AG, %pstate
-       stx             %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
+               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
 
-       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]
+               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
 
-       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]
-       stx             %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]
-       stx             %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]
-       stx             %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
-       wrpr            %l1, (PSTATE_IE | PSTATE_AG), %pstate
-       sethi           %uhi(KERNBASE), %g4
+               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]
 
-       rd              %pic, %g6
-       jmpl            %l2 + 0x4, %g0
-        sllx           %g4, 32, %g4
-etraptl1:
-       rdpr    %tstate, %g1
-       sub     %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
-       ba,pt   %xcc, 1b
-        andcc  %g1, TSTATE_PRIV, %g0
-       nop
+               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
+
+               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
+#undef TASK_REGOFF
+#undef FPUREG_SZ
diff --git a/arch/sparc64/kernel/hack.S b/arch/sparc64/kernel/hack.S
deleted file mode 100644 (file)
index 8432213..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/* <hack>
-   This is just a huge ugly hack to get things compiled.
-   Hopefully will disappear quickly, once we get everything
-   to compile... */
-       .text
-       .align  8
-       .globl  breakpoint
-breakpoint:    retl;nop
-       .globl  do_cee
-do_cee:        retl;nop
-       .globl  do_cee_tl1
-do_cee_tl1:    retl;nop
-       .globl  do_dae_tl1
-do_dae_tl1:    retl;nop
-       .globl  do_div0_tl1
-do_div0_tl1:   retl;nop
-       .globl  do_fpdis_tl1
-do_fpdis_tl1:  retl;nop
-       .globl  do_fpieee_tl1
-do_fpieee_tl1: retl;nop
-       .globl  do_fpother_tl1
-do_fpother_tl1:        retl;nop
-       .globl  do_iae_tl1
-do_iae_tl1:    retl;nop
-       .globl  do_ill_tl1
-do_ill_tl1:    retl;nop
-       .globl  do_irq_tl1
-do_irq_tl1:    retl;nop
-       .globl  do_lddfmna
-do_lddfmna:    retl;nop
-       .globl  do_lddfmna_tl1
-do_lddfmna_tl1:        retl;nop
-       .globl  do_paw
-do_paw:        retl;nop
-       .globl  do_paw_tl1
-do_paw_tl1:    retl;nop
-       .globl  do_stdfmna
-do_stdfmna:    retl;nop
-       .globl  do_stdfmna_tl1
-do_stdfmna_tl1:        retl;nop
-       .globl  do_tof_tl1
-do_tof_tl1:    retl;nop
-       .globl  do_vaw
-do_vaw:        retl;nop
-       .globl  do_vaw_tl1
-do_vaw_tl1:    retl;nop
-       .globl  floppy_hardint
-floppy_hardint:        retl;nop
-       .globl  get_cpuid
-get_cpuid:     retl;mov 0, %o0
-       .globl  getcc
-getcc: retl;nop
-       .globl  halt
-halt:  retl;nop
-       .globl  indirect_syscall
-indirect_syscall:      retl;nop
-       .globl  install_linux_ticker
-install_linux_ticker:  retl;nop
-       .globl  install_obp_ticker
-install_obp_ticker:    retl;nop
-       .globl  linux_dbvec
-linux_dbvec:   retl;nop
-       .globl  linux_num_cpus
-linux_num_cpus:        retl;nop
-       .globl  netbsd_syscall
-netbsd_syscall:        retl;nop
-       .globl  setcc
-setcc: retl;nop
-       .globl  solaris_syscall
-solaris_syscall:       retl;nop
-       .globl  sunos_mmap
-sunos_mmap:    retl;nop
-       .globl  sunos_syscall
-sunos_syscall: retl;nop
-       .globl  svr4_getcontext
-svr4_getcontext:       retl;nop
-       .globl  svr4_setcontext
-svr4_setcontext:       retl;nop
-       .globl  sunos_accept
-sunos_accept:  retl;nop
-       .globl  sunos_audit
-sunos_audit:   retl;nop
-       .globl  sunos_brk
-sunos_brk:     retl;nop
-       .globl  sunos_execv
-sunos_execv:   retl;nop
-       .globl  sunos_fpathconf
-sunos_fpathconf:       retl;nop
-       .globl  sunos_getdents
-sunos_getdents:        retl;nop
-       .globl  sunos_getdirentries
-sunos_getdirentries:   retl;nop
-       .globl  sunos_getdomainname
-sunos_getdomainname:   retl;nop
-       .globl  sunos_getdtablesize
-sunos_getdtablesize:   retl;nop
-       .globl  sunos_getgid
-sunos_getgid:  retl;nop
-       .globl  sunos_gethostid
-sunos_gethostid:       retl;nop
-       .globl  sunos_getpid
-sunos_getpid:  retl;nop
-       .globl  sunos_getsockopt
-sunos_getsockopt:      retl;nop
-       .globl  sunos_getuid
-sunos_getuid:  retl;nop
-       .globl  sunos_indir
-sunos_indir:   retl;nop
-       .globl  sunos_ioctl
-sunos_ioctl:   retl;nop
-       .globl  sunos_killpg
-sunos_killpg:  retl;nop
-       .globl  sunos_madvise
-sunos_madvise: retl;nop
-       .globl  sunos_mctl
-sunos_mctl:    retl;nop
-       .globl  sunos_mincore
-sunos_mincore: retl;nop
-       .globl  sunos_mount
-sunos_mount:   retl;nop
-       .globl  sunos_nop
-sunos_nop:     retl;nop
-       .globl  sunos_nosys
-sunos_nosys:   retl;nop
-       .globl  sunos_open
-sunos_open:    retl;nop
-       .globl  sunos_pathconf
-sunos_pathconf:        retl;nop
-       .globl  sunos_poll
-sunos_poll:    retl;nop
-       .globl  sunos_read
-sunos_read:    retl;nop
-       .globl  sunos_readv
-sunos_readv:   retl;nop
-       .globl  sunos_recv
-sunos_recv:    retl;nop
-       .globl  sunos_sbrk
-sunos_sbrk:    retl;nop
-       .globl  sunos_select
-sunos_select:  retl;nop
-       .globl  sunos_semsys
-sunos_semsys:  retl;nop
-       .globl  sunos_send
-sunos_send:    retl;nop
-       .globl  sunos_setpgrp
-sunos_setpgrp: retl;nop
-       .globl  sunos_setsockopt
-sunos_setsockopt:      retl;nop
-       .globl  sunos_shmsys
-sunos_shmsys:  retl;nop
-       .globl  sunos_sigaction
-sunos_sigaction:       retl;nop
-       .globl  sunos_sigblock
-sunos_sigblock:        retl;nop
-       .globl  sunos_sigsetmask
-sunos_sigsetmask:      retl;nop
-       .globl  sunos_sstk
-sunos_sstk:    retl;nop
-       .globl  sunos_sysconf
-sunos_sysconf: retl;nop
-       .globl  sunos_uname
-sunos_uname:   retl;nop
-       .globl  sunos_vadvise
-sunos_vadvise: retl;nop
-       .globl  sunos_wait4
-sunos_wait4:   retl;nop
-       .globl  sunos_write
-sunos_write:   retl;nop
-       .globl  sunos_writev
-sunos_writev:  retl;nop
index 3844c24c3842ab7aa15b98af5c6987919b6ba74f..0ed975aff584624370cecc559a61ed5fd625c649 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.31 1997/05/30 22:35:28 davem Exp $
+/* $Id: head.S,v 1.43 1997/07/07 03:05:25 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,20 +8,25 @@
  */
 
 #include <linux/version.h>
+#include <linux/errno.h>
+#include <asm/asm_offsets.h>
+#include <asm/asi.h>
 #include <asm/pstate.h>
 #include <asm/ptrace.h>
 #include <asm/spitfire.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/errno.h>
+#include <asm/signal.h>
+#include <asm/processor.h>
 #include <asm/lsu.h>
 #include <asm/head.h>
        
 /* This section from from _start to sparc64_boot_end should fit into
- * 0xffff.f800.0000.4000 to 0xffff.f800.0000.8000 and will be sharing space
- * with bootup_user_stack, which is from 0xffff.f800.0000.4000 to
- * 0xffff.f800.0000.6000 and bootup_kernel_stack, which is from
- * 0xffff.f800.0000.6000 to 0xffff.f800.0000.8000. 
+ * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
+ * with bootup_user_stack, which is from 0x0000.0000.0040.4000 to
+ * 0x0000.0000.0040.6000 and bootup_kernel_stack, which is from
+ * 0x0000.0000.0040.6000 to 0x0000.0000.0040.8000. 
  */
 
        .text
@@ -31,7 +36,7 @@ start:
 _stext:
 stext:
 bootup_user_stack:
-! 0xfffff80000004000
+! 0x0000000000404000
        b       sparc64_boot
         flushw                                 /* Flush register file.      */
 
@@ -41,10 +46,11 @@ bootup_user_stack:
  */
         .global root_flags, ram_flags, root_dev
         .global ramdisk_image, ramdisk_size
+       .globl  silo_args
 
         .ascii  "HdrS"
         .word   LINUX_VERSION_CODE
-        .half   0x0201          /* HdrS version */
+        .half   0x0202          /* HdrS version */
 root_flags:
         .half   1
 root_dev:
@@ -55,7 +61,8 @@ ramdisk_image:
         .word   0
 ramdisk_size:
         .word   0
-        .xword   reboot_command
+        .xword  reboot_command
+       .xword  bootstr_len
 
        /* We must be careful, 32-bit OpenBOOT will get confused if it
         * tries to save away a register window to a 64-bit kernel
@@ -80,26 +87,7 @@ sparc64_boot:
         * Again, typically PROM has left %pil at 13 or similar, and
         * (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate.
          */
-       wrpr    %g0, 0xf, %pil                  /* Interrupts off.           */
-       wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF), %pstate
-
-       /* Check if we are mapped where we expect to be in virtual
-        * memory.  The Solaris /boot elf format bootloader
-        * will peek into our elf header and load us where
-        * we want to be, otherwise we have to re-map.
-        */
-current_pc:
-       rd      %pc, %g3
-       sethi   %uhi(KERNBASE), %g4
-       sllx    %g4, 32, %g4
-
-       /* Check the run time program counter. */
-
-       set     current_pc, %g5
-       add     %g5, %g4, %g5
-       cmp     %g3, %g5
-       be      %xcc, sun4u_init
-        nop
+       wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
 
 create_mappings:
        /* %g5 holds the tlb data */
@@ -136,15 +124,10 @@ create_mappings:
        cmp     %g1, %g2
        be,a,pn %xcc, got_tlbentry
         ldxa   [%l0] ASI_ITLB_DATA_ACCESS, %g1
-       cmp     %l1, (63 << 3)
+       cmp     %l0, (63 << 3)
        blu,pt  %xcc, 1b
         add    %l0, (1 << 3), %l0
 
-boot_failed:
-       /* Debugging 8-) */
-       set     0xdeadbeef, %g1
-       t       0x11
-
 got_tlbentry:
        /* Nops here again, perhaps Cheetah/Blackbird are better behaved... */
        nop
@@ -159,33 +142,73 @@ got_tlbentry:
 
        or      %g5, %g1, %g5           /* Or it into TAG being built.        */
 
+       clr     %l0                     /* TLB entry walker. */
+       sethi   %hi(KERNBASE), %g3      /* 4M lower limit */
+       sethi   %hi(KERNBASE<<1), %g7   /* 8M upper limit */
+       mov     TLB_TAG_ACCESS, %l7
+1:
+       /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
+       ldxa    [%l0] ASI_ITLB_TAG_READ, %g1
+       nop
+       nop
+       nop
+       andn    %g1, %l2, %g1           /* Get vaddr */
+       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                     /* TLB entry walker. */
+1:
+       /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
+       ldxa    [%l0] ASI_DTLB_TAG_READ, %g1
+       nop
+       nop
+       nop
+       andn    %g1, %l2, %g1           /* Get vaddr */
+       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
+
+
        /* PROM never puts any TLB entries into the MMU with the lock bit
-        * set.  So we gladly use tlb entry 63 for KERNBASE, 62 for
-        * boot time locked PROM CIF handler page, we remove the locked
-        * bit for the CIF page in paging_init().
+        * set.  So we gladly use tlb entry 63 for KERNBASE.
         */
-       mov     TLB_TAG_ACCESS, %g3
-       mov     (63 << 3), %g7
-       stxa    %g4, [%g3] ASI_IMMU             /* KERNBASE into TLB TAG        */
-       stxa    %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA            */
-       membar  #Sync
 
-       /* Same for DTLB */
-       stxa    %g4, [%g3] ASI_DMMU             /* KERNBASE into TLB TAG        */
+       sethi   %hi(KERNBASE), %g3
+       mov     (63 << 3), %g7
+       stxa    %g3, [%l7] ASI_DMMU             /* KERNBASE into TLB TAG        */
        stxa    %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA            */
        membar  #Sync
-
-       /* Kill instruction prefetch queues. */
-       flush   %g4
+       stxa    %g3, [%l7] ASI_IMMU             /* KERNBASE into TLB TAG        */
+       stxa    %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA            */
        membar  #Sync
-
-       ba,pt   %xcc, go_to_highmem
+       flush   %g3
+       membar  #Sync
+       ba,pt   %xcc, 1f
         nop
-
-go_to_highmem:
-       /* Now do a non-relative jump so that PC is in high-memory */
+1:
        set     sun4u_init, %g2
-       jmpl     %g2 + %g4, %g0
+       jmpl    %g2 + %g0, %g0
         nop
 
 sun4u_init:
@@ -198,42 +221,16 @@ sun4u_init:
        stxa    %g0, [%g7] ASI_DMMU
        membar  #Sync
 
-       /* The lock bit has to be removed from this page later on, 
-        * but before firing up init we will use PROM a lot, so we
-        * lock it there now...
-        */
-
-       /* Compute PROM CIF interface page TTE. */
-       sethi   %hi(__p1275_loc), %g7
-       or      %g7, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_L), %g7
-       sethi   %uhi(_PAGE_VALID), %g5
-       sethi   %hi(0x8000), %g3
-       sllx    %g5, 32, %g5
-       mov     TLB_TAG_ACCESS, %g6
-       or      %g5, %g7, %g5
-       add     %g5, %g1, %g5                           /* Add in physbase. */
-
-       mov     (62 << 3), %g7                          /* TLB entry 62           */
-       stxa    %g3, [%g6] ASI_IMMU                     /* CIF page into TLB TAG  */
-       stxa    %g5, [%g7] ASI_ITLB_DATA_ACCESS         /* TTE into TLB DATA      */
-       membar  #Sync
-
-       /* Same for DTLB */
-       stxa    %g3, [%g6] ASI_DMMU                     /* CIF page into TLB TAG  */
-       stxa    %g5, [%g7] ASI_DTLB_DATA_ACCESS         /* TTE into TLB DATA      */
-       membar  #Sync
-
-       /* Kill instruction prefetch queues. */
-       flush   %g3
-       membar  #Sync
+       sethi   %uhi(PAGE_OFFSET), %g4
+       sllx    %g4, 32, %g4
 
        /* We are now safely (we hope) in Nucleus context (0), rewrite
         * the KERNBASE TTE's so they no longer have the global bit set.
         * Don't forget to setup TAG_ACCESS first 8-)
         */
        mov     TLB_TAG_ACCESS, %g2
-       stxa    %g4, [%g2] ASI_IMMU
-       stxa    %g4, [%g2] ASI_DMMU
+       stxa    %g3, [%g2] ASI_IMMU
+       stxa    %g3, [%g2] ASI_DMMU
 
        mov     (63 << 3), %g7
        ldxa    [%g7] ASI_ITLB_DATA_ACCESS, %g1
@@ -247,30 +244,22 @@ sun4u_init:
        membar  #Sync
 
        /* Kill instruction prefetch queues. */
-       flush   %g4
+       flush   %g3
        membar  #Sync
 
-       /* Compute the number of windows in this machine
-        * store this in nwindows and nwindowsm1
-        */
-       rdpr    %ver, %g1                       /* Get VERSION register.        */
-       sethi   %hi(nwindows), %g2
-       and     %g1, VERS_MAXWIN, %g5
-       or      %g2,%lo(nwindows),%g2
-       add     %g5, 1, %g6
-       add     %g2, (nwindows - nwindowsm1), %g3
-       stx     %g6, [%g2 + %g4]
-       stx     %g5, [%g3 + %g4]
-
        sethi   %hi(init_task_union), %g6
        or      %g6, %lo(init_task_union), %g6
-       add     %g6, %g4, %g6                   ! g6 usage is fixed as well
        mov     %sp, %l6
        mov     %o4, %l7
 
+#if 0  /* We don't do it like this anymore, but for historical hack value
+        * I leave this snippet here to show how crazy we can be sometimes. 8-)
+        */
+
        /* Setup "Linux Current Register", thanks Sun 8-) */
        wr      %g0, 0x1, %pcr
        wr      %g6, 0x0, %pic
+#endif
 
        mov     1, %g5
        sllx    %g5, (PAGE_SHIFT + 1), %g5
@@ -291,23 +280,19 @@ sun4u_init:
        add     %l1, %l2, %l1
        andn    %l1, %l2, %l1
        add     %l2, 1, %l2
-       add     %l0, %g4, %o0
+       add     %l0, %g0, %o0
 1:
-       clr     %o1
-       sethi   %hi(PAGE_SIZE), %o2
-       or      %o2, %lo(PAGE_SIZE), %o2
-       call    __memset
+       mov     %l2, %o1
+       call    __bzero
         add    %l0, %l2, %l0
        cmp     %l0, %l1
        blu,pt  %xcc, 1b
-        add    %l0, %g4, %o0
+        add    %l0, %g0, %o0
 
        /* Now clear empty_zero_page */
-       clr     %o1
-       sethi   %hi(PAGE_SIZE), %o2
-       or      %o2, %lo(PAGE_SIZE), %o2
-       call    __memset
-        mov    %g4, %o0
+       mov     %l2, %o1
+       call    __bzero
+        mov    %g3, %o0
 
        mov     %l6, %o1                        ! OpenPROM stack
        call    prom_init
@@ -320,36 +305,45 @@ sun4u_init:
 
        .globl  setup_tba
 setup_tba:
+       save    %sp, -160, %sp
+
+       rdpr    %tba, %g7
+       sethi   %hi(prom_tba), %o1
+       or      %o1, %lo(prom_tba), %o1
+       stx     %g7, [%o1]
+
+       /* Setup "Linux" globals 8-) */
+       rdpr    %pstate, %o1
+       mov     %g6, %o2
+       wrpr    %o1, (PSTATE_AG|PSTATE_IE), %pstate
        sethi   %hi(sparc64_ttable_tl0), %g5
-       add     %g5, %g4, %g5
        wrpr    %g5, %tba
+       mov     %o2, %g6
 
        /* Set up MMU globals */
-       rdpr    %pstate, %o1
-       wrpr    %o1, PSTATE_MG, %pstate
+       wrpr    %o1, (PSTATE_MG|PSTATE_IE), %pstate
 
        /* PGD/PMD offset mask, used by TLB miss handlers. */
        sethi   %hi(0x1ff8), %g2
        or      %g2, %lo(0x1ff8), %g2
 
        /* Kernel PGDIR used by TLB miss handlers. */
-       mov     %o0, %g6
+       mov     %i0, %g6
 
        /* To catch bootup bugs, this is user PGDIR for TLB miss handlers. */
        clr     %g7
 
        /* Setup Interrupt globals */
-       wrpr    %o1, PSTATE_IG, %pstate
-       sethi   %uhi(ivector_to_mask), %g4
-       or      %g4, %ulo(ivector_to_mask), %g4
+       wrpr    %o1, (PSTATE_IG|PSTATE_IE), %pstate
        sethi   %hi(ivector_to_mask), %g5
-       or      %g5, %lo(ivector_to_mask), %g5
-       or      %g5, %g4, %g1                   /* IVECTOR table */
+       or      %g5, %lo(ivector_to_mask), %g1  /* IVECTOR table */
        mov     0x40, %g2                       /* INTR data 0 register */
 
-       andn    %o1, PSTATE_IE, %o1
+       /* 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.
+        */
        wrpr    %g0, %g0, %wstate
-       wrpr    %o1, %g0, %pstate
+       wrpr    %o1, PSTATE_IE, %pstate
 
        /* Zap TSB BASE to zero with TSB_size==1. */
        mov     TSB_REG, %o4
@@ -359,8 +353,16 @@ setup_tba:
 
        membar  #Sync
 
-       retl
-        nop
+       sethi   %hi(sparc64_ttable_tl0), %g5
+       call    prom_set_trap_table
+        mov    %g5, %o0
+
+       rdpr    %pstate, %o1
+       or      %o1, PSTATE_IE, %o1
+       wrpr    %o1, 0, %pstate
+
+       ret
+        restore
 
 sparc64_boot_end:
        .skip   0x2000 + _start - sparc64_boot_end
@@ -369,18 +371,21 @@ bootup_user_stack_end:
 bootup_kernel_stack:
        .skip   0x2000
 
-! 0xfffff80000008000
+! 0x0000000000408000
 
 #include "ttable.S"
+#include "etrap.S"
+#include "rtrap.S"
+#include "winfixup.S"
+#include "entry.S"
 
        /* This is just anal retentiveness on my part... */
        .align  16384
 
        .data
        .align  8
-       .globl  nwindows, nwindowsm1 
-nwindows:      .xword  0
-nwindowsm1:    .xword  0
+       .globl  prom_tba
+prom_tba:      .xword  0
        .section        ".fixup",#alloc,#execinstr
        .globl  __ret_efault
 __ret_efault:
index 2f94e910204270e7c18358f70d5bdd1100f1b5d2..390c33517b12a073dc2d2d8cb2e92561d7a03779 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.7 1997/04/10 05:13:01 davem Exp $
+/* $Id: ioport.c,v 1.10 1997/06/30 09:24:02 jj Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -64,13 +64,7 @@ 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 {
-               vaddr = occupy_region(sparc_iobase_vaddr, IOBASE_END,
-                               (offset + len + PAGE_SIZE-1) & PAGE_MASK, PAGE_SIZE, name);
-               if (vaddr == 0) {
-                       /* Usually we cannot see printks in this case. */
-                       prom_printf("alloc_io: cannot occupy %d region\n", len);
-                       prom_halt();
-               }
+               return __va(addr);
        }
 
        base_address = vaddr;
@@ -88,6 +82,9 @@ 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;
+       
+       if (virtual >= PAGE_OFFSET + 0x10000000000UL)
+               return;
 
        release_region(vaddr, plen);
 
index 3c9b1a89e3d7f96ba31cae9ef3b4a9cdb303ba31..6c2225d1da3ccd935293a36706cc7a662120d231 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.13 1997/05/27 07:54:28 davem Exp $
+/* $Id: irq.c,v 1.14 1997/06/24 17:30:26 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -558,6 +558,8 @@ struct sun5_timer {
        volatile u32 limit1, _unused3;
 } *prom_timers;
 
+static u32 prom_limit0, prom_limit1;
+
 static void map_prom_timers(void)
 {
        unsigned int addr[3];
@@ -590,24 +592,39 @@ static void kill_prom_timer(void)
        if(!prom_timers)
                return;
 
+       /* Save them away for later. */
+       prom_limit0 = prom_timers->limit0;
+       prom_limit1 = prom_timers->limit1;
+
        /* Just as in sun4c/sun4m PROM uses timer which ticks at IRQ 14.
         * We turn both off here just to be paranoid.
         */
        prom_timers->limit0 = 0;
        prom_timers->limit1 = 0;
+
+       /* Wheee, eat the interrupt packet too... */
+       __asm__ __volatile__("
+       mov     0x40, %%g2
+       ldxa    [%%g0] %0, %%g1
+       ldxa    [%%g2] %1, %%g1
+       stxa    %%g0, [%%g0] %0
+       membar  #Sync
+"      : /* no outputs */
+       : "i" (ASI_INTR_RECEIVE), "i" (ASI_UDB_INTR_R)
+       : "g1", "g2");
 }
 
-#if 0 /* Unused at this time. -DaveM */
-static void enable_prom_timer(void)
+void enable_prom_timer(void)
 {
        if(!prom_timers)
                return;
 
-       /* Set it to fire off every 10ms. */
-       prom_timers->limit1 = 0xa000270f;
+       /* Set it to whatever was there before. */
+       prom_timers->limit1 = prom_limit1;
        prom_timers->count1 = 0;
+       prom_timers->limit0 = prom_limit0;
+       prom_timers->count0 = 0;
 }
-#endif
 
 __initfunc(void init_IRQ(void))
 {
index 626ad73cb4744c3f352f9d8f7a64529ae9c8e7c1..08ed1bc670ad2bf8a991e51510b4c6d2babb9dd4 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.18 1997/06/13 14:02:42 davem Exp $
+/*  $Id: process.c,v 1.26 1997/07/01 21:15:07 jj Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -137,7 +137,7 @@ void machine_restart(char * cmd)
                prom_reboot(cmd);
        if (*reboot_command)
                prom_reboot(reboot_command);
-       prom_feval ("reset");
+       prom_reboot("");
        panic("Reboot failed!");
 }
 
@@ -146,8 +146,55 @@ void machine_power_off(void)
        machine_halt();
 }
 
-void show_regwindow(struct reg_window *rw)
+static void show_regwindow32(struct pt_regs *regs)
 {
+       struct reg_window32 *rw;
+       struct reg_window32 r_w;
+       unsigned long old_fs;
+       
+       __asm__ __volatile__ ("flushw");
+       rw = (struct reg_window32 *)((long)(unsigned)regs->u_regs[14]);
+       old_fs = get_fs();
+       set_fs (USER_DS);
+       if (copy_from_user (&r_w, rw, sizeof(r_w))) {
+               set_fs (old_fs);
+               return;
+       }
+       rw = &r_w;
+       set_fs (old_fs);                        
+       printk("l0: %016x l1: %016x l2: %016x l3: %016x\n"
+              "l4: %016x l5: %016x l6: %016x l7: %016x\n",
+              rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
+              rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
+       printk("i0: %016x i1: %016x i2: %016x i3: %016x\n"
+              "i4: %016x i5: %016x i6: %016x i7: %016x\n",
+              rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
+              rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
+}
+
+static void show_regwindow(struct pt_regs *regs)
+{
+       struct reg_window *rw;
+       struct reg_window r_w;
+       unsigned long old_fs;
+
+       if ((regs->tstate & TSTATE_PRIV) || !(current->tss.flags & SPARC_FLAG_32BIT)) {
+               __asm__ __volatile__ ("flushw");
+               rw = (struct reg_window *)(regs->u_regs[14] + STACK_BIAS);
+               if (!(regs->tstate & TSTATE_PRIV)) {
+                       old_fs = get_fs();
+                       set_fs (USER_DS);
+                       if (copy_from_user (&r_w, rw, sizeof(r_w))) {
+                               set_fs (old_fs);
+                               return;
+                       }
+                       rw = &r_w;
+                       set_fs (old_fs);                        
+               }
+       } else {
+               show_regwindow32(regs);
+               return;
+       }
        printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n",
               rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3]);
        printk("l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n",
@@ -158,18 +205,6 @@ void show_regwindow(struct reg_window *rw)
               rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
 }
 
-void show_regwindow32(struct reg_window32 *rw)
-{
-       printk("l0: %08x l1: %08x l2: %08x l3: %08x\n"
-              "l4: %08x l5: %08x l6: %08x l7: %08x\n",
-              rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
-              rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
-       printk("i0: %08x i1: %08x i2: %08x i3: %08x\n"
-              "i4: %08x i5: %08x i6: %08x i7: %08x\n",
-              rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
-              rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
-}
-
 void show_stackframe(struct sparc_stackf *sf)
 {
        unsigned long size;
@@ -231,7 +266,7 @@ void show_regs(struct pt_regs * regs)
 #if __MPP__
        printk("CID: %d\n",mpp_cid());
 #endif
-        printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %016lx\n", regs->tstate,
+        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",
               regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
@@ -245,9 +280,7 @@ void show_regs(struct pt_regs * regs)
        printk("o4: %016lx o5: %016lx sp: %016lx ret_pc: %016lx\n",
               regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
               regs->u_regs[15]);
-#if 0
-       show_regwindow((struct reg_window *)(regs->u_regs[14] + STACK_BIAS));
-#endif
+       show_regwindow(regs);
 }
 
 void show_regs32(struct pt_regs32 *regs)
@@ -269,7 +302,6 @@ void show_regs32(struct pt_regs32 *regs)
        printk("o4: %08x o5: %08x sp: %08x ret_pc: %08x\n",
               regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
               regs->u_regs[15]);
-       show_regwindow32((struct reg_window32 *)((unsigned long)regs->u_regs[14]));
 }
 
 void show_thread(struct thread_struct *tss)
@@ -290,46 +322,22 @@ void show_thread(struct thread_struct *tss)
                        continue;
                printk("reg_window[%d]:\n", i);
                printk("stack ptr:         0x%016lx\n", tss->rwbuf_stkptrs[i]);
-               show_regwindow(&tss->reg_window[i]);
        }
        printk("w_saved:           0x%08lx\n", tss->w_saved);
 
-       /* XXX missing: float_regs */
-       printk("fsr:               0x%016lx\n", tss->fsr);
-
        printk("sstk_info.stack:   0x%016lx\n",
                (unsigned long)tss->sstk_info.the_stack);
        printk("sstk_info.status:  0x%016lx\n",
                (unsigned long)tss->sstk_info.cur_status);
-       printk("flags:             0x%016lx\n", tss->flags);
-       printk("current_ds:        0x%016x\n", tss->current_ds);
+       printk("flags:             0x%08x\n", tss->flags);
+       printk("current_ds:        0x%016lx\n", tss->current_ds);
 
        /* XXX missing: core_exec */
 }
 
-/*
- * Free current thread data structures etc..
- */
+/* Free current thread data structures etc.. */
 void exit_thread(void)
 {
-#ifndef __SMP__
-       if(last_task_used_math == current) {
-#else
-       if(current->flags & PF_USEDFPU) {
-#endif
-               fprs_write(FPRS_FEF);
-               if(current->tss.flags & SPARC_FLAG_32BIT)
-                       fpsave32((unsigned long *)&current->tss.float_regs[0],
-                                &current->tss.fsr);
-               else
-                       fpsave((unsigned long *)&current->tss.float_regs[0],
-                              &current->tss.fsr);
-#ifndef __SMP__
-               last_task_used_math = NULL;
-#else
-               current->flags &= ~PF_USEDFPU;
-#endif
-       }
 }
 
 void flush_thread(void)
@@ -338,26 +346,9 @@ void flush_thread(void)
        current->tss.sstk_info.cur_status = 0;
        current->tss.sstk_info.the_stack = 0;
 
-       /* No new signal delivery by default */
+       /* No new signal delivery by default. */
        current->tss.new_signal = 0;
-#ifndef __SMP__
-       if(last_task_used_math == current) {
-#else
-       if(current->flags & PF_USEDFPU) {
-#endif
-               fprs_write(FPRS_FEF);
-               if(current->tss.flags & SPARC_FLAG_32BIT)
-                       fpsave32((unsigned long *)&current->tss.float_regs[0],
-                                &current->tss.fsr);
-               else
-                       fpsave((unsigned long *)&current->tss.float_regs[0],
-                              &current->tss.fsr);
-#ifndef __SMP__
-               last_task_used_math = NULL;
-#else
-               current->flags &= ~PF_USEDFPU;
-#endif
-       }
+       current->flags &= ~PF_USEDFPU;
        
        /* Now, this task is no longer a kernel thread. */
        current->tss.current_ds = USER_DS;
@@ -371,54 +362,7 @@ void flush_thread(void)
        }
        current->tss.ctx = current->mm->context & 0x1fff;
        spitfire_set_secondary_context (current->tss.ctx);
-}
-
-static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src)
-{
-       __asm__ __volatile__("ldd\t[%1 + 0x00], %%g2\n\t"
-                            "ldd\t[%1 + 0x08], %%g4\n\t"
-                            "ldd\t[%1 + 0x10], %%o4\n\t"
-                            "std\t%%g2, [%0 + 0x00]\n\t"
-                            "std\t%%g4, [%0 + 0x08]\n\t"
-                            "std\t%%o4, [%0 + 0x10]\n\t"
-                            "ldd\t[%1 + 0x18], %%g2\n\t"
-                            "ldd\t[%1 + 0x20], %%g4\n\t"
-                            "ldd\t[%1 + 0x28], %%o4\n\t"
-                            "std\t%%g2, [%0 + 0x18]\n\t"
-                            "std\t%%g4, [%0 + 0x20]\n\t"
-                            "std\t%%o4, [%0 + 0x28]\n\t"
-                            "ldd\t[%1 + 0x30], %%g2\n\t"
-                            "ldd\t[%1 + 0x38], %%g4\n\t"
-                            "ldd\t[%1 + 0x40], %%o4\n\t"
-                            "std\t%%g2, [%0 + 0x30]\n\t"
-                            "std\t%%g4, [%0 + 0x38]\n\t"
-                            "ldd\t[%1 + 0x48], %%g2\n\t"
-                            "std\t%%o4, [%0 + 0x40]\n\t"
-                            "std\t%%g2, [%0 + 0x48]\n\t" : :
-                            "r" (dst), "r" (src) :
-                            "g2", "g3", "g4", "g5", "o4", "o5");
-}
-
-static __inline__ void copy_regwin(struct reg_window *dst, struct reg_window *src)
-{
-       __asm__ __volatile__("ldd\t[%1 + 0x00], %%g2\n\t"
-                            "ldd\t[%1 + 0x08], %%g4\n\t"
-                            "ldd\t[%1 + 0x10], %%o4\n\t"
-                            "std\t%%g2, [%0 + 0x00]\n\t"
-                            "std\t%%g4, [%0 + 0x08]\n\t"
-                            "std\t%%o4, [%0 + 0x10]\n\t"
-                            "ldd\t[%1 + 0x18], %%g2\n\t"
-                            "ldd\t[%1 + 0x20], %%g4\n\t"
-                            "ldd\t[%1 + 0x28], %%o4\n\t"
-                            "std\t%%g2, [%0 + 0x18]\n\t"
-                            "std\t%%g4, [%0 + 0x20]\n\t"
-                            "std\t%%o4, [%0 + 0x28]\n\t"
-                            "ldd\t[%1 + 0x30], %%g2\n\t"
-                            "ldd\t[%1 + 0x38], %%g4\n\t"
-                            "std\t%%g2, [%0 + 0x30]\n\t"
-                            "std\t%%g4, [%0 + 0x38]\n\t" : :
-                            "r" (dst), "r" (src) :
-                            "g2", "g3", "g4", "g5", "o4", "o5");
+       __asm__ __volatile__("flush %g6");
 }
 
 static __inline__ struct sparc_stackf *
@@ -462,16 +406,19 @@ void synchronize_user_stack(void)
        flush_user_windows();
        if((window = tp->w_saved) != 0) {
                int winsize = REGWIN_SZ;
+               int bias = 0;
 
 #ifdef DEBUG_WINFIXUPS
                printk("sus(%d", (int)window);
 #endif
                if(tp->flags & SPARC_FLAG_32BIT)
                        winsize = REGWIN32_SZ;
+               else
+                       bias = STACK_BIAS;
 
                window -= 1;
                do {
-                       unsigned long sp = tp->rwbuf_stkptrs[window];
+                       unsigned long sp = (tp->rwbuf_stkptrs[window] + bias);
                        struct reg_window *rwin = &tp->reg_window[window];
 
                        if(!copy_to_user((char *)sp, rwin, winsize)) {
@@ -490,9 +437,12 @@ void fault_in_user_windows(struct pt_regs *regs)
        struct thread_struct *tp = &current->tss;
        unsigned long window;
        int winsize = REGWIN_SZ;
+       int bias = 0;
 
        if(tp->flags & SPARC_FLAG_32BIT)
                winsize = REGWIN32_SZ;
+       else
+               bias = STACK_BIAS;
        flush_user_windows();
        window = tp->w_saved;
 #ifdef DEBUG_WINFIXUPS
@@ -501,7 +451,7 @@ void fault_in_user_windows(struct pt_regs *regs)
        if(window != 0) {
                window -= 1;
                do {
-                       unsigned long sp = tp->rwbuf_stkptrs[window];
+                       unsigned long sp = (tp->rwbuf_stkptrs[window] + bias);
                        struct reg_window *rwin = &tp->reg_window[window];
 
                        if(copy_to_user((char *)sp, rwin, winsize))
@@ -531,51 +481,34 @@ extern void ret_from_syscall(void);
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
                struct task_struct *p, struct pt_regs *regs)
 {
-       struct pt_regs *childregs;
-       struct reg_window *new_stack, *old_stack;
        unsigned long stack_offset;
+       char *child_trap_frame;
+       int tframe_size;
 
-#ifndef __SMP__
-       if(last_task_used_math == current) {
-#else
-       if(current->flags & PF_USEDFPU) {
-#endif
-               fprs_write(FPRS_FEF);
-               fpsave((unsigned long *)&p->tss.float_regs[0], &p->tss.fsr);
-#ifdef __SMP__
-               current->flags &= ~PF_USEDFPU;
+#if 0  /* Now all syscall entries flip off the fpu. */
+       if(regs->tstate & TSTATE_PRIV)
+               regs->fprs = 0;
 #endif
-       }
-
        /* Calculate offset to stack_frame & pt_regs */
-       stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ);
-
-       if(regs->tstate & TSTATE_PRIV)
-               stack_offset -= REGWIN_SZ;
-
-       childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset));
-       *childregs = *regs;
-       new_stack = (((struct reg_window *) childregs) - 1);
-       old_stack = (((struct reg_window *) regs) - 1);
-       *new_stack = *old_stack;
-
-       p->tss.ksp = ((unsigned long) new_stack) - STACK_BIAS;
+       stack_offset = (((PAGE_SIZE << 1) -
+                       ((sizeof(unsigned int)*64) + (2*sizeof(unsigned long)))) &
+               ~(64 - 1)) - (TRACEREG_SZ+REGWIN_SZ);
+       tframe_size = (TRACEREG_SZ + REGWIN_SZ) +
+               (sizeof(unsigned int) * 64) + (2 * sizeof(unsigned long));
+       child_trap_frame = ((char *)p) + stack_offset;
+       memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size);
+       p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
        p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
-       p->tss.kregs = childregs;
-
-       /* Don't look... */
+       p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
        p->tss.cwp = regs->u_regs[UREG_G0];
-
-       /* tss.wstate was copied by do_fork() */
-
        if(regs->tstate & TSTATE_PRIV) {
-               childregs->u_regs[UREG_FP] = p->tss.ksp;
+               p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
                p->tss.flags |= SPARC_FLAG_KTHREAD;
                p->tss.current_ds = KERNEL_DS;
                p->tss.ctx = 0;
-               childregs->u_regs[UREG_G6] = (unsigned long) p;
+               p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
        } else {
-               childregs->u_regs[UREG_FP] = sp;
+               p->tss.kregs->u_regs[UREG_FP] = sp;
                p->tss.flags &= ~SPARC_FLAG_KTHREAD;
                p->tss.current_ds = USER_DS;
                p->tss.ctx = (p->mm->context & 0x1fff);
@@ -590,39 +523,20 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
                         */
                        childstack = (struct sparc_stackf *)sp;
                        parentstack = (struct sparc_stackf *)regs->u_regs[UREG_FP];
-
-#if 0
-                       printk("clone: parent stack:\n");
-                       show_stackframe(parentstack);
-#endif
-
                        childstack = clone_stackframe(childstack, parentstack);
                        if (!childstack)
                                return -EFAULT;
-
-#if 0
-                       printk("clone: child stack:\n");
-                       show_stackframe(childstack);
-#endif
-
                        childregs->u_regs[UREG_FP] = (unsigned long)childstack;
                }
 #endif
        }
 
        /* Set the return value for the child. */
-       childregs->u_regs[UREG_I0] = current->pid;
-       childregs->u_regs[UREG_I1] = 1;
+       p->tss.kregs->u_regs[UREG_I0] = current->pid;
+       p->tss.kregs->u_regs[UREG_I1] = 1;
 
-       /* Set the return value for the parent. */
+       /* Set the second return value for the parent. */
        regs->u_regs[UREG_I1] = 0;
-#if 0
-       printk("CHILD register dump\n");
-       show_regs(childregs);
-       show_regwindow(new_stack);
-       while(1)
-               barrier();
-#endif
        return 0;
 }
 
@@ -684,5 +598,9 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
        error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1],
                          (char **) regs->u_regs[base + UREG_I2], regs);
        putname(filename);
+       if(!error) {
+               fprs_write(0);
+               regs->fprs = 0;
+       }
        return error;
 }
index 24fe052cde8e87d5d6665ccdb3890e3fe3537abe..48c5e17ca5bb89be64c48073a32727a27f48b950 100644 (file)
@@ -100,7 +100,16 @@ static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vm
 /* this is a hack for non-kernel-mapped video buffers and similar */
        flush_cache_page(vma, addr);
        if (MAP_NR(page) < max_mapnr) {
-               *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+               unsigned long pgaddr;
+
+               pgaddr = page + (addr & ~PAGE_MASK);
+               *(unsigned long *) (pgaddr) = data;
+
+               __asm__ __volatile__("
+               membar  #StoreStore
+               flush   %0
+"              : : "r" (pgaddr & ~7) : "memory");
+
                flush_page_to_ram(page);
        }
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
@@ -138,7 +147,16 @@ static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma
 /* this is a hack for non-kernel-mapped video buffers and similar */
        flush_cache_page(vma, addr);
        if (MAP_NR(page) < max_mapnr) {
-               *(unsigned int *) (page + (addr & ~PAGE_MASK)) = data;
+               unsigned long pgaddr;
+
+               pgaddr = page + (addr & ~PAGE_MASK);
+               *(unsigned int *) (pgaddr) = data;
+
+               __asm__ __volatile__("
+               membar  #StoreStore
+               flush   %0
+"              : : "r" (pgaddr & ~7) : "memory");
+
                flush_page_to_ram(page);
        }
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
@@ -570,6 +588,21 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                pt_error_return(regs, ESRCH);
                goto out;
        }
+
+       if(!(child->tss.flags & SPARC_FLAG_32BIT)       &&
+          ((request == PTRACE_READDATA64)              ||
+           (request == PTRACE_WRITEDATA64)             ||
+           (request == PTRACE_READTEXT64)              ||
+           (request == PTRACE_WRITETEXT64)             ||
+           (request == PTRACE_PEEKTEXT64)              ||
+           (request == PTRACE_POKETEXT64)              ||
+           (request == PTRACE_PEEKDATA64)              ||
+           (request == PTRACE_POKEDATA64))) {
+               addr = regs->u_regs[UREG_G2];
+               addr2 = regs->u_regs[UREG_G3];
+               request -= 30; /* wheee... */
+       }
+
        switch(request) {
        case PTRACE_PEEKTEXT: /* read word at location addr. */ 
        case PTRACE_PEEKDATA: {
@@ -641,195 +674,207 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                goto out;
        }
 
-       case PTRACE_GETREGS: 
-               if (current->tss.flags & SPARC_FLAG_32BIT) {
-                       struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
-                       struct pt_regs *cregs = child->tss.kregs;
-                       int rval;
-
-                       if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
-                           __put_user(cregs->tpc, (&pregs->pc)) ||
-                           __put_user(cregs->tnpc, (&pregs->npc)) ||
-                           __put_user(cregs->y, (&pregs->y))) {
+       case PTRACE_GETREGS: {
+               struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
+               struct pt_regs *cregs = child->tss.kregs;
+               int rval;
+
+               if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
+                   __put_user(cregs->tpc, (&pregs->pc)) ||
+                   __put_user(cregs->tnpc, (&pregs->npc)) ||
+                   __put_user(cregs->y, (&pregs->y))) {
+                       pt_error_return(regs, EFAULT);
+                       goto out;
+               }
+               for(rval = 1; rval < 16; rval++)
+                       if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
                                pt_error_return(regs, EFAULT);
                                goto out;
                        }
-                       for(rval = 1; rval < 16; rval++)
-                               if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
-                                       pt_error_return(regs, EFAULT);
-                                       goto out;
-                               }
-                       pt_succ_return(regs, 0);
+               pt_succ_return(regs, 0);
 #ifdef DEBUG_PTRACE
-                       printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
+               printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
 #endif
+               goto out;
+       }
+
+       case PTRACE_GETREGS64: {
+               struct pt_regs *pregs = (struct pt_regs *) addr;
+               struct pt_regs *cregs = child->tss.kregs;
+               int rval;
+
+               if (__put_user(cregs->tstate, (&pregs->tstate)) ||
+                   __put_user(cregs->tpc, (&pregs->tpc)) ||
+                   __put_user(cregs->tnpc, (&pregs->tnpc)) ||
+                   __put_user(cregs->y, (&pregs->y))) {
+                       pt_error_return(regs, EFAULT);
                        goto out;
-               } else {
-                       struct pt_regs *pregs = (struct pt_regs *) addr;
-                       struct pt_regs *cregs = child->tss.kregs;
-                       int rval;
-
-                       if (__put_user(cregs->tstate, (&pregs->tstate)) ||
-                           __put_user(cregs->tpc, (&pregs->tpc)) ||
-                           __put_user(cregs->tnpc, (&pregs->tnpc)) ||
-                           __put_user(cregs->y, (&pregs->y))) {
+               }
+               for(rval = 1; rval < 16; rval++)
+                       if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
                                pt_error_return(regs, EFAULT);
                                goto out;
                        }
-                       for(rval = 1; rval < 16; rval++)
-                               if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
-                                       pt_error_return(regs, EFAULT);
-                                       goto out;
-                               }
-                       pt_succ_return(regs, 0);
+               pt_succ_return(regs, 0);
 #ifdef DEBUG_PTRACE
-                       printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
+               printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
 #endif
+               goto out;
+       }
+
+       case PTRACE_SETREGS: {
+               struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
+               struct pt_regs *cregs = child->tss.kregs;
+               unsigned int psr, pc, npc, y;
+               int i;
+
+               /* Must be careful, tracing process can only set certain
+                * bits in the psr.
+                */
+               if (__get_user(psr, (&pregs->psr)) ||
+                   __get_user(pc, (&pregs->pc)) ||
+                   __get_user(npc, (&pregs->npc)) ||
+                   __get_user(y, (&pregs->y))) {
+                       pt_error_return(regs, EFAULT);
                        goto out;
                }
-
-       case PTRACE_SETREGS: 
-               if (current->tss.flags & SPARC_FLAG_32BIT) {
-                       struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
-                       struct pt_regs *cregs = child->tss.kregs;
-                       unsigned int psr, pc, npc, y;
-                       int i;
-
-                       /* Must be careful, tracing process can only set certain
-                        * bits in the psr.
-                        */
-                       if (__get_user(psr, (&pregs->psr)) ||
-                           __get_user(pc, (&pregs->pc)) ||
-                           __get_user(npc, (&pregs->npc)) ||
-                           __get_user(y, (&pregs->y))) {
+               cregs->tstate &= ~(TSTATE_ICC);
+               cregs->tstate |= psr_to_tstate_icc(psr);
+                       if(!((pc | npc) & 3)) {
+                       cregs->tpc = pc;
+                       cregs->tpc = npc;
+               }
+               cregs->y = y;
+               for(i = 1; i < 16; i++)
+                       if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
                                pt_error_return(regs, EFAULT);
                                goto out;
                        }
-                       cregs->tstate &= ~(TSTATE_ICC);
-                       cregs->tstate |= psr_to_tstate_icc(psr);
-                       if(!((pc | npc) & 3)) {
-                               cregs->tpc = pc;
-                               cregs->tpc = npc;
-                       }
-                       cregs->y = y;
-                       for(i = 1; i < 16; i++)
-                               if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
-                                       pt_error_return(regs, EFAULT);
-                                       goto out;
-                               }
-                       pt_succ_return(regs, 0);
-                       goto out;
-               } else {
-                       struct pt_regs *pregs = (struct pt_regs *) addr;
-                       struct pt_regs *cregs = child->tss.kregs;
-                       unsigned long tstate, tpc, tnpc, y;
-                       int i;
+               pt_succ_return(regs, 0);
+               goto out;
+       }
 
-                       /* Must be careful, tracing process can only set certain
-                        * bits in the psr.
-                        */
-                       if (__get_user(tstate, (&pregs->tstate)) ||
-                           __get_user(tpc, (&pregs->tpc)) ||
-                           __get_user(tnpc, (&pregs->tnpc)) ||
-                           __get_user(y, (&pregs->y))) {
-                               pt_error_return(regs, EFAULT);
-                               goto out;
-                       }
-                       tstate &= (TSTATE_ICC | TSTATE_XCC);
-                       cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
-                       cregs->tstate |= tstate;
-                       if(!((tpc | tnpc) & 3)) {
-                               cregs->tpc = tpc;
-                               cregs->tnpc = tnpc;
-                       }
-                       cregs->y = y;
-                       for(i = 1; i < 16; i++)
-                               if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
-                                       pt_error_return(regs, EFAULT);
-                                       goto out;
-                               }
-                       pt_succ_return(regs, 0);
+       case PTRACE_SETREGS64: {
+               struct pt_regs *pregs = (struct pt_regs *) addr;
+               struct pt_regs *cregs = child->tss.kregs;
+               unsigned long tstate, tpc, tnpc, y;
+               int i;
+
+               /* Must be careful, tracing process can only set certain
+                * bits in the psr.
+                */
+               if (__get_user(tstate, (&pregs->tstate)) ||
+                   __get_user(tpc, (&pregs->tpc)) ||
+                   __get_user(tnpc, (&pregs->tnpc)) ||
+                   __get_user(y, (&pregs->y))) {
+                       pt_error_return(regs, EFAULT);
                        goto out;
                }
-
-       case PTRACE_GETFPREGS: 
-               if (current->tss.flags & SPARC_FLAG_32BIT) {
-                       struct fps {
-                               unsigned int regs[32];
-                               unsigned int fsr;
-                               unsigned int flags;
-                               unsigned int extra;
-                               unsigned int fpqd;
-                               struct fq {
-                                       unsigned int insnaddr;
-                                       unsigned int insn;
-                               } fpq[16];
-                       } *fps = (struct fps *) addr;
-
-                       if (copy_to_user(&fps->regs[0], &child->tss.float_regs[0], (32 * sizeof(unsigned int))) ||
-                           __put_user(child->tss.fsr, (&fps->fsr)) ||
-                           __put_user(0, (&fps->fpqd)) ||
-                           __put_user(0, (&fps->flags)) ||
-                           __put_user(0, (&fps->extra)) ||
-                           clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
+               tstate &= (TSTATE_ICC | TSTATE_XCC);
+               cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
+               cregs->tstate |= tstate;
+               if(!((tpc | tnpc) & 3)) {
+                       cregs->tpc = tpc;
+                       cregs->tnpc = tnpc;
+               }
+               cregs->y = y;
+               for(i = 1; i < 16; i++)
+                       if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
                                pt_error_return(regs, EFAULT);
                                goto out;
                        }
-                       pt_succ_return(regs, 0);
+               pt_succ_return(regs, 0);
+               goto out;
+       }
+
+       case PTRACE_GETFPREGS: {
+               struct fps {
+                       unsigned int regs[32];
+                       unsigned int fsr;
+                       unsigned int flags;
+                       unsigned int extra;
+                       unsigned int fpqd;
+                       struct fq {
+                               unsigned int insnaddr;
+                               unsigned int insn;
+                       } fpq[16];
+               } *fps = (struct fps *) addr;
+               unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1);
+
+               if (copy_to_user(&fps->regs[0], fpregs,
+                                (32 * sizeof(unsigned int))) ||
+                   __put_user(((unsigned int)fpregs[32]), (&fps->fsr)) ||
+                   __put_user(0, (&fps->fpqd)) ||
+                   __put_user(0, (&fps->flags)) ||
+                   __put_user(0, (&fps->extra)) ||
+                   clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
+                       pt_error_return(regs, EFAULT);
                        goto out;
-               } else {
-                       struct fps {
-                               unsigned int regs[64];
-                               unsigned long fsr;
-                       } *fps = (struct fps *) addr;
+               }
+               pt_succ_return(regs, 0);
+               goto out;
+       }
 
-                       if (copy_to_user(&fps->regs[0], &child->tss.float_regs[0], (64 * sizeof(unsigned int))) ||
-                           __put_user(child->tss.fsr, (&fps->fsr))) {
-                               pt_error_return(regs, EFAULT);
-                               goto out;
-                       }
-                       pt_succ_return(regs, 0);
+       case PTRACE_GETFPREGS64: {
+               struct fps {
+                       unsigned int regs[64];
+                       unsigned long fsr;
+               } *fps = (struct fps *) addr;
+               unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1);
+
+               if (copy_to_user(&fps->regs[0], fpregs,
+                                (64 * sizeof(unsigned int))) ||
+                   __put_user(fpregs[32], (&fps->fsr))) {
+                       pt_error_return(regs, EFAULT);
                        goto out;
                }
+               pt_succ_return(regs, 0);
+               goto out;
+       }
 
-       case PTRACE_SETFPREGS:
-               if (current->tss.flags & SPARC_FLAG_32BIT) {
-                       struct fps {
-                               unsigned int regs[32];
-                               unsigned int fsr;
-                               unsigned int flags;
-                               unsigned int extra;
-                               unsigned int fpqd;
-                               struct fq {
-                                       unsigned int insnaddr;
-                                       unsigned int insn;
-                               } fpq[16];
-                       } *fps = (struct fps *) addr;
-                       unsigned fsr;
-
-                       if (copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned int))) ||
-                           __get_user(fsr, (&fps->fsr))) {
-                               pt_error_return(regs, EFAULT);
-                               goto out;
-                       }
-                       child->tss.fsr &= 0xffffffff00000000UL;
-                       child->tss.fsr |= fsr;
-                       pt_succ_return(regs, 0);
+       case PTRACE_SETFPREGS: {
+               struct fps {
+                       unsigned int regs[32];
+                       unsigned int fsr;
+                       unsigned int flags;
+                       unsigned int extra;
+                       unsigned int fpqd;
+                       struct fq {
+                               unsigned int insnaddr;
+                               unsigned int insn;
+                       } fpq[16];
+               } *fps = (struct fps *) addr;
+               unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1);
+               unsigned fsr;
+
+               if (copy_from_user(fpregs, &fps->regs[0],
+                                  (32 * sizeof(unsigned int))) ||
+                   __get_user(fsr, (&fps->fsr))) {
+                       pt_error_return(regs, EFAULT);
                        goto out;
-               } else {
-                       struct fps {
-                               unsigned int regs[64];
-                               unsigned long fsr;
-                       } *fps = (struct fps *) addr;
+               }
+               fpregs[32] &= 0xffffffff00000000UL;
+               fpregs[32] |= fsr;
+               pt_succ_return(regs, 0);
+               goto out;
+       }
 
-                       if (copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (64 * sizeof(unsigned int))) ||
-                           __get_user(child->tss.fsr, (&fps->fsr))) {
-                               pt_error_return(regs, EFAULT);
-                               goto out;
-                       }
-                       pt_succ_return(regs, 0);
+       case PTRACE_SETFPREGS64: {
+               struct fps {
+                       unsigned int regs[64];
+                       unsigned long fsr;
+               } *fps = (struct fps *) addr;
+               unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1);
+
+               if (copy_from_user(fpregs, &fps->regs[0],
+                                  (64 * sizeof(unsigned int))) ||
+                   __get_user(fpregs[32], (&fps->fsr))) {
+                       pt_error_return(regs, EFAULT);
                        goto out;
                }
+               pt_succ_return(regs, 0);
+               goto out;
+       }
 
        case PTRACE_READTEXT:
        case PTRACE_READDATA: {
@@ -1022,7 +1067,10 @@ asmlinkage void syscall_trace(void)
                current->pid, current->exit_code);
 #endif
        if (current->exit_code) {
-               set_bit(current->exit_code + 31, &current->signal);
+               /* spin_lock_irq(&current->sigmask_lock); */
+               current->signal |= (1 << (current->exit_code - 1));
+               /* spin_unlock_irq(&current->sigmask_lock); */
        }
+
        current->exit_code = 0;
 }
index 36999d2a055e5c0729cd7a1c50485dc224358f62..9f087a969a3fb7771a3a50f2cc4aa9ee0512560b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.23 1997/06/16 07:38:41 davem Exp $
+/* $Id: rtrap.S,v 1.28 1997/06/30 10:31:39 jj Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 #include <asm/spitfire.h>
 #include <asm/head.h>
 
-       /* We assume here that this is entered with AG, MG and IG bits
-        * in pstate clear.
-        */
+               .text
+               .align                  32
+               .globl                  rtrap_clr_l6, rtrap
+#define                PTREGS_OFF              (STACK_BIAS + REGWIN_SZ)
+rtrap_clr_l6:  ba,pt                   %xcc, rtrap
+                clr                    %l6
+rtrap:         sethi                   %hi(bh_active), %l2
+               sethi                   %hi(bh_mask), %l1
+               ldx                     [%l2 + %lo(bh_active)], %l4
+               ldx                     [%l1 + %lo(bh_mask)], %l7
 
-       .text
-       .align  32
-       .globl  rtrap_clr_l6, rtrap
-rtrap_clr_l6:
-       ba,pt           %xcc, rtrap
-        clr            %l6
-rtrap: sethi           %hi(bh_active), %l2
-       or              %l2, %lo(bh_active), %l2
-       sethi           %hi(bh_mask), %l1
-       or              %l1, %lo(bh_mask), %l1
-       ldx             [%l2 + %g4], %l4
-       ldx             [%l1 + %g4], %l7
+               andcc                   %l4, %l7, %g0
+               be,pt                   %xcc, 2f
+                nop
+               call                    do_bottom_half
+                nop
+2:             ldx                     [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+               sethi                   %hi(0xf << 20), %l4
+               andcc                   %l1, TSTATE_PRIV, %l3
 
-       andcc           %l4, %l7, %g0
-       be,pt           %xcc, 2f
-        nop
-       call            do_bottom_half
-        nop
-2:     ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1
-       sethi           %hi(0xf << 20), %l4
-       andcc           %l1, TSTATE_PRIV, %l3
+               and                     %l1, %l4, %l4
+               rdpr                    %pstate, %l7
+               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
 
-       and             %l1, %l4, %l4
-       rdpr            %pstate, %l7
-       andn            %l1, %l4, %l1
-       be,pt           %icc, to_user
-        andn           %l7, PSTATE_IE, %l7
-3:     ldx             [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2
+               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
+               mov                     %g6, %l6
+               ldx                     [%sp + PTREGS_OFF + PT_V9_G4], %g4
+               ldx                     [%sp + PTREGS_OFF + PT_V9_G5], %g5
+               ldx                     [%sp + PTREGS_OFF + PT_V9_G6], %g6
+               ldx                     [%sp + PTREGS_OFF + PT_V9_G7], %g7
 
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7
-       wrpr            %l7, PSTATE_AG, %pstate
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1
+               wrpr                    %l7, PSTATE_AG, %pstate
+               ldx                     [%sp + PTREGS_OFF + PT_V9_I0], %i0
+               ldx                     [%sp + PTREGS_OFF + PT_V9_I1], %i1
+               ldx                     [%sp + PTREGS_OFF + PT_V9_I2], %i2
+               ldx                     [%sp + PTREGS_OFF + PT_V9_I3], %i3
+               ldx                     [%sp + PTREGS_OFF + PT_V9_I4], %i4
+               ldx                     [%sp + PTREGS_OFF + PT_V9_I5], %i5
+               ldx                     [%sp + PTREGS_OFF + PT_V9_I6], %i6
 
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2
+               ldx                     [%sp + PTREGS_OFF + PT_V9_I7], %i7
+               ld                      [%sp + PTREGS_OFF + PT_V9_Y], %o3
+               ldx                     [%sp + PTREGS_OFF + PT_V9_TPC], %l2
+               ldx                     [%sp + PTREGS_OFF + PT_V9_TNPC], %o2
+               wr                      %o3, %g0, %y
+               srl                     %l4, 20, %l4
+               wrpr                    %l4, 0x0, %pil
+               wrpr                    %g0, 0x1, %tl
 
-       ldx             [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2
-       wr              %o3, %g0, %y
-       srl             %l4, 20, %l4
-       wrpr            %l4, 0x0, %pil
-       wrpr            %g0, 0x1, %tl
-       wrpr            %l1, %g0, %tstate
-       wrpr            %l2, %g0, %tpc
-       mov             PRIMARY_CONTEXT, %l7
+               wrpr                    %l1, %g0, %tstate
+               wrpr                    %l2, %g0, %tpc
+               mov                     PRIMARY_CONTEXT, %l7
+               brnz,pn                 %l3, kern_rtt
+                wrpr                   %o2, %g0, %tnpc
+               stxa                    %l0, [%l7] ASI_DMMU
+               flush                   %l6
+               rdpr                    %wstate, %l1
 
-       wrpr            %o2, %g0, %tnpc
-       brnz,a,pn       %l3, 1f
-        restore
-       sethi           %uhi(KERNBASE), %l5
-       sllx            %l5, 32, %l5
-       stxa            %l0, [%l7] ASI_DMMU
-       flush           %l5
-       rdpr            %wstate, %l1
+               rdpr                    %otherwin, %l2
+               srl                     %l1, 3, %l1
+               wrpr                    %l2, %g0, %canrestore
+               wrpr                    %l1, %g0, %wstate
+               wrpr                    %g0, %g0, %otherwin
+               restore
+               rdpr                    %canrestore, %g1
+               wrpr                    %g1, 0x0, %cleanwin
 
-       rdpr            %otherwin, %l2
-       srl             %l1, 3, %l1
-       wrpr            %l2, %g0, %canrestore
-       wrpr            %l1, %g0, %wstate
-       wrpr            %g0, %g0, %otherwin
-       restore
-       rdpr            %canrestore, %g1
-       wrpr            %g1, 0x0, %cleanwin
+               retry
+kern_rtt:      restore
+               retry
+to_user:       sethi                   %hi(need_resched), %l0
+               ld                      [%l0 + %lo(need_resched)], %l0
+               wrpr                    %l7, PSTATE_IE, %pstate
+               brz,pt                  %l0, check_signal
+                ldx                    [%g6 + AOFF_task_signal], %l0
 
-1:     retry
-to_user:
-       sethi   %hi(need_resched), %l0
-       or      %l0, %lo(need_resched), %l0
-       ld      [%l0 + %g4], %l0
-       wrpr    %l7, PSTATE_IE, %pstate
-       brz,pt  %l0, check_signal
-        ldx    [%g6 + AOFF_task_signal], %l0
-       nop
+               call                    schedule
+                nop
+               ldx                     [%g6 + AOFF_task_signal], %l0
+               nop
+check_signal:  ldx                     [%g6 + AOFF_task_blocked], %o0
+               andncc                  %l0, %o0, %g0
+               be,pt                   %xcc, check_user_wins
+                ldx                    [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
 
-       call    schedule
-        nop
-       ba,pt   %xcc, check_signal
-        ldx    [%g6 + AOFF_task_signal], %l0
-check_signal:
-       ldx     [%g6 + AOFF_task_blocked], %o0
-       andncc  %l0, %o0, %g0
-       be,a,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
+               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, 3b
-        nop
+               brz,pt                  %o2, rt_continue
+                nop
+
+               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
+
+               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
+               membar                  #Sync
 
-       call    fault_in_user_windows
-        add    %sp, STACK_BIAS + REGWIN_SZ, %o0
-       ba,a,pt %xcc, 3b
-       nop
-       nop
-       nop
-       nop
-       nop
+               b,pt                    %xcc, rt_after_fpu
+                wr                     %g3, 0, %gsr
+#undef PTREGS_OFF
index 832d3b97f9c779002b9f0a5203f9d187c1d9fafc..096d93f5a2f9d3bbba46f8689950497906ad5c13 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.7 1997/05/20 07:58:56 jj Exp $
+/*  $Id: setup.c,v 1.9 1997/07/05 09:52:29 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -62,7 +62,6 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
  */
 
 extern unsigned long sparc64_ttable_tl0;
-extern void breakpoint(void);
 #if CONFIG_SUN_CONSOLE
 extern void console_restore_palette(void);
 #endif
@@ -108,23 +107,13 @@ static int console_fb = 0;
 #endif
 static unsigned long memory_size = 0;
 
+/* XXX Implement this at some point... */
 void kernel_enter_debugger(void)
 {
-#if 0
-       if (boot_flags & BOOTME_KGDB) {
-               printk("KGDB: Entered\n");
-               breakpoint();
-       }
-#endif
 }
 
 int obp_system_intr(void)
 {
-       if (boot_flags & BOOTME_KGDB) {
-               printk("KGDB: system interrupted\n");
-               breakpoint();
-               return 1;
-       }
        if (boot_flags & BOOTME_DEBUG) {
                printk("OBP: system interrupted\n");
                prom_halt();
@@ -148,7 +137,7 @@ __initfunc(static void process_switch(char c))
                break;
        case 'h':
                prom_printf("boot_flags_init: Halt!\n");
-               halt();
+               prom_halt();
                break;
        default:
                printk("Unknown boot switch (-%c)\n", c);
@@ -266,23 +255,9 @@ __initfunc(void setup_arch(char **cmdline_p,
        *cmdline_p = prom_getbootargs();
        strcpy(saved_command_line, *cmdline_p);
 
-       prom_printf("BOOT: args[%s] saved[%s]\n", *cmdline_p, saved_command_line);
-
        printk("ARCH: SUN4U\n");
 
        boot_flags_init(*cmdline_p);
-#if 0  
-       if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
-          ((*(short *)linux_dbvec) != -1)) {
-               printk("Booted under KADB. Syncing trap table.\n");
-               (*(linux_dbvec->teach_debugger))();
-       }
-       if((boot_flags & BOOTME_KGDB)) {
-               set_debug_traps();
-               prom_printf ("Breakpoint!\n");
-               breakpoint();
-       }
-#endif 
 
        idprom_init();
        total = prom_probe_memory();
@@ -424,7 +399,11 @@ extern char *mmu_info(void);
 
 int get_cpuinfo(char *buffer)
 {
-       int cpuid=get_cpuid();
+#ifndef __SMP__
+       int cpuid=0;
+#else
+#error SMP not supported on sparc64 yet
+#endif
 
        return sprintf(buffer, "cpu\t\t: %s\n"
             "fpu\t\t: %s\n"
index f1e02382bf4aae8128cd8cf78498e6a5f1228b9b..c0f0714962b89ff9e26db328e157aa7f0c8d8e09 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.7 1997/06/16 06:49:59 davem Exp $
+/*  $Id: signal.c,v 1.17 1997/07/05 09:52:31 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -8,6 +8,7 @@
  *  Copyright (C) 1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
@@ -23,6 +24,7 @@
 #include <asm/svr4.h>
 #include <asm/pgtable.h>
 #include <asm/fpumacro.h>
+#include <asm/uctx.h>
 #include <asm/smp_lock.h>
 
 #define _S(nr) (1<<((nr)-1))
@@ -38,6 +40,124 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
 /* This turned off for production... */
 /* #define DEBUG_SIGNALS 1 */
 
+/* {set, get}context() needed for 64-bit SparcLinux userland. */
+asmlinkage void sparc64_set_context(struct pt_regs *regs)
+{
+       struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0];
+       struct thread_struct *tp = &current->tss;
+       mc_gregset_t *grp;
+       unsigned long pc, npc, tstate;
+       unsigned long fp, i7;
+       unsigned char fenab;
+
+       __asm__ __volatile__("flushw");
+       if(tp->w_saved                                          ||
+          (((unsigned long)ucp) & (sizeof(unsigned long)-1))   ||
+          (!__access_ok((unsigned long)ucp, sizeof(*ucp))))
+               do_exit(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);
+       if(regs->u_regs[UREG_I1]) {
+               __get_user(current->blocked, &ucp->uc_sigmask);
+               current->blocked &= _BLOCKABLE;
+       }
+       regs->tpc = pc;
+       regs->tnpc = npc;
+       __get_user(regs->y, &((*grp)[MC_Y]));
+       __get_user(tstate, &((*grp)[MC_Y]));
+       regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
+       regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC));
+       __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1]));
+       __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2]));
+       __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3]));
+       __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4]));
+       __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5]));
+       __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6]));
+       __get_user(regs->u_regs[UREG_G7], (&(*grp)[MC_G7]));
+       __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0]));
+       __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1]));
+       __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2]));
+       __get_user(regs->u_regs[UREG_I3], (&(*grp)[MC_O3]));
+       __get_user(regs->u_regs[UREG_I4], (&(*grp)[MC_O4]));
+       __get_user(regs->u_regs[UREG_I5], (&(*grp)[MC_O5]));
+       __get_user(regs->u_regs[UREG_I6], (&(*grp)[MC_O6]));
+       __get_user(regs->u_regs[UREG_I7], (&(*grp)[MC_O7]));
+
+       __get_user(fp, &(ucp->uc_mcontext.mc_fp));
+       __get_user(i7, &(ucp->uc_mcontext.mc_i7));
+       __put_user(fp, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6])));
+       __put_user(i7, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7])));
+
+       __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));
+               __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;
+       }
+}
+
+asmlinkage void sparc64_get_context(struct pt_regs *regs)
+{
+       struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0];
+       struct thread_struct *tp = &current->tss;
+       mc_gregset_t *grp;
+       mcontext_t *mcp;
+       unsigned long fp, i7;
+       unsigned char fenab = (current->flags & PF_USEDFPU);
+
+       synchronize_user_stack();
+       if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
+               do_exit(SIGSEGV);
+       mcp = &ucp->uc_mcontext;
+       grp = &mcp->mc_gregs;
+
+       /* Skip over the trap instruction, first. */
+       regs->tpc   = regs->tnpc;
+       regs->tnpc += 4;
+
+       __put_user(current->blocked, &ucp->uc_sigmask);
+       __put_user(regs->tstate, &((*grp)[MC_TSTATE]));
+       __put_user(regs->tpc, &((*grp)[MC_PC]));
+       __put_user(regs->tnpc, &((*grp)[MC_NPC]));
+       __put_user(regs->y, &((*grp)[MC_Y]));
+       __put_user(regs->u_regs[UREG_G1], &((*grp)[MC_G1]));
+       __put_user(regs->u_regs[UREG_G2], &((*grp)[MC_G2]));
+       __put_user(regs->u_regs[UREG_G3], &((*grp)[MC_G3]));
+       __put_user(regs->u_regs[UREG_G4], &((*grp)[MC_G4]));
+       __put_user(regs->u_regs[UREG_G5], &((*grp)[MC_G5]));
+       __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G6]));
+       __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G7]));
+       __put_user(regs->u_regs[UREG_I0], &((*grp)[MC_O0]));
+       __put_user(regs->u_regs[UREG_I1], &((*grp)[MC_O1]));
+       __put_user(regs->u_regs[UREG_I2], &((*grp)[MC_O2]));
+       __put_user(regs->u_regs[UREG_I3], &((*grp)[MC_O3]));
+       __put_user(regs->u_regs[UREG_I4], &((*grp)[MC_O4]));
+       __put_user(regs->u_regs[UREG_I5], &((*grp)[MC_O5]));
+       __put_user(regs->u_regs[UREG_I6], &((*grp)[MC_O6]));
+       __put_user(regs->u_regs[UREG_I7], &((*grp)[MC_O7]));
+
+       __get_user(fp, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6])));
+       __get_user(i7, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7])));
+       __put_user(fp, &(mcp->mc_fp));
+       __put_user(i7, &(mcp->mc_i7));
+
+       __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));
+               __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));
+       }
+}
+
 /* 
  * The new signal frame, intended to be used for Linux applications only
  * (we have enough in there to work with clone).
@@ -65,7 +185,8 @@ asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs)
 
 #ifdef CONFIG_SPARC32_COMPAT
        if (current->tss.flags & SPARC_FLAG_32BIT) {
-               extern asmlinkage void _sigpause32_common(unsigned int, struct pt_regs *);
+               extern asmlinkage void _sigpause32_common(unsigned int,
+                                                         struct pt_regs *);
                _sigpause32_common(set, regs);
                return;
        }
@@ -111,22 +232,12 @@ asmlinkage void do_sigsuspend(struct pt_regs *regs)
 static inline void
 restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
-#ifdef __SMP__
-       if (current->flags & PF_USEDFPU)
-               regs->tstate &= ~(TSTATE_PEF);
-#else
-       if (current == last_task_used_math) {
-               last_task_used_math = 0;
-               regs->tstate &= ~(TSTATE_PEF);
-       }
-#endif
-       current->used_math = 1;
-       current->flags &= ~PF_USEDFPU;
-
-       copy_from_user(&current->tss.float_regs[0],
-                      &fpu->si_float_regs[0],
+       unsigned long *fpregs = (unsigned long *)(regs+1);
+       copy_from_user(fpregs, &fpu->si_float_regs[0],
                       (sizeof(unsigned int) * 64));
-       __get_user(current->tss.fsr, &fpu->si_fsr);
+       __get_user(fpregs[32], &fpu->si_fsr);
+       __get_user(fpregs[33], &fpu->si_gsr);
+       regs->fprs = FPRS_FEF;
 }
 
 void do_sigreturn(struct pt_regs *regs)
@@ -139,8 +250,7 @@ void do_sigreturn(struct pt_regs *regs)
 #ifdef CONFIG_SPARC32_COMPAT
        if (current->tss.flags & SPARC_FLAG_32BIT) {
                extern asmlinkage void do_sigreturn32(struct pt_regs *);
-               do_sigreturn32(regs);
-               return;
+               return do_sigreturn32(regs);
        }
 #endif 
        synchronize_user_stack ();
@@ -167,9 +277,9 @@ void do_sigreturn(struct pt_regs *regs)
        __get_user(tstate, &sf->info.si_regs.tstate);
        copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs));
 
-       /* User can only change condition codes and FPU enabling in %tstate. */
-       regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
-       regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_PEF));
+       /* User can only change condition codes in %tstate. */
+       regs->tstate &= ~(TSTATE_ICC);
+       regs->tstate |= (tstate & TSTATE_ICC);
 
        __get_user(fpu_save, &sf->fpu_save);
        if (fpu_save)
@@ -193,27 +303,12 @@ static int invalid_frame_pointer(void *fp, int fplen)
 static inline void
 save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
-#ifdef __SMP__
-       if (current->flags & PF_USEDFPU) {
-               fprs_write(FPRS_FEF);
-               fpsave((unsigned long *)&current->tss.float_regs[0],
-                      &current->tss.fsr);
-               regs->tstate &= ~(TSTATE_PEF);
-               current->flags &= ~(PF_USEDFPU);
-       }
-#else
-       if (current == last_task_used_math) {
-               fprs_write(FPRS_FEF);
-               fpsave((unsigned long *)&current->tss.float_regs[0],
-                      &current->tss.fsr);
-               last_task_used_math = 0;
-               regs->tstate &= ~(TSTATE_PEF);
-       }
-#endif
-       copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+       unsigned long *fpregs = (unsigned long *)(regs+1);
+       copy_to_user(&fpu->si_float_regs[0], fpregs,
                     (sizeof(unsigned int) * 64));
-       __put_user(current->tss.fsr, &fpu->si_fsr);
-       current->used_math = 0;
+       __put_user(fpregs[32], &fpu->si_fsr);
+       __put_user(fpregs[33], &fpu->si_gsr);
+       regs->fprs = 0;
 }
 
 static inline void
@@ -228,7 +323,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->used_math)
+       if (!(current->flags & PF_USEDFPU))
                sigframe_size -= sizeof(__siginfo_fpu_t);
 
        sf = (struct new_signal_frame *)
@@ -249,7 +344,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->used_math) {
+       if (current->flags & PF_USEDFPU) {
                save_fpu_state(regs, &sf->fpu_state);
                __put_user((u64)&sf->fpu_state, &sf->fpu_save);
        } else {
@@ -277,15 +372,22 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
        regs->tnpc = (regs->tpc + 4);
 
        /* Flush instruction space. */
-       __asm__ __volatile__("
-       membar          #StoreStore
-       stxa            %%g0, [%0] %2
-       stxa            %%g0, [%1] %2
-       flush           %%g4
-       " : /* no outputs */
-         : "r" (((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)),
-           "r" ((((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)) + PAGE_SIZE),
-           "i" (ASI_IC_TAG));
+       {
+               unsigned long address = ((unsigned long)&(sf->insns[0]));
+               pgd_t *pgdp = pgd_offset(current->mm, address);
+               pmd_t *pmdp = pmd_offset(pgdp, address);
+               pte_t *ptep = pte_offset(pmdp, address);
+
+               if(pte_present(*ptep)) {
+                       unsigned long page = pte_page(*ptep);
+
+                       __asm__ __volatile__("
+                       membar  #StoreStore
+                       flush   %0 + %1"
+                       : : "r" (page), "r" (address & (PAGE_SIZE - 1))
+                       : "memory");
+               }
+       }
 }
 
 static inline void handle_signal(unsigned long signr, struct sigaction *sa,
index c0454658b53a0251ba1179ece767b4223cefe73f..1fe5cbaafb0529027eef2b35d25a1ebf53ced185 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.13 1997/06/01 05:46:09 davem Exp $
+/*  $Id: signal32.c,v 1.23 1997/07/05 07:09:15 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -67,13 +67,12 @@ struct signal_sframe32 {
  * (we have enough in there to work with clone).
  * All the interesting bits are in the info field.
  */
-
 struct new_signal_frame32 {
        struct sparc_stackf32   ss;
        __siginfo32_t           info;
        /* __siginfo_fpu32_t * */ u32 fpu_save;
        unsigned int            insns [2];
-       __siginfo_fpu32_t       fpu_state;
+       __siginfo_fpu_t         fpu_state;
 };
 
 /* Align macros */
@@ -115,25 +114,12 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs)
        }
 }
 
-static inline void
-restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
+static inline void restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
-#ifdef __SMP__
-       if (current->flags & PF_USEDFPU)
-               regs->tstate &= ~(TSTATE_PEF);
-#else
-       if (current == last_task_used_math) {
-               last_task_used_math = 0;
-               regs->tstate &= ~(TSTATE_PEF);
-       }
-#endif
-       current->used_math = 1;
-       current->flags &= ~PF_USEDFPU;
-
-       copy_from_user(&current->tss.float_regs[0],
-                      &fpu->si_float_regs[0],
-                      (sizeof(unsigned int) * 32));
-       __get_user(current->tss.fsr, &fpu->si_fsr);
+       unsigned long *fpregs = (unsigned long *)(regs + 1);
+       copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 64));
+       __get_user(fpregs[32], &fpu->si_fsr);
+       __get_user(fpregs[33], &fpu->si_gsr);
 }
 
 void do_new_sigreturn32(struct pt_regs *regs)
@@ -142,6 +128,7 @@ void do_new_sigreturn32(struct pt_regs *regs)
        unsigned int psr;
        unsigned pc, npc, fpu_save, mask;
        
+       regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
        sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
 
        /* 1. Make sure we are not getting garbage from the user */
@@ -178,12 +165,12 @@ void do_new_sigreturn32(struct pt_regs *regs)
        __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]);
        __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]);
 
-       /* User can only change condition codes and FPU enabling in %tstate. */
-       regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
+       /* User can only change condition codes in %tstate. */
+       regs->tstate &= ~(TSTATE_ICC);
        regs->tstate |= psr_to_tstate_icc(psr);
 
        if (psr & PSR_EF)
-               regs->tstate |= TSTATE_PEF;
+               regs->fprs = FPRS_FEF;
 
        __get_user(fpu_save, &sf->fpu_save);
        if (fpu_save)
@@ -206,7 +193,8 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
        if (current->tss.new_signal)
                return do_new_sigreturn32(regs);
 
-       scptr = (struct sigcontext32 *) regs->u_regs[UREG_I0];
+       scptr = (struct sigcontext32 *)
+               (regs->u_regs[UREG_I0] & 0x00000000ffffffffUL);
        /* Check sanity of the user arg. */
        if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
           (((unsigned long) scptr) & 3))
@@ -260,6 +248,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        int i;
 
        synchronize_user_stack();
+       regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
        sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP];
        sframep = (struct signal_sframe32 *) (((unsigned long) sframep)-SF_ALIGNEDSZ);
        if (invalid_frame_pointer (sframep, sizeof(*sframep))){
@@ -285,6 +274,8 @@ 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)
+               psr |= PSR_EF;
        __put_user(psr, &sc->sigc_psr);
        __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
        __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
@@ -329,35 +320,17 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
 }
 
 
-static inline void
-save_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
+static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
-#ifdef __SMP__
-       if (current->flags & PF_USEDFPU) {
-               fprs_write(FPRS_FEF);
-               fpsave32((unsigned long *)&current->tss.float_regs[0],
-                        &current->tss.fsr);
-               regs->tstate &= ~(TSTATE_PEF);
-               current->flags &= ~(PF_USEDFPU);
-       }
-#else
-       if (current == last_task_used_math) {
-               fprs_write(FPRS_FEF);
-               fpsave32((unsigned long *)&current->tss.float_regs[0],
-                        &current->tss.fsr);
-               last_task_used_math = 0;
-               regs->tstate &= ~(TSTATE_PEF);
-       }
-#endif
-       copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
-                    (sizeof(unsigned int) * 32));
-       __put_user(current->tss.fsr, &fpu->si_fsr);
-       current->used_math = 0;
+       unsigned long *fpregs = (unsigned long *)(regs+1);
+       copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 64));
+       __put_user(fpregs[32], &fpu->si_fsr);
+       __put_user(fpregs[33], &fpu->si_gsr);
+       regs->fprs = 0;
 }
 
-static inline void
-new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
-                 int signo, unsigned long oldmask)
+static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
+                                    int signo, unsigned long oldmask)
 {
        struct new_signal_frame32 *sf;
        int sigframe_size;
@@ -367,19 +340,26 @@ 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->used_math)
-               sigframe_size -= sizeof(__siginfo_fpu32_t);
+       if (!(current->flags & PF_USEDFPU))
+               sigframe_size -= sizeof(__siginfo_fpu_t);
 
+       regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
        sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size);
        
        if (invalid_frame_pointer (sf, sigframe_size)) {
+#ifdef DEBUG_SIGNALS
+               printk("new_setup_frame32(%s:%d): invalid_frame_pointer(%p, %d)\n",
+                      current->comm, current->pid, sf, sigframe_size);
+#endif
                lock_kernel ();
                do_exit(SIGILL);
        }
 
        if (current->tss.w_saved != 0) {
+#ifdef DEBUG_SIGNALS
                printk ("%s[%d]: Invalid user stack frame for "
                        "signal delivery.\n", current->comm, current->pid);
+#endif
                lock_kernel ();
                do_exit (SIGILL);
        }
@@ -389,11 +369,13 @@ 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)
+               psr |= PSR_EF;
        __put_user(psr, &sf->info.si_regs.psr);
        for (i = 0; i < 16; i++)
                __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
 
-       if (current->used_math) {
+       if (psr & PSR_EF) {
                save_fpu_state32(regs, &sf->fpu_state);
                __put_user((u64)&sf->fpu_state, &sf->fpu_save);
        } else {
@@ -425,15 +407,22 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
        regs->tnpc = (regs->tpc + 4);
 
        /* Flush instruction space. */
-       __asm__ __volatile__("
-       membar          #StoreStore
-       stxa            %%g0, [%0] %2
-       stxa            %%g0, [%1] %2
-       flush           %%g4
-       " : /* no outputs */
-         : "r" (((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)),
-           "r" ((((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)) + PAGE_SIZE),
-           "i" (ASI_IC_TAG));
+       {
+               unsigned long address = ((unsigned long)&(sf->insns[0]));
+               pgd_t *pgdp = pgd_offset(current->mm, address);
+               pmd_t *pmdp = pmd_offset(pgdp, address);
+               pte_t *ptep = pte_offset(pmdp, address);
+
+               if(pte_present(*ptep)) {
+                       unsigned long page = pte_page(*ptep);
+
+                       __asm__ __volatile__("
+                       membar  #StoreStore
+                       flush   %0 + %1"
+                       : : "r" (page), "r" (address & (PAGE_SIZE - 1))
+                       : "memory");
+               }
+       }
 }
 
 /* Setup a Solaris stack frame */
@@ -454,6 +443,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        int i;
 
        synchronize_user_stack();
+       regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
        sfp = (svr4_signal_frame_t *) regs->u_regs[UREG_FP] - REGWIN_SZ;
        sfp = (svr4_signal_frame_t *) (((unsigned long) sfp)-SVR4_SF_ALIGNED);
 
@@ -485,6 +475,8 @@ 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)
+               psr |= PSR_EF;
        __put_user(psr, &((*gr) [SVR4_PSR]));
        __put_user(regs->y, &((*gr) [SVR4_Y]));
        
@@ -546,7 +538,8 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
 #endif
        /* Arguments passed to signal handler */
        if (regs->u_regs [14]){
-               struct reg_window32 *rw = (struct reg_window32 *) regs->u_regs [14];
+               struct reg_window32 *rw = (struct reg_window32 *)
+                       (regs->u_regs [14] & 0x00000000ffffffffUL);
 
                __put_user(signr, &rw->ins [0]);
                __put_user((u64)si, &rw->ins [1]);
@@ -583,7 +576,9 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
        /* Store registers */
        __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), &uc->mcontext.greg [SVR4_PSR]);
+       __put_user((tstate_to_psr(regs->tstate) |
+                   ((current->flags & PF_USEDFPU) ? PSR_EF : 0)),
+                  &uc->mcontext.greg [SVR4_PSR]);
         __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
        
        /* Copy g [1..7] and o [0..7] registers */
@@ -650,12 +645,14 @@ 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(psr & PSR_EF)
+               regs->fprs = FPRS_FEF;
 
        /* Restore g[1..7] and o[0..7] registers */
        for (i = 0; i < 7; i++)
-               __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+               __get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
        for (i = 0; i < 8; i++)
-               __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
+               __get_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
 
        return -EINTR;
 }
@@ -805,9 +802,10 @@ struct sigstack32 {
        int cur_status;
 };
 
-asmlinkage int
-sys32_sigstack(struct sigstack32 *ssptr, struct sigstack32 *ossptr)
+asmlinkage int sys32_sigstack(u32 u_ssptr, u32 u_ossptr)
 {
+       struct sigstack32 *ssptr = (struct sigstack32 *)((unsigned long)(u_ssptr));
+       struct sigstack32 *ossptr = (struct sigstack32 *)((unsigned long)(u_ossptr));
        int ret = -EFAULT;
 
        lock_kernel();
index 91426c814f2164992311d3a0b65dfc5eba8bb3db..0a32bc093445eda0832e2de6ec5a14672dbbca70 100644 (file)
@@ -1,5 +1,5 @@
-/* $Id: sparc64_ksyms.c,v 1.4 1997/04/14 17:04:43 jj Exp $
- * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
+/* $Id: sparc64_ksyms.c,v 1.8 1997/07/07 04:58:14 davem Exp $
+ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
@@ -38,19 +38,17 @@ struct poll {
        short revents;
 };
 
-extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *);
-extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *);
 extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
                                unsigned long, unsigned long, unsigned long);
 void _sigpause_common (unsigned int set, struct pt_regs *);
-extern void __copy_1page(void *, const void *);
-extern void *bzero_1page(void *);
+extern void *__bzero_1page(void *);
 extern void *__bzero(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 void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
@@ -75,6 +73,8 @@ EXPORT_SYMBOL(klock_info);
 EXPORT_SYMBOL_PRIVATE(_lock_kernel);
 EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
 
+EXPORT_SYMBOL_PRIVATE(flushw_user);
+
 EXPORT_SYMBOL(mstk48t02_regs);
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
@@ -99,8 +99,6 @@ EXPORT_SYMBOL(dma_chain);
 #endif
 
 /* Solaris/SunOS binary compatibility */
-EXPORT_SYMBOL(svr4_setcontext);
-EXPORT_SYMBOL(svr4_getcontext);
 EXPORT_SYMBOL(_sigpause_common);
 EXPORT_SYMBOL(sunos_mmap);
 
@@ -119,7 +117,7 @@ EXPORT_SYMBOL(prom_getproplen);
 EXPORT_SYMBOL(prom_getproperty);
 EXPORT_SYMBOL(prom_node_has_property);
 EXPORT_SYMBOL(prom_setprop);
-EXPORT_SYMBOL(prom_getbootargs);
+EXPORT_SYMBOL(saved_command_line);
 EXPORT_SYMBOL(prom_getname);
 EXPORT_SYMBOL(prom_feval);
 EXPORT_SYMBOL(prom_getstring);
@@ -148,10 +146,9 @@ EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strspn);
 
 /* Special internal versions of library functions. */
-EXPORT_SYMBOL(__copy_1page);
 EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memset);
-EXPORT_SYMBOL(bzero_1page);
+EXPORT_SYMBOL(__bzero_1page);
 EXPORT_SYMBOL(__bzero);
 EXPORT_SYMBOL(__memscan_zero);
 EXPORT_SYMBOL(__memscan_generic);
diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c
new file mode 100644 (file)
index 0000000..8676985
--- /dev/null
@@ -0,0 +1,276 @@
+/* $Id: sunos_ioctl32.c,v 1.2 1997/07/05 07:09:16 davem Exp $
+ * sunos_ioctl32.c: SunOS ioctl compatability on sparc64.
+ *
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/termios.h>
+#include <linux/ioctl.h>
+#include <linux/route.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <asm/kbio.h>
+
+#define A(x) ((unsigned long)x)
+
+#define SUNOS_NR_OPEN  256
+
+struct rtentry32 {
+        u32            rt_pad1;
+        struct sockaddr rt_dst;         /* target address               */
+        struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
+        struct sockaddr rt_genmask;     /* target network mask (IP)     */
+        unsigned short  rt_flags;
+        short           rt_pad2;
+        u32            rt_pad3;
+        unsigned char   rt_tos;
+        unsigned char   rt_class;
+        short           rt_pad4;
+        short           rt_metric;      /* +1 for binary compatibility! */
+        /* char * */ u32 rt_dev;        /* forcing the device at add    */
+        u32            rt_mtu;         /* per route MTU/Window         */
+        u32            rt_window;      /* Window clamping              */
+        unsigned short  rt_irtt;        /* Initial RTT                  */
+
+};
+
+struct ifmap32 {
+       u32 mem_start;
+       u32 mem_end;
+       unsigned short base_addr;
+       unsigned char irq;
+       unsigned char dma;
+       unsigned char port;
+};
+
+struct ifreq32 {
+#define IFHWADDRLEN     6
+#define IFNAMSIZ        16
+        union {
+                char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
+        } ifr_ifrn;
+        union {
+                struct  sockaddr ifru_addr;
+                struct  sockaddr ifru_dstaddr;
+                struct  sockaddr ifru_broadaddr;
+                struct  sockaddr ifru_netmask;
+                struct  sockaddr ifru_hwaddr;
+                short   ifru_flags;
+                int     ifru_ivalue;
+                int     ifru_mtu;
+                struct  ifmap32 ifru_map;
+                char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+                __kernel_caddr_t32 ifru_data;
+        } ifr_ifru;
+};
+
+struct ifconf32 {
+        int     ifc_len;                        /* size of buffer       */
+        __kernel_caddr_t32  ifcbuf;
+};
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+extern asmlinkage int sys32_ioctl(unsigned int, unsigned int, u32);
+extern asmlinkage int sys_setsid(void);
+
+asmlinkage int sunos_ioctl (int fd, unsigned long cmd, u32 arg)
+{
+       struct file *filp;
+       int ret = -EBADF;
+
+       lock_kernel();
+       if(fd >= SUNOS_NR_OPEN || !(filp = current->files->fd[fd]))
+               goto out;
+       if(cmd == TIOCSETD) {
+               unsigned long old_fs = get_fs();
+               int *p, ntty = N_TTY;
+               int tmp;
+
+               p = (int *)A(arg);
+               ret = -EFAULT;
+               if(get_user(tmp, p))
+                       goto out;
+               if(tmp == 2) {
+                       set_fs(KERNEL_DS);
+                       ret = sys_ioctl(fd, cmd, (unsigned long) &ntty);
+                       set_fs(old_fs);
+                       ret = (ret == -EINVAL ? -EOPNOTSUPP : ret);
+                       goto out;
+               }
+       }
+       if(cmd == TIOCNOTTY) {
+               ret = sys_setsid();
+               goto out;
+       }
+       switch(cmd) {
+       case _IOW('r', 10, struct rtentry32):
+               ret = sys32_ioctl(fd, SIOCADDRT, arg);
+               goto out;
+       case _IOW('r', 11, struct rtentry32):
+               ret = sys32_ioctl(fd, SIOCDELRT, arg);
+               goto out;
+
+       case _IOW('i', 12, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCSIFADDR, arg);
+               goto out;
+       case _IOWR('i', 13, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCGIFADDR, arg);
+               goto out;
+       case _IOW('i', 14, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCSIFDSTADDR, arg);
+               goto out;
+       case _IOWR('i', 15, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCGIFDSTADDR, arg);
+               goto out;
+       case _IOW('i', 16, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCSIFFLAGS, arg);
+               goto out;
+       case _IOWR('i', 17, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCGIFFLAGS, arg);
+               goto out;
+       case _IOW('i', 18, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCSIFMEM, arg);
+               goto out;
+       case _IOWR('i', 19, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCGIFMEM, arg);
+               goto out;
+
+       case _IOWR('i', 20, struct ifconf32):
+               ret = sys32_ioctl(fd, SIOCGIFCONF, arg);
+               goto out;
+
+       case _IOW('i', 21, struct ifreq): /* SIOCSIFMTU */
+               ret = sys_ioctl(fd, SIOCSIFMTU, arg);
+               goto out;
+       case _IOWR('i', 22, struct ifreq): /* SIOCGIFMTU */
+               ret = sys_ioctl(fd, SIOCGIFMTU, arg);
+               goto out;
+
+       case _IOWR('i', 23, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCGIFBRDADDR, arg);
+               goto out;
+       case _IOW('i', 24, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCGIFBRDADDR, arg);
+               goto out;
+       case _IOWR('i', 25, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCGIFNETMASK, arg);
+               goto out;
+       case _IOW('i', 26, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCSIFNETMASK, arg);
+               goto out;
+       case _IOWR('i', 27, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCGIFMETRIC, arg);
+               goto out;
+       case _IOW('i', 28, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCSIFMETRIC, arg);
+               goto out;
+
+       case _IOW('i', 30, struct arpreq):
+               ret = sys32_ioctl(fd, SIOCSARP, arg);
+               goto out;
+       case _IOWR('i', 31, struct arpreq):
+               ret = sys32_ioctl(fd, SIOCGARP, arg);
+               goto out;
+       case _IOW('i', 32, struct arpreq):
+               ret = sys32_ioctl(fd, SIOCDARP, arg);
+               goto out;
+
+       case _IOW('i', 40, struct ifreq32): /* SIOCUPPER */
+       case _IOW('i', 41, struct ifreq32): /* SIOCLOWER */
+       case _IOW('i', 44, struct ifreq32): /* SIOCSETSYNC */
+       case _IOW('i', 45, struct ifreq32): /* SIOCGETSYNC */
+       case _IOW('i', 46, struct ifreq32): /* SIOCSSDSTATS */
+       case _IOW('i', 47, struct ifreq32): /* SIOCSSESTATS */
+       case _IOW('i', 48, struct ifreq32): /* SIOCSPROMISC */
+               ret = -EOPNOTSUPP;
+               goto out;
+
+       case _IOW('i', 49, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCADDMULTI, arg);
+               goto out;
+       case _IOW('i', 50, struct ifreq32):
+               ret = sys32_ioctl(fd, SIOCDELMULTI, arg);
+               goto out;
+
+       /* FDDI interface ioctls, unsupported. */
+               
+       case _IOW('i', 51, struct ifreq32): /* SIOCFDRESET */
+       case _IOW('i', 52, struct ifreq32): /* SIOCFDSLEEP */
+       case _IOW('i', 53, struct ifreq32): /* SIOCSTRTFMWAR */
+       case _IOW('i', 54, struct ifreq32): /* SIOCLDNSTRTFW */
+       case _IOW('i', 55, struct ifreq32): /* SIOCGETFDSTAT */
+       case _IOW('i', 56, struct ifreq32): /* SIOCFDNMIINT */
+       case _IOW('i', 57, struct ifreq32): /* SIOCFDEXUSER */
+       case _IOW('i', 58, struct ifreq32): /* SIOCFDGNETMAP */
+       case _IOW('i', 59, struct ifreq32): /* SIOCFDGIOCTL */
+               printk("FDDI ioctl, returning EOPNOTSUPP\n");
+               ret = -EOPNOTSUPP;
+               goto out;
+
+       case _IOW('t', 125, int):
+               /* More stupid tty sunos ioctls, just
+                * say it worked.
+                */
+               ret = 0;
+               goto out;
+
+       /* Non posix grp */
+       case _IOW('t', 118, int): {
+               int oldval, newval, *ptr;
+
+               cmd = TIOCSPGRP;
+               ptr = (int *) A(arg);
+               ret = -EFAULT;
+               if(get_user(oldval, ptr))
+                       goto out;
+               ret = sys32_ioctl(fd, cmd, arg);
+               __get_user(newval, ptr);
+               if(newval == -1) {
+                       __put_user(oldval, ptr);
+                       ret = -EIO;
+               }
+               if(ret == -ENOTTY)
+                       ret = -EIO;
+               goto out;
+       }
+
+       case _IOR('t', 119, int): {
+               int oldval, newval, *ptr;
+
+               cmd = TIOCGPGRP;
+               ptr = (int *) A(arg);
+               ret = -EFAULT;
+               if(get_user(oldval, ptr))
+                       goto out;
+               ret = sys32_ioctl(fd, cmd, arg);
+               __get_user(newval, ptr);
+               if(newval == -1) {
+                       __put_user(oldval, ptr);
+                       ret = -EIO;
+               }
+               if(ret == -ENOTTY)
+                       ret = -EIO;
+               goto out;
+       }
+       };
+
+       ret = sys32_ioctl(fd, cmd, arg);
+       /* so stupid... */
+       ret = (ret == -EINVAL ? -EOPNOTSUPP : ret);
+out:
+       unlock_kernel();
+       return ret;
+}
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
new file mode 100644 (file)
index 0000000..ed14462
--- /dev/null
@@ -0,0 +1,427 @@
+/* $Id: sys32.S,v 1.1 1997/06/29 03:38:56 davem Exp $
+ * sys32.S: I-cache tricks for 32-bit compatability layer simple
+ *          conversions.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+       .text
+
+       .align          32
+       .globl          sys32_mmap, sys32_mprotect, sys32_munmap, sys32_msync
+       .globl          sys32_mlock, sys32_munlock, sys32_mremap, sparc32_brk
+sys32_mmap:
+       srl             %o0, 0, %o0                     ! IEU0  Group
+       sethi           %hi(0xffffffff), %g2            ! IEU1
+       srl             %o1, 0, %o1                     ! IEU0  Group
+       or              %g2, %lo(0xffffffff), %g2       ! IEU1
+       srl             %o2, 0, %o2                     ! IEU0  Group
+       mov             %o7, %g1                        ! IEU1
+       and             %o3, %g2, %o3                   ! IEU0  Group
+       and             %o4, %g2, %o4                   ! IEU1
+       and             %o5, %g2, %o5                   ! IEU0  Group
+       call            sys_mmap                        ! CTI   Group brk forced
+        mov            %g1, %o7                        ! IEU0  Group (regdep)
+sys32_mprotect:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       srl             %o2, 0, %o2
+       call            sys_mprotect
+        mov            %g1, %o7
+sys32_munmap:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       call            sys_munmap
+        mov            %g1, %o7
+sparc32_brk:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_brk
+        mov            %g1, %o7
+sys32_msync:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       call            sys_msync
+        mov            %g1, %o7
+sys32_mlock:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       call            sys_mlock
+        mov            %g1, %o7
+sys32_munlock:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       call            sys_munlock
+        mov            %g1, %o7
+sys32_mremap:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       srl             %o2, 0, %o2
+       srl             %o3, 0, %o3
+       call            sys_mremap
+        mov            %g1, %o7
+
+       .align          32
+       .globl          sys32_read, sys32_write, sys32_open, sys32_access
+       .globl          sys32_chdir, sys32_lseek, sys32_llseek, sys32_poll
+       .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
+sys32_read:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       call            sys_read
+        mov            %g1, %o7
+sys32_write:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       call            sys_write
+        mov            %g1, %o7
+sys32_open:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_open
+        mov            %g1, %o7
+sys32_access:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_access
+        mov            %g1, %o7
+sys32_chdir:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_chdir
+        mov            %g1, %o7
+sys32_lseek:
+       sra             %o1, 0, %o1
+       mov             %o7, %g1
+       call            sys_lseek
+        mov            %g1, %o7
+sys32_llseek:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       srl             %o3, 0, %o3
+       call            sys_llseek
+        mov            %g1, %o7
+sys32_poll:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_poll
+        mov            %g1, %o7
+sys32_readlink:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       call            sys_readlink
+        mov            %g1, %o7
+sys32_unlink:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_unlink
+        mov            %g1, %o7
+sys32_rmdir:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_rmdir
+        mov            %g1, %o7
+sys32_symlink:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       call            sys_symlink
+        mov            %g1, %o7
+sys32_link:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       call            sys_link
+        mov            %g1, %o7
+sys32_rename:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       call            sys_rename
+        mov            %g1, %o7
+       nop
+sys32_truncate:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       srl             %o1, 0, %o1
+       call            sys_truncate
+        mov            %g1, %o7
+sys32_ftruncate:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       call            sys_ftruncate
+        mov            %g1, %o7
+sys32_chroot:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_chroot
+        mov            %g1, %o7
+sys32_chmod:
+       sll             %o1, 16, %o1
+       mov             %o7, %g1
+       srl             %o0, 0, %o0
+       srl             %o1, 16, %o1
+       call            sys_chmod
+        mov            %g1, %o7
+sys32_chown:
+       sll             %o1, 16, %o1
+       mov             %o7, %g1
+       sll             %o2, 16, %o2
+       srl             %o0, 0, %o0
+       srl             %o1, 16, %o1
+       srl             %o2, 16, %o2
+       call            sys_chown
+        mov            %g1, %o7
+sys32_creat:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_creat
+        mov            %g1, %o7
+sys32_mkdir:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_mkdir
+        mov            %g1, %o7
+sys32_mknod:
+       sll             %o2, 16, %o2
+       mov             %o7, %g1
+       srl             %o0, 0, %o0
+       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
+       call            sys_ustat
+         mov           %g1, %o7
+
+       .align          32
+       .globl          sys32_bind, sys32_accept, sys32_connect, sys32_getsockname
+       .globl          sys32_getpeername, sys32_send, sys32_sendto, sys32_recv
+       .globl          sys32_recvfrom, sys32_setsockopt, sys32_getsockopt
+sys32_bind:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       call            sys_bind
+        mov            %g1, %o7
+sys32_accept:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       call            sys_accept
+        mov            %g1, %o7
+sys32_connect:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       call            sys_connect
+        mov            %g1, %o7
+sys32_getsockname:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       call            sys_getsockname
+        mov            %g1, %o7
+sys32_getpeername:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       call            sys_getpeername
+        mov            %g1, %o7
+sys32_send:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       call            sys_send
+        mov            %g1, %o7
+sys32_sendto:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       srl             %o4, 0, %o4
+       call            sys_sendto
+        mov            %g1, %o7
+sys32_recv:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       call            sys_recv
+        mov            %g1, %o7
+sys32_recvfrom:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       srl             %o4, 0, %o4
+       srl             %o5, 0, %o5
+       call            sys_recvfrom
+        mov            %g1, %o7
+sys32_setsockopt:
+       srl             %o3, 0, %o3
+       mov             %o7, %g1
+       call            sys_setsockopt
+        mov            %g1, %o7
+sys32_getsockopt:
+       srl             %o3, 0, %o3
+       mov             %o7, %g1
+       srl             %o4, 0, %o4
+       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_sched_setparam, sys32_sched_getparam, sys32_signal
+       .globl          sys32_reboot, sys32_acct, sys32_newuname, sys32_olduname
+       .globl          sys32_sethostname, sys32_gethostname, sys32_setdomainname
+       .globl          sys32_time, sys32_swapoff, sys32_swapon, sys32_nfsservctl
+       .globl          sys32_create_module, sys32_init_module, sys32_delete_module
+sys32_bdflush:
+       sra             %o1, 0, %o1
+       mov             %o7, %g1
+       call            sys_bdflush
+        mov            %g1, %o7
+sys32_uselib:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_uselib
+        mov            %g1, %o7
+sys32_umount:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_umount
+        mov            %g1, %o7
+sys32_syslog:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       call            sys_syslog
+        mov            %g1, %o7
+sys32_personality:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_personality
+        mov            %g1, %o7
+sys32_waitpid:
+       srl             %o1, 0, %o1
+       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
+       call            sys_sched_setscheduler
+        mov            %g1, %o7
+sys32_sched_setparam:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       call            sys_sched_setparam
+        mov            %g1, %o7
+sys32_sched_getparam:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       call            sys_sched_getparam
+        mov            %g1, %o7
+sys32_signal:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       call            sys_signal
+        mov            %g1, %o7
+sys32_reboot:
+       srl             %o3, 0, %o3
+       mov             %o7, %g1
+       call            sys_reboot
+        mov            %g1, %o7
+sys32_acct:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_acct
+        mov            %g1, %o7
+sys32_newuname:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_newuname
+        mov            %g1, %o7
+sys32_olduname:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_olduname
+        mov            %g1, %o7
+sys32_sethostname:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_sethostname
+        mov            %g1, %o7
+sys32_gethostname:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_gethostname
+        mov            %g1, %o7
+sys32_setdomainname:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_setdomainname
+        mov            %g1, %o7
+sys32_time:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_time
+        mov            %g1, %o7
+sys32_swapoff:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_swapoff
+        mov            %g1, %o7
+sys32_swapon:
+       srl             %o0, 0, %o0
+       mov             %o7, %g1
+       call            sys_swapon
+        mov            %g1, %o7
+sys32_nfsservctl:
+       srl             %o1, 0, %o1
+       mov             %o7, %g1
+       srl             %o2, 0, %o2
+       call            sys_nfsservctl
+        mov            %g1, %o7
index 851d1550c06fe1d5b3b97e330da89158f2144b58..c827df7a1aba3bc70bde1d1e1e6364423909a1ba 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.1 1997/04/09 08:25:18 jj Exp $
+/* $Id: sys_sparc.c,v 1.2 1997/07/05 09:52:34 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -9,7 +9,6 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/sched.h>
-#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/sem.h>
index 3ecaee05f92e12d624ac907fa1f1c8509619b303..3281d2f5837cbcfb901a1f768f1fdb6091719f67 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.32 1997/06/17 05:36:40 davem Exp $
+/* $Id: sys_sparc32.c,v 1.42 1997/07/05 09:52:36 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -8,6 +8,7 @@
  * environment.
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/fs.h> 
 #include <linux/signal.h>
 #include <linux/ncp_fs.h>
 #include <linux/quota.h>
 #include <linux/file.h>
+#include <linux/module.h>
 
 #include <asm/types.h>
 #include <asm/poll.h>
 #include <asm/ipc.h>
 #include <asm/uaccess.h>
+#include <asm/fpumacro.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.
@@ -372,11 +375,12 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
                        switch (version) {
                        case 0: default: {
                                unsigned long raddr;
+                               u32 *uptr = (u32 *) A(((u32)third));
                                err = sys_shmat (first, (char *)A(ptr), second, &raddr);
                                if (err)
                                        goto out;
                                err = -EFAULT;
-                               if(put_user (raddr, ((u32 *)A(third))))
+                               if(put_user (raddr, uptr))
                                        goto out;
                                err = 0;
                                goto out;
@@ -469,32 +473,6 @@ out:
        return err;
 }
 
-extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
-                                        unsigned long prot, unsigned long flags,
-                                        unsigned long fd, unsigned long off);
-
-asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot,
-                                   u32 flags, u32 fd, u32 off)
-{
-       return sys_mmap((unsigned long)addr, (unsigned long)len,
-                       (unsigned long)prot, (unsigned long)flags, 
-                       (unsigned long)fd, (unsigned long)off);
-}
-
-extern asmlinkage int sys_bdflush(int func, long data);
-
-asmlinkage int sys32_bdflush(int func, s32 data)
-{
-       return sys_bdflush(func, (long)data);
-}
-
-extern asmlinkage int sys_uselib(const char * library);
-
-asmlinkage int sys32_uselib(u32 library)
-{
-       return sys_uselib((const char *)A(library));
-}
-
 static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
 {
        if(get_user(kfl->l_type, &ufl->l_type)          ||
@@ -544,55 +522,6 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
        }
 }
 
-extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev);
-
-asmlinkage int sys32_mknod(u32 filename, int mode, __kernel_dev_t32 dev)
-{
-       return sys_mknod((const char *)A(filename), mode, dev);
-}
-
-extern asmlinkage int sys_mkdir(const char * pathname, int mode);
-
-asmlinkage int sys32_mkdir(u32 pathname, int mode)
-{
-       return sys_mkdir((const char *)A(pathname), mode);
-}
-
-extern asmlinkage int sys_rmdir(const char * pathname);
-
-asmlinkage int sys32_rmdir(u32 pathname)
-{
-       return sys_rmdir((const char *)A(pathname));
-}
-
-extern asmlinkage int sys_unlink(const char * pathname);
-
-asmlinkage int sys32_unlink(u32 pathname)
-{
-       return sys_unlink((const char *)A(pathname));
-}
-
-extern asmlinkage int sys_symlink(const char * oldname, const char * newname);
-
-asmlinkage int sys32_symlink(u32 oldname, u32 newname)
-{
-       return sys_symlink((const char *)A(oldname), (const char *)A(newname));
-}
-
-extern asmlinkage int sys_link(const char * oldname, const char * newname);
-
-asmlinkage int sys32_link(u32 oldname, u32 newname)
-{
-       return sys_link((const char *)A(oldname), (const char *)A(newname));
-}
-
-extern asmlinkage int sys_rename(const char * oldname, const char * newname);
-
-asmlinkage int sys32_rename(u32 oldname, u32 newname)
-{
-       return sys_rename((const char *)A(oldname), (const char *)A(newname));
-}
-
 struct dqblk32 {
     __u32 dqb_bhardlimit;
     __u32 dqb_bsoftlimit;
@@ -701,20 +630,6 @@ asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
        return ret;
 }
 
-extern asmlinkage int sys_truncate(const char * path, unsigned long length);
-
-asmlinkage int sys32_truncate(u32 path, u32 length)
-{
-       return sys_truncate((const char *)A(path), (unsigned long)length);
-}
-
-extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length);
-
-asmlinkage int sys32_ftruncate(unsigned int fd, u32 length)
-{
-       return sys_ftruncate(fd, (unsigned long)length);
-}
-
 extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
 
 asmlinkage int sys32_utime(u32 filename, u32 times)
@@ -741,96 +656,6 @@ asmlinkage int sys32_utime(u32 filename, u32 times)
        return ret;
 }
 
-extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes);
-
-asmlinkage int sys32_utimes(u32 filename, u32 utimes)
-{
-       /* struct timeval is the same :)) */
-       return sys_utimes((char *)A(filename), (struct timeval *)A(utimes));
-}
-
-extern asmlinkage int sys_access(const char * filename, int mode);
-
-asmlinkage int sys32_access(u32 filename, int mode)
-{
-       return sys_access((const char *)A(filename), mode);
-}
-
-extern asmlinkage int sys_chdir(const char * filename);
-
-asmlinkage int sys32_chdir(u32 filename)
-{
-       return sys_chdir((const char *)A(filename));
-}
-
-extern asmlinkage int sys_chroot(const char * filename);
-
-asmlinkage int sys32_chroot(u32 filename)
-{
-       return sys_chroot((const char *)A(filename));
-}
-
-extern asmlinkage int sys_chmod(const char * filename, mode_t mode);
-
-asmlinkage int sys32_chmod(u32 filename, __kernel_mode_t32 mode)
-{
-       return sys_chmod((const char *)A(filename), mode);
-}
-
-extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group);
-
-asmlinkage int sys32_chown(u32 filename, __kernel_uid_t32 user, __kernel_gid_t32 group)
-{
-       return sys_chown((const char *)A(filename), user, group);
-}
-
-extern asmlinkage int sys_open(const char * filename,int flags,int mode);
-
-asmlinkage int sys32_open(u32 filename, int flags, int mode)
-{
-       return sys_open((const char *)A(filename), flags, mode);
-}
-
-extern asmlinkage int sys_creat(const char * pathname, int mode);
-
-asmlinkage int sys32_creat(u32 pathname, int mode)
-{
-       return sys_creat((const char *)A(pathname), mode);
-}
-
-extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
-
-asmlinkage long sys32_lseek(unsigned int fd, s32 offset, unsigned int origin)
-{
-       return sys_lseek(fd, (off_t)offset, origin);
-}
-
-extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
-                                unsigned long offset_low,
-                                loff_t *result, unsigned int origin);
-
-asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high,
-                           u32 offset_low, u32 result, unsigned int origin)
-{
-       /* loff_t is the same :)) */
-       return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low,
-                         (loff_t *)A(result), origin);
-}
-
-extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count);
-
-asmlinkage long sys32_read(unsigned int fd, u32 buf, u32 count)
-{
-       return sys_read(fd, (char *)A(buf), (unsigned long)count);
-}
-
-extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count);
-
-asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count)
-{
-       return sys_write(fd, (const char *)A(buf), (unsigned long)count);
-}
-
 struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };
 
 typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long);
@@ -1196,13 +1021,6 @@ out:
        return ret;
 }
 
-extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout);
-
-asmlinkage int sys32_poll(u32 ufds, unsigned int nfds, int timeout)
-{
-       return sys_poll((struct pollfd *)A(ufds), nfds, timeout);
-}
-
 static inline int putstat(struct stat32 *ubuf, struct stat *kbuf)
 {
        if (put_user (kbuf->st_dev, &ubuf->st_dev)              ||
@@ -1280,13 +1098,6 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
        return ret;
 }
 
-extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz);
-
-asmlinkage int sys32_readlink(u32 path, u32 buf, int bufsiz)
-{
-       return sys_readlink((const char *)A(path), (char *)A(buf), bufsiz);
-}
-
 extern asmlinkage int sys_sysfs(int option, ...);
 
 asmlinkage int sys32_sysfs(int option, ...)
@@ -1312,21 +1123,6 @@ asmlinkage int sys32_sysfs(int option, ...)
        return ret;
 }
 
-extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf);
-
-asmlinkage int sys32_ustat(dev_t dev, u32 ubuf)
-{
-       /* ustat is the same :)) */
-       return sys_ustat(dev, (struct ustat *)A(ubuf));
-}
-
-extern asmlinkage int sys_umount(char * name);
-
-asmlinkage int sys32_umount(u32 name)
-{
-       return sys_umount((char *)A(name));
-}
-
 struct ncp_mount_data32 {
         int version;
         unsigned int ncp_fd;
@@ -1485,20 +1281,6 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags,
        }
 }
 
-extern asmlinkage int sys_syslog(int type, char * bug, int count);
-
-asmlinkage int sys32_syslog(int type, u32 bug, int count)
-{
-       return sys_syslog(type, (char *)A(bug), count);
-}
-
-extern asmlinkage int sys_personality(unsigned long personality);
-
-asmlinkage int sys32_personality(u32 personality)
-{
-       return sys_personality((unsigned long)personality);
-}
-
 struct rusage32 {
         struct timeval ru_utime;
         struct timeval ru_stime;
@@ -1565,13 +1347,6 @@ asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32
        }
 }
 
-extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options);
-
-asmlinkage int sys32_waitpid(__kernel_pid_t32 pid, u32 stat_addr, int options)
-{
-       return sys_waitpid(pid, (unsigned int *)A(stat_addr), options);
-}
-
 struct sysinfo32 {
         s32 uptime;
         u32 loads[3];
@@ -1611,46 +1386,6 @@ asmlinkage int sys32_sysinfo(u32 info)
        return ret;
 }
 
-extern asmlinkage int sys_getitimer(int which, struct itimerval *value);
-
-asmlinkage int sys32_getitimer(int which, u32 value)
-{
-       /* itimerval is the same :)) */
-       return sys_getitimer(which, (struct itimerval *)A(value));
-}
-
-extern asmlinkage int sys_setitimer(int which, struct itimerval *value,
-                                   struct itimerval *ovalue);
-
-asmlinkage int sys32_setitimer(int which, u32 value, u32 ovalue)
-{
-       return sys_setitimer(which, (struct itimerval *)A(value),
-                            (struct itimerval *)A(ovalue));
-}
-
-extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy,
-                                            struct sched_param *param);
-
-asmlinkage int sys32_sched_setscheduler(__kernel_pid_t32 pid, int policy, u32 param)
-{
-       /* sched_param is the same :)) */
-       return sys_sched_setscheduler(pid, policy, (struct sched_param *)A(param));
-}
-
-extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param);
-
-asmlinkage int sys32_sched_setparam(__kernel_pid_t32 pid, u32 param)
-{
-       return sys_sched_setparam(pid, (struct sched_param *)A(param));
-}
-
-extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param);
-
-asmlinkage int sys32_sched_getparam(__kernel_pid_t32 pid, u32 param)
-{
-       return sys_sched_getparam(pid, (struct sched_param *)A(param));
-}
-
 struct timespec32 {
        s32    tv_sec;
        s32    tv_nsec;
@@ -1726,27 +1461,6 @@ asmlinkage int sys32_sigpending(u32 set)
        return ret;
 }
 
-extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler);
-
-asmlinkage unsigned long sys32_signal(int signum, u32 handler)
-{
-       return sys_signal(signum, (__sighandler_t)A(handler));
-}
-
-extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg);
-
-asmlinkage int sys32_reboot(int magic1, int magic2, int cmd, u32 arg)
-{
-       return sys_reboot(magic1, magic2, cmd, (void *)A(arg));
-}
-
-extern asmlinkage int sys_acct(const char *name);
-
-asmlinkage int sys32_acct(u32 name)
-{
-       return sys_acct((const char *)A(name));
-}
-
 extern asmlinkage int sys_setreuid(uid_t ruid, uid_t euid);
 
 asmlinkage int sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid)
@@ -1854,42 +1568,6 @@ asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
        return ret;
 }
 
-extern asmlinkage int sys_newuname(struct new_utsname * name);
-
-asmlinkage int sys32_newuname(u32 name)
-{
-       /* utsname is the same :)) */
-       return sys_newuname((struct new_utsname *)A(name));
-}
-
-extern asmlinkage int sys_olduname(struct oldold_utsname * name);
-
-asmlinkage int sys32_olduname(u32 name)
-{
-       return sys_olduname((struct oldold_utsname *)A(name));
-}
-
-extern asmlinkage int sys_sethostname(char *name, int len);
-
-asmlinkage int sys32_sethostname(u32 name, int len)
-{
-       return sys_sethostname((char *)A(name), len);
-}
-
-extern asmlinkage int sys_gethostname(char *name, int len);
-
-asmlinkage int sys32_gethostname(u32 name, int len)
-{
-       return sys_gethostname((char *)A(name), len);
-}
-
-extern asmlinkage int sys_setdomainname(char *name, int len);
-
-asmlinkage int sys32_setdomainname(u32 name, int len)
-{
-       return sys_setdomainname((char *)A(name), len);
-}
-
 #define RLIM_INFINITY32        0x7fffffff
 #define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
 
@@ -1953,28 +1631,6 @@ asmlinkage int sys32_getrusage(int who, u32 ru)
        return ret;
 }
 
-extern asmlinkage int sys_time(int * tloc);
-
-asmlinkage int sys32_time(u32 tloc)
-{
-       return sys_time((int *)A(tloc));
-}
-
-extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz);
-
-asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
-{
-       /* both timeval and timezone are ok :)) */
-       return sys_gettimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
-}
-
-extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz);
-
-asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
-{
-       return sys_settimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
-}
-
 struct timex32 {
        unsigned int modes;
        s32 offset;
@@ -2046,170 +1702,6 @@ asmlinkage int sys32_adjtimex(u32 txc_p)
        return ret;
 }
 
-extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags);
-
-asmlinkage int sys32_msync(u32 start, __kernel_size_t32 len, int flags)
-{
-       return sys_msync((unsigned long)start, (size_t)len, flags);
-}
-
-extern asmlinkage int sys_mlock(unsigned long start, size_t len);
-
-asmlinkage int sys32_mlock(u32 start, __kernel_size_t32 len)
-{
-       return sys_mlock((unsigned long)start, (size_t)len);
-}
-
-extern asmlinkage int sys_munlock(unsigned long start, size_t len);
-
-asmlinkage int sys32_munlock(u32 start, __kernel_size_t32 len)
-{
-       return sys_munlock((unsigned long)start, (size_t)len);
-}
-
-extern asmlinkage unsigned long sys_brk(unsigned long brk);
-
-asmlinkage unsigned long sparc32_brk(u32 brk)
-{
-       return sys_brk((unsigned long)brk);
-}
-
-extern asmlinkage int sys_munmap(unsigned long addr, size_t len);
-
-asmlinkage int sys32_munmap(u32 addr, __kernel_size_t32 len)
-{
-       return sys_munmap((unsigned long)addr, (size_t)len);
-}
-
-extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot);
-
-asmlinkage int sys32_mprotect(u32 start, __kernel_size_t32 len, u32 prot)
-{
-       return sys_mprotect((unsigned long)start, (size_t)len, (unsigned long)prot);
-}
-
-extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len,
-                                          unsigned long new_len, unsigned long flags);
-
-asmlinkage unsigned long sys32_mremap(u32 addr, u32 old_len, u32 new_len, u32 flags)
-{
-       return sys_mremap((unsigned long)addr, (unsigned long)old_len,
-                         (unsigned long)new_len, (unsigned long)flags);
-}
-
-extern asmlinkage int sys_swapoff(const char * specialfile);
-
-asmlinkage int sys32_swapoff(u32 specialfile)
-{
-       return sys_swapoff((const char *)A(specialfile));
-}
-
-extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags);
-
-asmlinkage int sys32_swapon(u32 specialfile, int swap_flags)
-{
-       return sys_swapon((const char *)A(specialfile), swap_flags);
-}
-
-extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
-
-asmlinkage inline int sys32_bind(int fd, u32 umyaddr, int addrlen)
-{
-       /* sockaddr is the same :)) */
-       return sys_bind(fd, (struct sockaddr *)A(umyaddr), addrlen);
-}
-
-extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr,
-                                int *upeer_addrlen);
-
-asmlinkage inline int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen)
-{
-       return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr),
-                         (int *)A(upeer_addrlen));
-}
-
-extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
-
-asmlinkage inline int sys32_connect(int fd, u32 uservaddr, int addrlen)
-{
-       return sys_connect(fd, (struct sockaddr *)A(uservaddr), addrlen);
-}
-
-extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr,
-                                     int *usockaddr_len);
-
-asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len)
-{
-       return sys_getsockname(fd, (struct sockaddr *)A(usockaddr),
-                              (int *)A(usockaddr_len));
-}
-
-extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr,
-                                     int *usockaddr_len);
-
-asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len)
-{
-       return sys_getpeername(fd, (struct sockaddr *)A(usockaddr),
-                              (int *)A(usockaddr_len));
-}
-
-extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags);
-
-asmlinkage inline int sys32_send(int fd, u32 buff,
-                                __kernel_size_t32 len, unsigned flags)
-{
-       return sys_send(fd, (void *)A(buff), (size_t)len, flags);
-}
-
-extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags,
-                                struct sockaddr *addr, int addr_len);
-
-asmlinkage inline int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len,
-                                  unsigned flags, u32 addr, int addr_len)
-{
-       return sys_sendto(fd, (void *)A(buff), (size_t)len, flags,
-                         (struct sockaddr *)A(addr), addr_len);
-}
-
-extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags);
-
-asmlinkage inline int sys32_recv(int fd, u32 ubuf,
-                                __kernel_size_t32 size, unsigned flags)
-{
-       return sys_recv(fd, (void *)A(ubuf), (size_t)size, flags);
-}
-
-extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags,
-                                  struct sockaddr *addr, int *addr_len); 
-
-asmlinkage inline int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
-                                    unsigned flags, u32 addr, u32 addr_len)
-{
-       return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags,
-                           (struct sockaddr *)A(addr), (int *)A(addr_len));
-}
-extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
-                                    char *optval, int optlen);
-
-asmlinkage inline int sys32_setsockopt(int fd, int level, int optname,
-                                      u32 optval, int optlen)
-{
-       /* XXX handle ip_fw32->ip_fw conversion for IP firewalling and accounting.
-              Do it using some macro in ip_sockglue.c
-          Other optval arguments are mostly just ints or 32<->64bit transparent */
-       return sys_setsockopt(fd, level, optname, (char *)A(optval), optlen);
-}
-
-extern asmlinkage int sys_getsockopt(int fd, int level, int optname,
-                                    char *optval, int *optlen);
-
-asmlinkage inline int sys32_getsockopt(int fd, int level, int optname,
-                                      u32 optval, u32 optlen)
-{
-       return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen));
-}
-
 /* XXX This really belongs in some header file... -DaveM */
 #define MAX_SOCK_ADDR  128             /* 108 for Unix domain - 
                                           16 for IP, 16 for IPX,
@@ -2474,6 +1966,24 @@ static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
                                 AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
 #undef AL
 
+extern asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen);
+extern asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen);
+extern asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen);
+extern asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len);
+extern asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len);
+extern asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len,
+                                unsigned flags);
+extern asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len,
+                                  unsigned flags, u32 addr, int addr_len);
+extern asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size,
+                                unsigned flags);
+extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
+                                    unsigned flags, u32 addr, u32 addr_len);
+extern asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+                                      u32 optval, int optlen);
+extern asmlinkage int sys32_getsockopt(int fd, int level, int optname,
+                                      u32 optval, u32 optlen);
+
 extern asmlinkage int sys_socket(int family, int type, int protocol);
 extern asmlinkage int sys_socketpair(int family, int type, int protocol,
                                     int usockvec[2]);
@@ -2570,7 +2080,7 @@ asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction)
                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), p, sizeof(struct sigaction32)))
+               if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32)))
                        goto out;       
        }
 
@@ -2588,14 +2098,6 @@ out:
        return err;
 }
 
-extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp);
-
-asmlinkage int sys32_nfsservctl(int cmd, u32 argp, u32 resp)
-{
-       /* XXX handle argp and resp args */
-       return sys_nfsservctl(cmd, (void *)A(argp), (void *)A(resp));
-}
-
 /*
  * count32() counts the number of arguments/envelopes
  */
@@ -2731,11 +2233,219 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
                (u32 *)A((u32)regs->u_regs[base + UREG_I1]),
                (u32 *)A((u32)regs->u_regs[base + UREG_I2]), regs);
         putname(filename);
+       if(!error) {
+               fprs_write(0);
+               regs->fprs = 0;
+       }
         return error;
 }
 
-/* Modules will be supported with 64bit modutils only */
-asmlinkage int sys32_no_modules(void)
+#ifdef CONFIG_MODULES
+
+extern asmlinkage unsigned long sys_create_module(const char *name_user, size_t size);
+
+asmlinkage unsigned long sys32_create_module(u32 name_user, __kernel_size_t32 size)
+{
+       return sys_create_module((const char *)A(name_user), (size_t)size);
+}
+
+extern asmlinkage int sys_init_module(const char *name_user, struct module *mod_user);
+
+/* Hey, when you're trying to init module, take time and prepare us a nice 64bit
+ * module structure, even if from 32bit modutils... Why to pollute kernel... :))
+ */
+asmlinkage int sys32_init_module(u32 nameuser, u32 mod_user)
+{
+       return sys_init_module((const char *)A(nameuser), (struct module *)A(mod_user));
+}
+
+extern asmlinkage int sys_delete_module(const char *name_user);
+
+asmlinkage int sys32_delete_module(u32 name_user)
+{
+       return sys_delete_module((const char *)A(name_user));
+}
+
+struct module_info32 {
+       u32 addr;
+       u32 size;
+       u32 flags;
+       s32 usecount;
+};
+
+extern asmlinkage int sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret);
+
+asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 retv)
+{
+       char *buff;
+       unsigned long old_fs = get_fs();
+       size_t val;
+       int ret, i, j;
+       unsigned long *p;
+       char *usernam = NULL;
+       int bufsiz = bufsize;
+       struct module_info mi;
+       
+       switch (which) {
+       case 0: return sys_query_module ((const char *)A(name_user), which, (char *)A(buf), (size_t)bufsize, (size_t *)A(retv));
+       case QM_SYMBOLS:
+               bufsiz <<= 1;
+       case QM_MODULES:
+       case QM_REFS:
+       case QM_DEPS:
+               if (name_user && (ret = getname32 (name_user, &usernam)))
+                       return ret;
+               buff = kmalloc (bufsiz, GFP_KERNEL);
+               if (!buff) {
+                       if (name_user) putname32 (usernam);
+                       return -ENOMEM;
+               }
+qmsym_toshort:
+               set_fs (KERNEL_DS);
+               ret = sys_query_module (usernam, which, buff, bufsiz, &val);
+               set_fs (old_fs);
+               if (which != QM_SYMBOLS) {
+                       if (ret == -ENOSPC || !ret) {
+                               if (put_user (val, (__kernel_size_t32 *)A(retv)))
+                                       ret = -EFAULT;
+                       }
+                       if (!ret) {
+                               if (copy_to_user ((char *)A(buf), buff, bufsize))
+                                       ret = -EFAULT;
+                       }
+               } else {
+                       if (ret == -ENOSPC) {
+                               if (put_user (2 * val, (__kernel_size_t32 *)A(retv)))
+                                       ret = -EFAULT;
+                       }
+                       p = (unsigned long *)buff;
+                       if (!ret) {
+                               if (put_user (val, (__kernel_size_t32 *)A(retv)))
+                                       ret = -EFAULT;
+                       }
+                       if (!ret) {
+                               j = val * 8;
+                               for (i = 0; i < val; i++, p += 2) {
+                                       if (bufsize < (2 * sizeof (u32))) {
+                                               bufsiz = 0;
+                                               goto qmsym_toshort;
+                                       }
+                                       if (put_user (p[0], (u32 *)A(buf)) ||
+                                           __put_user (p[1] - j, (((u32 *)A(buf))+1))) {
+                                               ret = -EFAULT;
+                                               break;
+                                       }
+                                       bufsize -= (2 * sizeof (u32));
+                                       buf += (2 * sizeof (u32));
+                               }
+                       }
+                       if (!ret && val) {
+                               char *strings = buff + ((unsigned long *)buff)[1];
+                               j = *(p - 1) - ((unsigned long *)buff)[1];
+                               j = j + strlen (buff + j) + 1;
+                               if (bufsize < j) {
+                                       bufsiz = 0;
+                                       goto qmsym_toshort;
+                               }
+                               if (copy_to_user ((char *)A(buf), strings, j))
+                                       ret = -EFAULT;
+                       }
+               }
+               kfree (buff);
+               if (name_user) putname32 (usernam);
+               return ret;
+       case QM_INFO:
+               if (name_user && (ret = getname32 (name_user, &usernam)))
+                       return ret;
+               set_fs (KERNEL_DS);
+               ret = sys_query_module (usernam, which, (char *)&mi, sizeof (mi), &val);
+               set_fs (old_fs);
+               if (!ret) {
+                       if (put_user (sizeof (struct module_info32), (__kernel_size_t32 *)A(retv)))
+                               ret = -EFAULT;
+                       else if (bufsize < sizeof (struct module_info32))
+                               ret = -ENOSPC;
+               }
+               if (!ret) {
+                       if (put_user (mi.addr, &(((struct module_info32 *)A(buf))->addr)) ||
+                           __put_user (mi.size, &(((struct module_info32 *)A(buf))->size)) ||
+                           __put_user (mi.flags, &(((struct module_info32 *)A(buf))->flags)) ||
+                           __put_user (mi.usecount, &(((struct module_info32 *)A(buf))->usecount)))
+                               ret = -EFAULT;
+               }
+               if (name_user) putname32 (usernam);
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+struct kernel_sym32 {
+       u32 value;
+       char name[60];
+};
+                
+extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table);
+
+asmlinkage int sys32_get_kernel_syms(u32 table)
+{
+       int len, i;
+       struct kernel_sym *tbl;
+       unsigned long old_fs;
+       
+       len = sys_get_kernel_syms(NULL);
+       if (!table) return len;
+       tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL);
+       if (!tbl) return -ENOMEM;
+       old_fs = get_fs();
+       set_fs (KERNEL_DS);
+       sys_get_kernel_syms(tbl);
+       set_fs (old_fs);
+       for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) {
+               if (put_user (tbl[i].value, &(((struct kernel_sym32 *)A(table))->value)) ||
+                   copy_to_user (((struct kernel_sym32 *)A(table))->name, tbl[i].name, 60))
+                       break;
+       }
+       kfree (tbl);
+       return i;
+}
+
+#else /* CONFIG_MODULES */
+
+asmlinkage unsigned long
+sys_create_module(const char *name_user, size_t size)
+{
+       return -ENOSYS;
+}
+
+asmlinkage int
+sys_init_module(const char *name_user, struct module *mod_user)
+{
+       return -ENOSYS;
+}
+
+asmlinkage int
+sys_delete_module(const char *name_user)
 {
        return -ENOSYS;
 }
+
+asmlinkage int
+sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
+                size_t *ret)
+{
+       /* Let the program know about the new interface.  Not that
+          it'll do them much good.  */
+       if (which == 0)
+               return 0;
+
+       return -ENOSYS;
+}
+
+asmlinkage int
+sys_get_kernel_syms(struct kernel_sym *table)
+{
+       return -ENOSYS;
+}
+
+#endif  /* CONFIG_MODULES */
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
new file mode 100644 (file)
index 0000000..381d7e3
--- /dev/null
@@ -0,0 +1,1468 @@
+/* $Id: sys_sunos32.c,v 1.2 1997/07/05 07:09:16 davem Exp $
+ * sys_sunos32.c: SunOS binary compatability layer on sparc64.
+ *
+ * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Based upon preliminary work which is:
+ *
+ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/resource.h>
+#include <linux/ipc.h>
+#include <linux/shm.h>
+#include <linux/msg.h>
+#include <linux/sem.h>
+#include <linux/signal.h>
+#include <linux/uio.h>
+#include <linux/utsname.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/pagemap.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pconf.h>
+#include <asm/idprom.h> /* for gethostid() */
+#include <asm/unistd.h>
+#include <asm/system.h>
+
+/* For the nfs mount emulation */
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/nfs.h>
+#include <linux/nfs_mount.h>
+
+/* for sunos_select */
+#include <linux/time.h>
+#include <linux/personality.h>
+
+#define A(x) ((unsigned long)x)
+
+#define SUNOS_NR_OPEN  256
+
+extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
+
+asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
+{
+       struct file *file = NULL;
+       unsigned long retval, ret_type;
+
+       lock_kernel();
+       current->personality |= PER_BSD;
+       if(flags & MAP_NORESERVE) {
+               printk("%s:  unimplemented SunOS MAP_NORESERVE mmap() flag\n",
+                      current->comm);
+               flags &= ~MAP_NORESERVE;
+       }
+       retval = -EBADF;
+       if(!(flags & MAP_ANONYMOUS))
+               if(fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+                       goto out;
+       retval = -ENOMEM;
+       if(!(flags & MAP_FIXED) && !addr) {
+               unsigned long attempt = get_unmapped_area(addr, len);
+               if(!attempt || (attempt >= 0xf0000000UL))
+                       goto out;
+               addr = (u32) attempt;
+       }
+       if(MAJOR(file->f_inode->i_rdev) == MEM_MAJOR &&
+          MINOR(file->f_inode->i_rdev) == 5) {
+               flags |= MAP_ANONYMOUS;
+               file = 0;
+       }
+       if(!(flags & MAP_FIXED))
+               addr = 0;
+       ret_type = flags & _MAP_NEW;
+       flags &= ~_MAP_NEW;
+
+       retval = do_mmap(file,
+                        (unsigned long) addr, (unsigned long) len,
+                        (unsigned long) prot, (unsigned long) flags,
+                        (unsigned long) off);
+       if(!ret_type)
+               retval = ((retval < 0xf0000000) ? 0 : retval);
+out:
+       unlock_kernel();
+       return (u32) retval;
+}
+
+asmlinkage int sunos_mctl(u32 addr, u32 len, int function, u32 arg)
+{
+       return 0;
+}
+
+asmlinkage int sunos_brk(u32 baddr)
+{
+       int freepages, retval = -ENOMEM;
+       unsigned long rlim;
+       unsigned long newbrk, oldbrk, brk = (unsigned long) baddr;
+
+       lock_kernel();
+       if (brk < current->mm->end_code)
+               goto out;
+       newbrk = PAGE_ALIGN(brk);
+       oldbrk = PAGE_ALIGN(current->mm->brk);
+       retval = 0;
+       if (oldbrk == newbrk) {
+               current->mm->brk = brk;
+               goto out;
+       }
+       /* Always allow shrinking brk. */
+       if (brk <= current->mm->brk) {
+               current->mm->brk = brk;
+               do_munmap(newbrk, oldbrk-newbrk);
+               goto out;
+       }
+       /* Check against rlimit and stack.. */
+       retval = -ENOMEM;
+       rlim = current->rlim[RLIMIT_DATA].rlim_cur;
+       if (rlim >= RLIM_INFINITY)
+               rlim = ~0;
+       if (brk - current->mm->end_code > rlim)
+               goto out;
+       /* Check against existing mmap mappings. */
+       if (find_vma_intersection(current->mm, oldbrk, newbrk+PAGE_SIZE))
+               goto out;
+       /* stupid algorithm to decide if we have enough memory: while
+        * simple, it hopefully works in most obvious cases.. Easy to
+        * fool it, but this should catch most mistakes.
+        */
+       freepages = buffermem >> PAGE_SHIFT;
+        freepages += page_cache_size;
+       freepages >>= 1;
+       freepages += nr_free_pages;
+       freepages += nr_swap_pages;
+       freepages -= num_physpages >> 4;
+       freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
+       if (freepages < 0)
+               goto out;
+       /* Ok, we have probably got enough memory - let it rip. */
+       current->mm->brk = brk;
+       do_mmap(NULL, oldbrk, newbrk-oldbrk,
+               PROT_READ|PROT_WRITE|PROT_EXEC,
+               MAP_FIXED|MAP_PRIVATE, 0);
+       retval = 0;
+out:
+       unlock_kernel();
+       return retval;
+}
+
+asmlinkage u32 sunos_sbrk(int increment)
+{
+       int error, oldbrk;
+
+       /* This should do it hopefully... */
+       lock_kernel();
+       oldbrk = (int)current->mm->brk;
+       error = sunos_brk(((int) current->mm->brk) + increment);
+       if(!error)
+               error = oldbrk;
+       unlock_kernel();
+       return error;
+}
+
+asmlinkage u32 sunos_sstk(int increment)
+{
+       lock_kernel();
+       printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n",
+              current->comm, increment);
+       unlock_kernel();
+       return (u32)-1;
+}
+
+/* Give hints to the kernel as to what paging strategy to use...
+ * Completely bogus, don't remind me.
+ */
+#define VA_NORMAL     0 /* Normal vm usage expected */
+#define VA_ABNORMAL   1 /* Abnormal/random vm usage probable */
+#define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */
+#define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */
+static char *vstrings[] = {
+       "VA_NORMAL",
+       "VA_ABNORMAL",
+       "VA_SEQUENTIAL",
+       "VA_INVALIDATE",
+};
+
+asmlinkage void sunos_vadvise(u32 strategy)
+{
+       /* I wanna see who uses this... */
+       lock_kernel();
+       printk("%s: Advises us to use %s paging strategy\n",
+              current->comm,
+              strategy <= 3 ? vstrings[strategy] : "BOGUS");
+       unlock_kernel();
+}
+
+/* Same as vadvise, and just as bogus, but for a range of virtual
+ * process address space.
+ */
+#define MADV_NORMAL      0 /* Nothing special... */
+#define MADV_RANDOM      1 /* I am emacs... */
+#define MADV_SEQUENTIAL  2 /* I am researcher code... */
+#define MADV_WILLNEED    3 /* Pages in this range will be needed */
+#define MADV_DONTNEED    4 /* Pages in this range won't be needed */
+
+static char *mstrings[] = {
+       "MADV_NORMAL",
+       "MADV_RANDOM",
+       "MADV_SEQUENTIAL",
+       "MADV_WILLNEED",
+       "MADV_DONTNEED",
+};
+
+asmlinkage void sunos_madvise(u32 address, u32 len, u32 strategy)
+{
+       /* I wanna see who uses this... */
+       lock_kernel();
+       printk("%s: Advises us to use %s paging strategy for addr<%08x> len<%08x>\n",
+              current->comm, strategy <= 4 ? mstrings[strategy] : "BOGUS",
+              address, len);
+       unlock_kernel();
+}
+
+/* Places into character array, the status of all the pages in the passed
+ * range from 'addr' to 'addr + len'.  -1 on failure, 0 on success...
+ * The encoding in each character is:
+ * low-bit is zero == Page is not in physical ram right now
+ * low-bit is one  == Page is currently residing in core
+ * All other bits are undefined within the character so there...
+ * Also, if you try to get stats on an area outside of the user vm area
+ * *or* the passed base address is not aligned on a page boundary you
+ * get an error.
+ */
+asmlinkage int sunos_mincore(u32 addr, u32 len, u32 u_array)
+{
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+       unsigned long limit;
+       int num_pages, pnum, retval = -EINVAL;
+       char *array = (char *)A(u_array);
+
+       lock_kernel();
+       if(addr & ~(4096))
+               goto out;
+       num_pages = (len / 4096);
+       retval = -EFAULT;
+       if(verify_area(VERIFY_WRITE, array, num_pages))
+               goto out;
+       retval = -ENOMEM;
+       if((addr >= 0xf0000000) || ((addr + len) > 0xf0000000))
+               goto out; /* I'm sure you're curious about kernel mappings.. */
+       /* Wheee, go through pte's */
+       pnum = 0;
+       for(limit = addr + len; addr < limit; addr += 4096, pnum++) {
+               pgdp = pgd_offset(current->mm, addr);
+               if(pgd_none(*pgdp))
+                       goto out; /* As per SunOS manpage */
+               pmdp = pmd_offset(pgdp, addr);
+               if(pmd_none(*pmdp))
+                       goto out; /* As per SunOS manpage */
+               ptep = pte_offset(pmdp, addr);
+               if(pte_none(*ptep))
+                       goto out; /* As per SunOS manpage */
+               /* Page in core or Swapped page? */
+               __put_user((pte_present(*ptep) ? 1 : 0), &array[pnum]);
+       }
+       retval = 0; /* Success... I think... */
+out:
+       unlock_kernel();
+       return retval;
+}
+
+/* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE
+ * resource limit and is for backwards compatibility with older sunos
+ * revs.
+ */
+asmlinkage int sunos_getdtablesize(void)
+{
+       return SUNOS_NR_OPEN;
+}
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+asmlinkage u32 sunos_sigblock(u32 blk_mask)
+{
+       unsigned long flags;
+       u32 old;
+
+       lock_kernel();
+       save_and_cli(flags);
+       old = (u32) current->blocked;
+       current->blocked |= (blk_mask & _BLOCKABLE);
+       restore_flags(flags);
+       unlock_kernel();
+       return old;
+}
+
+asmlinkage u32 sunos_sigsetmask(u32 newmask)
+{
+       unsigned long flags;
+       u32 retval;
+
+       lock_kernel();
+       save_and_cli(flags);
+       retval = (u32) current->blocked;
+       current->blocked = (newmask & _BLOCKABLE);
+       restore_flags(flags);
+       unlock_kernel();
+       return retval;
+}
+
+/* SunOS getdents is very similar to the newer Linux (iBCS2 compliant)    */
+/* getdents system call, the format of the structure just has a different */
+/* layout (d_off+d_ino instead of d_ino+d_off) */
+struct sunos_dirent {
+    s32                d_off;
+    u32                d_ino;
+    u16                d_reclen;
+    u16                d_namlen;
+    char       d_name[1];
+};
+
+struct sunos_dirent_callback {
+    struct sunos_dirent *curr;
+    struct sunos_dirent *previous;
+    int count;
+    int error;
+};
+
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+sizeof(s32)-1) & ~(sizeof(s32)-1))
+
+static int sunos_filldir(void * __buf, const char * name, int namlen,
+                        off_t offset, ino_t ino)
+{
+       struct sunos_dirent * dirent;
+       struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
+       int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+       buf->error = -EINVAL;   /* only used if we fail.. */
+       if (reclen > buf->count)
+               return -EINVAL;
+       dirent = buf->previous;
+       if (dirent)
+               put_user(offset, &dirent->d_off);
+       dirent = buf->curr;
+       buf->previous = dirent;
+       put_user(ino, &dirent->d_ino);
+       put_user(namlen, &dirent->d_namlen);
+       put_user(reclen, &dirent->d_reclen);
+       copy_to_user(dirent->d_name, name, namlen);
+       put_user(0, dirent->d_name + namlen);
+       ((char *) dirent) += reclen;
+       buf->curr = dirent;
+       buf->count -= reclen;
+       return 0;
+}
+
+asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
+{
+       struct file * file;
+       struct sunos_dirent * lastdirent;
+       struct sunos_dirent_callback buf;
+       int error = -EBADF;
+       void *dirent = (void *)A(u_dirent);
+
+       lock_kernel();
+       if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+               goto out;
+       error = -ENOTDIR;
+       if (!file->f_op || !file->f_op->readdir)
+               goto out;
+       error = -EINVAL;
+       if(cnt < (sizeof(struct sunos_dirent) + 255))
+               goto out;
+
+       buf.curr = (struct sunos_dirent *) dirent;
+       buf.previous = NULL;
+       buf.count = cnt;
+       buf.error = 0;
+       error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir);
+       if (error < 0)
+               goto out;
+       lastdirent = buf.previous;
+       if (!lastdirent) {
+               error = buf.error;
+       } else {
+               put_user(file->f_pos, &lastdirent->d_off);
+               error = cnt - buf.count;
+       }
+out:
+       unlock_kernel();
+       return error;
+}
+
+/* Old sunos getdirentries, severely broken compatibility stuff here. */
+struct sunos_direntry {
+    u32                d_ino;
+    u16                d_reclen;
+    u16                d_namlen;
+    char       d_name[1];
+};
+
+struct sunos_direntry_callback {
+    struct sunos_direntry *curr;
+    struct sunos_direntry *previous;
+    int count;
+    int error;
+};
+
+static int sunos_filldirentry(void * __buf, const char * name, int namlen,
+                             off_t offset, ino_t ino)
+{
+       struct sunos_direntry * dirent;
+       struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf;
+       int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+       buf->error = -EINVAL;   /* only used if we fail.. */
+       if (reclen > buf->count)
+               return -EINVAL;
+       dirent = buf->previous;
+       dirent = buf->curr;
+       buf->previous = dirent;
+       put_user(ino, &dirent->d_ino);
+       put_user(namlen, &dirent->d_namlen);
+       put_user(reclen, &dirent->d_reclen);
+       copy_to_user(dirent->d_name, name, namlen);
+       put_user(0, dirent->d_name + namlen);
+       ((char *) dirent) += reclen;
+       buf->curr = dirent;
+       buf->count -= reclen;
+       return 0;
+}
+
+asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent,
+                                  int cnt, u32 u_basep)
+{
+       struct file * file;
+       struct sunos_direntry * lastdirent;
+       struct sunos_direntry_callback buf;
+       int error = -EBADF;
+       void *dirent = (void *) A(u_dirent);
+       unsigned int *basep = (unsigned int *)A(u_basep);
+
+       lock_kernel();
+       if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+               goto out;
+       error = -ENOTDIR;
+       if (!file->f_op || !file->f_op->readdir)
+               goto out;
+       error = -EINVAL;
+       if(cnt < (sizeof(struct sunos_direntry) + 255))
+               goto out;
+
+       buf.curr = (struct sunos_direntry *) dirent;
+       buf.previous = NULL;
+       buf.count = cnt;
+       buf.error = 0;
+       error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry);
+       if (error < 0)
+               goto out;
+       lastdirent = buf.previous;
+       if (!lastdirent) {
+               error = buf.error;
+       } else {
+               put_user(file->f_pos, basep);
+               error = cnt - buf.count;
+       }
+out:
+       unlock_kernel();
+       return error;
+}
+
+asmlinkage int sunos_getdomainname(u32 u_name, int len)
+{
+        int nlen = strlen(system_utsname.domainname);
+       int ret = -EFAULT;
+       char *name = (char *)A(u_name);
+
+       lock_kernel();
+        if (nlen < len)
+                len = nlen;
+
+       if(len > __NEW_UTS_LEN)
+               goto out;
+       if(copy_to_user(name, system_utsname.domainname, len))
+               goto out;
+       ret = 0;
+out:
+       unlock_kernel();
+       return ret;
+}
+
+struct sunos_utsname {
+       char sname[9];
+       char nname[9];
+       char nnext[56];
+       char rel[9];
+       char ver[9];
+       char mach[9];
+};
+
+asmlinkage int sunos_uname(u32 u_name)
+{
+       struct sunos_utsname *name = (struct sunos_utsname *)A(u_name);
+       int ret = -EFAULT;
+
+       lock_kernel();
+       if(!name)
+               goto out;
+       if(copy_to_user(&name->sname[0],
+                       &system_utsname.sysname[0],
+                       sizeof(name->sname) - 1))
+               goto out;
+       copy_to_user(&name->nname[0],
+                    &system_utsname.nodename[0],
+                    sizeof(name->nname) - 1);
+       put_user('\0', &name->nname[8]);
+       copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
+       copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
+       copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
+       ret = 0;
+out:
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_nosys(void)
+{
+       struct pt_regs *regs;
+
+       lock_kernel();
+       regs = current->tss.kregs;
+       current->tss.sig_address = regs->tpc;
+       current->tss.sig_desc = regs->u_regs[UREG_G1];
+       send_sig(SIGSYS, current, 1);
+       printk("Process makes ni_syscall number %d, register dump:\n",
+              (int) regs->u_regs[UREG_G1]);
+       show_regs(regs);
+       unlock_kernel();
+       return -ENOSYS;
+}
+
+/* This is not a real and complete implementation yet, just to keep
+ * the easy SunOS binaries happy.
+ */
+asmlinkage int sunos_fpathconf(int fd, int name)
+{
+       int ret;
+
+       lock_kernel();
+       switch(name) {
+       case _PCONF_LINK:
+               ret = LINK_MAX;
+               break;
+       case _PCONF_CANON:
+               ret = MAX_CANON;
+               break;
+       case _PCONF_INPUT:
+               ret = MAX_INPUT;
+               break;
+       case _PCONF_NAME:
+               ret = NAME_MAX;
+               break;
+       case _PCONF_PATH:
+               ret = PATH_MAX;
+               break;
+       case _PCONF_PIPE:
+               ret = PIPE_BUF;
+               break;
+       case _PCONF_CHRESTRICT:         /* XXX Investigate XXX */
+               ret = 1;
+               break;
+       case _PCONF_NOTRUNC:            /* XXX Investigate XXX */
+       case _PCONF_VDISABLE:
+               ret = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_pathconf(u32 u_path, int name)
+{
+       int ret;
+
+       lock_kernel();
+       ret = sunos_fpathconf(0, name); /* XXX cheese XXX */
+       unlock_kernel();
+       return ret;
+}
+
+/* SunOS mount system call emulation */
+extern asmlinkage int
+sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp);
+
+asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp)
+{
+       int ret;
+
+       /* SunOS binaries expect that select won't change the tvp contents */
+       lock_kernel();
+       current->personality |= STICKY_TIMEOUTS;
+       ret = sys32_select (width, inp, outp, exp, tvp);
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage void sunos_nop(void)
+{
+       return;
+}
+
+/* XXXXXXXXXX SunOS mount/umount. XXXXXXXXXXX */
+#define SMNT_RDONLY       1
+#define SMNT_NOSUID       2
+#define SMNT_NEWTYPE      4
+#define SMNT_GRPID        8
+#define SMNT_REMOUNT      16
+#define SMNT_NOSUB        32
+#define SMNT_MULTI        64
+#define SMNT_SYS5         128
+
+struct sunos_fh_t {
+       char fh_data [NFS_FHSIZE];
+};
+
+struct sunos_nfs_mount_args {
+       struct sockaddr_in  *addr; /* file server address */
+       struct nfs_fh *fh;     /* File handle to be mounted */
+       int        flags;      /* flags */
+       int        wsize;      /* write size in bytes */
+       int        rsize;      /* read size in bytes */
+       int        timeo;      /* initial timeout in .1 secs */
+       int        retrans;    /* times to retry send */
+       char       *hostname;  /* server's hostname */
+       int        acregmin;   /* attr cache file min secs */
+       int        acregmax;   /* attr cache file max secs */
+       int        acdirmin;   /* attr cache dir min secs */
+       int        acdirmax;   /* attr cache dir max secs */
+       char       *netname;   /* server's netname */
+};
+
+extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern dev_t get_unnamed_dev(void);
+extern void put_unnamed_dev(dev_t);
+extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
+extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
+extern asmlinkage int sys_socket(int family, int type, int protocol);
+extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+
+
+/* Bind the socket on a local reserved port and connect it to the
+ * remote server.  This on Linux/i386 is done by the mount program,
+ * not by the kernel. 
+ */
+/* XXXXXXXXXXXXXXXXXXXX */
+static int
+sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
+{
+       struct sockaddr_in local;
+       struct sockaddr_in server;
+       int    try_port;
+       int    ret;
+       struct socket *socket;
+       struct inode  *inode;
+       struct file   *file;
+
+       file = current->files->fd [fd];
+       inode = file->f_inode;
+       if (!inode || !inode->i_sock)
+               return 0;
+
+       socket = &inode->u.socket_i;
+       local.sin_family = AF_INET;
+       local.sin_addr.s_addr = INADDR_ANY;
+
+       /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */
+       try_port = 1024;
+       do {
+               local.sin_port = htons (--try_port);
+               ret = socket->ops->bind(socket, (struct sockaddr*)&local,
+                                       sizeof(local));
+       } while (ret && try_port > (1024 / 2));
+
+       if (ret)
+               return 0;
+
+       server.sin_family = AF_INET;
+       server.sin_addr = addr->sin_addr;
+       server.sin_port = NFS_PORT;
+
+       /* Call sys_connect */
+       ret = socket->ops->connect (socket, (struct sockaddr *) &server,
+                                   sizeof (server), file->f_flags);
+       if (ret < 0)
+               return 0;
+       return 1;
+}
+
+/* XXXXXXXXXXXXXXXXXXXX */
+static int get_default (int value, int def_value)
+{
+    if (value)
+       return value;
+    else
+       return def_value;
+}
+
+/* XXXXXXXXXXXXXXXXXXXX */
+asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
+{
+       int  ret = -ENODEV;
+       int  server_fd;
+       char *the_name;
+       struct nfs_mount_data linux_nfs_mount;
+       struct sunos_nfs_mount_args *sunos_mount = data;
+       dev_t dev;
+
+       /* Ok, here comes the fun part: Linux's nfs mount needs a
+        * socket connection to the server, but SunOS mount does not
+        * require this, so we use the information on the destination
+        * address to create a socket and bind it to a reserved
+        * port on this system
+        */
+       server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       if (server_fd < 0)
+               return -ENXIO;
+
+       if (!sunos_nfs_get_server_fd (server_fd, sunos_mount->addr)){
+               sys_close (server_fd);
+               return -ENXIO;
+       }
+
+       /* Now, bind it to a locally reserved port */
+       linux_nfs_mount.version  = NFS_MOUNT_VERSION;
+       linux_nfs_mount.flags    = sunos_mount->flags;
+       linux_nfs_mount.addr     = *sunos_mount->addr;
+       linux_nfs_mount.root     = *sunos_mount->fh;
+       linux_nfs_mount.fd       = server_fd;
+       
+       linux_nfs_mount.rsize    = get_default (sunos_mount->rsize, 8192);
+       linux_nfs_mount.wsize    = get_default (sunos_mount->wsize, 8192);
+       linux_nfs_mount.timeo    = get_default (sunos_mount->timeo, 10);
+       linux_nfs_mount.retrans  = sunos_mount->retrans;
+       
+       linux_nfs_mount.acregmin = sunos_mount->acregmin;
+       linux_nfs_mount.acregmax = sunos_mount->acregmax;
+       linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
+       linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
+
+       if (getname (sunos_mount->hostname, &the_name))
+               return -EFAULT;
+
+       strncpy (linux_nfs_mount.hostname, the_name, 254);
+       linux_nfs_mount.hostname [255] = 0;
+       putname (the_name);
+
+       dev = get_unnamed_dev ();
+       
+       ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
+       if (ret)
+           put_unnamed_dev(dev);
+
+       return ret;
+}
+
+/* XXXXXXXXXXXXXXXXXXXX */
+asmlinkage int
+sunos_mount(char *type, char *dir, int flags, void *data)
+{
+       int linux_flags = MS_MGC_MSK; /* new semantics */
+       int ret = -EINVAL;
+       char *dev_fname = 0;
+
+       lock_kernel();
+       /* We don't handle the integer fs type */
+       if ((flags & SMNT_NEWTYPE) == 0)
+               goto out;
+
+       /* Do not allow for those flags we don't support */
+       if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5))
+               goto out;
+
+       if(flags & SMNT_REMOUNT)
+               linux_flags |= MS_REMOUNT;
+       if(flags & SMNT_RDONLY)
+               linux_flags |= MS_RDONLY;
+       if(flags & SMNT_NOSUID)
+               linux_flags |= MS_NOSUID;
+       if(strcmp(type, "ext2") == 0) {
+               dev_fname = (char *) data;
+       } else if(strcmp(type, "iso9660") == 0) {
+               dev_fname = (char *) data;
+       } else if(strcmp(type, "minix") == 0) {
+               dev_fname = (char *) data;
+       } else if(strcmp(type, "nfs") == 0) {
+               ret = sunos_nfs_mount (dir, flags, data);
+               goto out;
+        } else if(strcmp(type, "ufs") == 0) {
+               printk("Warning: UFS filesystem mounts unsupported.\n");
+               ret = -ENODEV;
+               goto out;
+       } else if(strcmp(type, "proc")) {
+               ret = -ENODEV;
+               goto out;
+       }
+       ret = sys_mount(dev_fname, dir, type, linux_flags, NULL);
+out:
+       unlock_kernel();
+       return ret;
+}
+
+extern asmlinkage int sys_setsid(void);
+extern asmlinkage int sys_setpgid(pid_t, pid_t);
+
+asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid)
+{
+       int ret;
+
+       /* So stupid... */
+       lock_kernel();
+       if((!pid || pid == current->pid) &&
+          !pgid) {
+               sys_setsid();
+               ret = 0;
+       } else {
+               ret = sys_setpgid(pid, pgid);
+       }
+       unlock_kernel();
+       return ret;
+}
+
+/* So stupid... */
+extern asmlinkage int sys32_wait4(__kernel_pid_t32 pid,
+                                 u32 stat_addr, int options, u32 ru);
+
+asmlinkage int sunos_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru)
+{
+       int ret;
+
+       lock_kernel();
+       ret = sys32_wait4((pid ? pid : ((__kernel_pid_t32)-1)),
+                         stat_addr, options, ru);
+       unlock_kernel();
+       return ret;
+}
+
+extern int kill_pg(int, int, int);
+asmlinkage int sunos_killpg(int pgrp, int sig)
+{
+       int ret;
+
+       lock_kernel();
+       ret = kill_pg(pgrp, sig, 0);
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_audit(void)
+{
+       lock_kernel();
+       printk ("sys_audit\n");
+       unlock_kernel();
+       return -1;
+}
+
+extern asmlinkage u32 sunos_gethostid(void)
+{
+       u32 ret;
+
+       lock_kernel();
+       ret = (((u32)idprom->id_machtype << 24) | ((u32)idprom->id_sernum));
+       unlock_kernel();
+       return ret;
+}
+
+/* sysconf options, for SunOS compatibility */
+#define   _SC_ARG_MAX             1
+#define   _SC_CHILD_MAX           2
+#define   _SC_CLK_TCK             3
+#define   _SC_NGROUPS_MAX         4
+#define   _SC_OPEN_MAX            5
+#define   _SC_JOB_CONTROL         6
+#define   _SC_SAVED_IDS           7
+#define   _SC_VERSION             8
+
+extern asmlinkage s32 sunos_sysconf (int name)
+{
+       s32 ret;
+
+       lock_kernel();
+       switch (name){
+       case _SC_ARG_MAX:
+               ret = ARG_MAX;
+               break;
+       case _SC_CHILD_MAX:
+               ret = CHILD_MAX;
+               break;
+       case _SC_CLK_TCK:
+               ret = HZ;
+               break;
+       case _SC_NGROUPS_MAX:
+               ret = NGROUPS_MAX;
+               break;
+       case _SC_OPEN_MAX:
+               ret = OPEN_MAX;
+               break;
+       case _SC_JOB_CONTROL:
+               ret = 1;        /* yes, we do support job control */
+               break;
+       case _SC_SAVED_IDS:
+               ret = 1;        /* yes, we do support saved uids  */
+               break;
+       case _SC_VERSION:
+               /* mhm, POSIX_VERSION is in /usr/include/unistd.h
+                * should it go on /usr/include/linux?
+                */
+               ret = 199009;
+               break;
+       default:
+               ret = -1;
+               break;
+       };
+       unlock_kernel();
+       return ret;
+}
+
+extern asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg);
+extern asmlinkage int sys_semget (key_t key, int nsems, int semflg);
+extern asmlinkage int sys_semop  (int semid, struct sembuf *tsops, unsigned nsops);
+
+asmlinkage int sunos_semsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 ptr)
+{
+       union semun arg4;
+       int ret;
+
+       lock_kernel();
+       switch (op) {
+       case 0:
+               /* Most arguments match on a 1:1 basis but cmd doesn't */
+               switch(arg3) {
+               case 4:
+                       arg3=GETPID; break;
+               case 5:
+                       arg3=GETVAL; break;
+               case 6:
+                       arg3=GETALL; break;
+               case 3:
+                       arg3=GETNCNT; break;
+               case 7:
+                       arg3=GETZCNT; break;
+               case 8:
+                       arg3=SETVAL; break;
+               case 9:
+                       arg3=SETALL; break;
+               }
+               /* sys_semctl(): */
+               arg4.__pad=(void *)A(ptr); /* value to modify semaphore to */
+               ret = sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4);
+               break;
+       case 1:
+               /* sys_semget(): */
+               ret = sys_semget((key_t)arg1, (int)arg2, (int)arg3);
+               break;
+       case 2:
+               /* sys_semop(): */
+               ret = sys_semop((int)arg1, (struct sembuf *)A(arg2), (unsigned)arg3);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       };
+       unlock_kernel();
+       return ret;
+}
+
+struct msgbuf32 {
+       s32 mtype;
+       char mtext[1];
+};
+
+struct ipc_perm32
+{
+       key_t             key;
+        __kernel_uid_t32  uid;
+        __kernel_gid_t32  gid;
+        __kernel_uid_t32  cuid;
+        __kernel_gid_t32  cgid;
+        __kernel_mode_t32 mode;
+        unsigned short  seq;
+};
+
+struct msqid_ds32
+{
+        struct ipc_perm32 msg_perm;
+        u32 msg_first;
+        u32 msg_last;
+        __kernel_time_t32 msg_stime;
+        __kernel_time_t32 msg_rtime;
+        __kernel_time_t32 msg_ctime;
+        u32 wwait;
+        u32 rwait;
+        unsigned short msg_cbytes;
+        unsigned short msg_qnum;  
+        unsigned short msg_qbytes;
+        __kernel_ipc_pid_t32 msg_lspid;
+        __kernel_ipc_pid_t32 msg_lrpid;
+};
+
+static inline int sunos_msqid_get(struct msqid_ds32 *user,
+                                 struct msqid_ds *kern)
+{
+       if(get_user(kern->msg_perm.key, &user->msg_perm.key)            ||
+          __get_user(kern->msg_perm.uid, &user->msg_perm.uid)          ||
+          __get_user(kern->msg_perm.gid, &user->msg_perm.gid)          ||
+          __get_user(kern->msg_perm.cuid, &user->msg_perm.cuid)        ||
+          __get_user(kern->msg_perm.cgid, &user->msg_perm.cgid)        ||
+          __get_user(kern->msg_stime, &user->msg_stime)                ||
+          __get_user(kern->msg_rtime, &user->msg_rtime)                ||
+          __get_user(kern->msg_ctime, &user->msg_ctime)                ||
+          __get_user(kern->msg_ctime, &user->msg_cbytes)               ||
+          __get_user(kern->msg_ctime, &user->msg_qnum)                 ||
+          __get_user(kern->msg_ctime, &user->msg_qbytes)               ||
+          __get_user(kern->msg_ctime, &user->msg_lspid)                ||
+          __get_user(kern->msg_ctime, &user->msg_lrpid))
+               return -EFAULT;
+       return 0;
+}
+
+static inline int sunos_msqid_put(struct msqid_ds32 *user,
+                                 struct msqid_ds *kern)
+{
+       if(put_user(kern->msg_perm.key, &user->msg_perm.key)            ||
+          __put_user(kern->msg_perm.uid, &user->msg_perm.uid)          ||
+          __put_user(kern->msg_perm.gid, &user->msg_perm.gid)          ||
+          __put_user(kern->msg_perm.cuid, &user->msg_perm.cuid)        ||
+          __put_user(kern->msg_perm.cgid, &user->msg_perm.cgid)        ||
+          __put_user(kern->msg_stime, &user->msg_stime)                ||
+          __put_user(kern->msg_rtime, &user->msg_rtime)                ||
+          __put_user(kern->msg_ctime, &user->msg_ctime)                ||
+          __put_user(kern->msg_ctime, &user->msg_cbytes)               ||
+          __put_user(kern->msg_ctime, &user->msg_qnum)                 ||
+          __put_user(kern->msg_ctime, &user->msg_qbytes)               ||
+          __put_user(kern->msg_ctime, &user->msg_lspid)                ||
+          __put_user(kern->msg_ctime, &user->msg_lrpid))
+               return -EFAULT;
+       return 0;
+}
+
+static inline int sunos_msgbuf_get(struct msgbuf32 *user, struct msgbuf *kern, int len)
+{
+       if(get_user(kern->mtype, &user->mtype)  ||
+          __copy_from_user(kern->mtext, &user->mtext, len))
+               return -EFAULT;
+       return 0;
+}
+
+static inline int sunos_msgbuf_put(struct msgbuf32 *user, struct msgbuf *kern, int len)
+{
+       if(put_user(kern->mtype, &user->mtype)  ||
+          __copy_to_user(user->mtext, kern->mtext, len))
+               return -EFAULT;
+       return 0;
+}
+
+extern asmlinkage int sys_msgget (key_t key, int msgflg);
+extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp,
+                                 size_t msgsz, long msgtyp, int msgflg);
+extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp,
+                                 size_t msgsz, int msgflg);
+extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
+
+asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+{
+       struct sparc_stackf32 *sp;
+       struct msqid_ds kds;
+       struct msgbuf *kmbuf;
+       unsigned long old_fs = get_fs();
+       u32 arg5;
+       int rval;
+
+       lock_kernel();
+       switch(op) {
+       case 0:
+               rval = sys_msgget((key_t)arg1, (int)arg2);
+               break;
+       case 1:
+               if(!sunos_msqid_get((struct msqid_ds32 *)A(arg3), &kds)) {
+                       set_fs(KERNEL_DS);
+                       rval = sys_msgctl((int)arg1, (int)arg2,
+                                         (struct msqid_ds *)A(arg3));
+                       set_fs(old_fs);
+                       if(!rval)
+                               rval = sunos_msqid_put((struct msqid_ds32 *)A(arg3),
+                                                      &kds);
+               } else
+                       rval = -EFAULT;
+               break;
+       case 2:
+               rval = -EFAULT;
+               kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3,
+                                                GFP_KERNEL);
+               if(!kmbuf)
+                       break;
+               sp = (struct sparc_stackf32 *)
+                       (current->tss.kregs->u_regs[UREG_FP] & 0xffffffffUL);
+               if(get_user(arg5, &sp->xxargs[0])) {
+                       rval = -EFAULT;
+                       break;
+               }
+               set_fs(KERNEL_DS);
+               rval = sys_msgrcv((int)arg1, kmbuf, (size_t)arg3,
+                                 (long)arg4, (int)arg5);
+               set_fs(old_fs);
+               if(!rval)
+                       rval = sunos_msgbuf_put((struct msgbuf32 *)A(arg2),
+                                               kmbuf, arg3);
+               kfree(kmbuf);
+               break;
+       case 3:
+               rval = -EFAULT;
+               kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3,
+                                                GFP_KERNEL);
+               if(!kmbuf || sunos_msgbuf_get((struct msgbuf32 *)A(arg2),
+                                             kmbuf, arg3))
+                       break;
+               set_fs(KERNEL_DS);
+               rval = sys_msgsnd((int)arg1, kmbuf, (size_t)arg3, (int)arg4);
+               set_fs(old_fs);
+               kfree(kmbuf);
+               break;
+       default:
+               rval = -EINVAL;
+               break;
+       }
+       unlock_kernel();
+       return rval;
+}
+
+struct shmid_ds32 {
+        struct ipc_perm32       shm_perm;
+        int                     shm_segsz;
+        __kernel_time_t32       shm_atime;
+        __kernel_time_t32       shm_dtime;
+        __kernel_time_t32       shm_ctime;
+        __kernel_ipc_pid_t32    shm_cpid; 
+        __kernel_ipc_pid_t32    shm_lpid; 
+        unsigned short          shm_nattch;
+        unsigned short          shm_npages;
+        u32                    shm_pages;
+        u32                    attaches; 
+};
+                                                        
+static inline int sunos_shmid_get(struct shmid_ds32 *user,
+                                 struct shmid_ds *kern)
+{
+       if(get_user(kern->shm_perm.key, &user->shm_perm.key)            ||
+          __get_user(kern->shm_perm.uid, &user->shm_perm.uid)          ||
+          __get_user(kern->shm_perm.gid, &user->shm_perm.gid)          ||
+          __get_user(kern->shm_perm.cuid, &user->shm_perm.cuid)        ||
+          __get_user(kern->shm_perm.cgid, &user->shm_perm.cgid)        ||
+          __get_user(kern->shm_segsz, &user->shm_segsz)                ||
+          __get_user(kern->shm_atime, &user->shm_atime)                ||
+          __get_user(kern->shm_dtime, &user->shm_dtime)                ||
+          __get_user(kern->shm_ctime, &user->shm_ctime)                ||
+          __get_user(kern->shm_cpid, &user->shm_cpid)                  ||
+          __get_user(kern->shm_lpid, &user->shm_lpid)                  ||
+          __get_user(kern->shm_nattch, &user->shm_nattch)              ||
+          __get_user(kern->shm_npages, &user->shm_npages))
+               return -EFAULT;
+       return 0;
+}
+
+static inline int sunos_shmid_put(struct shmid_ds32 *user,
+                                 struct shmid_ds *kern)
+{
+       if(put_user(kern->shm_perm.key, &user->shm_perm.key)            ||
+          __put_user(kern->shm_perm.uid, &user->shm_perm.uid)          ||
+          __put_user(kern->shm_perm.gid, &user->shm_perm.gid)          ||
+          __put_user(kern->shm_perm.cuid, &user->shm_perm.cuid)        ||
+          __put_user(kern->shm_perm.cgid, &user->shm_perm.cgid)        ||
+          __put_user(kern->shm_segsz, &user->shm_segsz)                ||
+          __put_user(kern->shm_atime, &user->shm_atime)                ||
+          __put_user(kern->shm_dtime, &user->shm_dtime)                ||
+          __put_user(kern->shm_ctime, &user->shm_ctime)                ||
+          __put_user(kern->shm_cpid, &user->shm_cpid)                  ||
+          __put_user(kern->shm_lpid, &user->shm_lpid)                  ||
+          __put_user(kern->shm_nattch, &user->shm_nattch)              ||
+          __put_user(kern->shm_npages, &user->shm_npages))
+               return -EFAULT;
+       return 0;
+}
+
+extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
+extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
+extern asmlinkage int sys_shmdt (char *shmaddr);
+extern asmlinkage int sys_shmget (key_t key, int size, int shmflg);
+
+asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3)
+{
+       struct shmid_ds ksds;
+       unsigned long raddr, old_fs = get_fs();
+       int rval;
+
+       lock_kernel();
+       switch(op) {
+       case 0:
+               /* sys_shmat(): attach a shared memory area */
+               rval = sys_shmat((int)arg1,(char *)A(arg2),(int)arg3,&raddr);
+               if(!rval)
+                       rval = (int) raddr;
+               break;
+       case 1:
+               /* sys_shmctl(): modify shared memory area attr. */
+               if(!sunos_shmid_get((struct shmid_ds32 *)A(arg3), &ksds)) {
+                       set_fs(KERNEL_DS);
+                       rval = sys_shmctl((int)arg1,(int)arg2, &ksds);
+                       set_fs(old_fs);
+                       if(!rval)
+                               rval = sunos_shmid_put((struct shmid_ds32 *)A(arg3),
+                                                      &ksds);
+               } else
+                       rval = -EFAULT;
+               break;
+       case 2:
+               /* sys_shmdt(): detach a shared memory area */
+               rval = sys_shmdt((char *)A(arg1));
+               break;
+       case 3:
+               /* sys_shmget(): get a shared memory area */
+               rval = sys_shmget((key_t)arg1,(int)arg2,(int)arg3);
+               break;
+       default:
+               rval = -EINVAL;
+               break;
+       };
+       unlock_kernel();
+       return rval;
+}
+
+asmlinkage int sunos_open(u32 filename, int flags, int mode)
+{
+       int ret;
+
+       lock_kernel();
+       current->personality |= PER_BSD;
+       ret = sys_open ((char *)A(filename), flags, mode);
+       unlock_kernel();
+       return ret;
+}
+
+#define SUNOS_EWOULDBLOCK 35
+
+/* see the sunos man page read(2v) for an explanation
+   of this garbage. We use O_NDELAY to mark
+   file descriptors that have been set non-blocking 
+   using 4.2BSD style calls. (tridge) */
+
+static inline int check_nonblock(int ret, int fd)
+{
+       if (ret == -EAGAIN && (current->files->fd[fd]->f_flags & O_NDELAY))
+               return -SUNOS_EWOULDBLOCK;
+       return ret;
+}
+
+extern asmlinkage int sys32_read(unsigned int fd, u32 buf, int count);
+extern asmlinkage int sys32_write(unsigned int fd, u32 buf,int count);
+extern asmlinkage int sys32_recv(int fd, u32 ubuf, int size, unsigned flags);
+extern asmlinkage int sys32_send(int fd, u32 buff, int len, unsigned flags);
+extern asmlinkage int sys32_accept(int fd, u32 sa, u32 addrlen);
+extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count);
+extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count);
+
+asmlinkage int sunos_read(unsigned int fd, u32 buf, int count)
+{
+       int ret;
+
+       lock_kernel();
+       ret = check_nonblock(sys32_read(fd, buf, count), fd);
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_readv(u32 fd, u32 vector, s32 count)
+{
+       int ret;
+
+       lock_kernel();
+       ret = check_nonblock(sys32_readv(fd, vector, count), fd);
+       lock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_write(unsigned int fd, u32 buf, int count)
+{
+       int ret;
+
+       lock_kernel();
+       ret = check_nonblock(sys32_write(fd, buf, count), fd);
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_writev(u32 fd, u32 vector, s32 count)
+{
+       int ret;
+
+       lock_kernel();
+       ret = check_nonblock(sys32_writev(fd, vector, count), fd);
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_recv(int fd, u32 ubuf, int size, unsigned flags)
+{
+       int ret;
+
+       lock_kernel();
+       ret = check_nonblock(sys32_recv(fd, ubuf, size, flags), fd);
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_send(int fd, u32 buff, int len, unsigned flags)
+{
+       int ret;
+
+       lock_kernel();
+       ret = check_nonblock(sys32_send(fd, buff, len, flags), fd);
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_accept(int fd, u32 sa, u32 addrlen)
+{
+       int ret;
+
+       lock_kernel();
+       ret = check_nonblock(sys32_accept(fd, sa, addrlen), fd);
+       unlock_kernel();
+       return ret;
+}
+
+#define SUNOS_SV_INTERRUPT 2
+
+extern void check_pending(int signum);
+
+asmlinkage int sunos_sigaction(int signum, u32 action, u32 oldaction)
+{
+       struct sigaction32 new_sa, old_sa;
+       struct sigaction *p;
+       const int sigaction_size = sizeof (struct sigaction32) - sizeof (u32);
+
+       current->personality |= PER_BSD;
+       if(signum < 1 || signum > 32)
+               return -EINVAL;
+
+       p = signum - 1 + current->sig->action;
+
+       if(action) {
+               if (signum==SIGKILL || signum==SIGSTOP)
+                       return -EINVAL;
+               memset(&new_sa, 0, sizeof(struct sigaction32));
+               if(copy_from_user(&new_sa, (struct sigaction32 *)A(action),
+                                 sigaction_size))
+                       return -EFAULT;
+               if (((__sighandler_t)A(new_sa.sa_handler) != SIG_DFL) &&
+                    (__sighandler_t)A(new_sa.sa_handler) != SIG_IGN) {
+                       if(verify_area(VERIFY_READ,
+                                      (__sighandler_t)A(new_sa.sa_handler), 1))
+                               return -EFAULT;
+               }
+               new_sa.sa_flags ^= SUNOS_SV_INTERRUPT;
+       }
+
+       if (oldaction) {
+               /* In the clone() case we could copy half consistant
+                * state to the user, however this could sleep and
+                * deadlock us if we held the signal lock on SMP.  So for
+                * now I take the easy way out and do no locking.
+                * But then again we don't support SunOS lwp's anyways ;-)
+                */
+               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);
+
+               if (old_sa.sa_flags & SA_RESTART)
+                       old_sa.sa_flags &= ~SA_RESTART;
+               else
+                       old_sa.sa_flags |= SUNOS_SV_INTERRUPT;
+               if (copy_to_user((struct sigaction32 *)A(oldaction),
+                                &old_sa, sigaction_size))
+                        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))0;
+               check_pending(signum);
+               spin_unlock_irq(&current->sig->siglock);
+       }
+       return 0;
+}
+
+
+extern asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+                                    u32 optval, int optlen);
+extern asmlinkage int sys32_getsockopt(int fd, int level, int optname,
+                                    u32 optval, u32 optlen);
+
+asmlinkage int sunos_setsockopt(int fd, int level, int optname, u32 optval,
+                               int optlen)
+{
+       int tr_opt = optname;
+       int ret;
+
+       lock_kernel();
+       if (level == SOL_IP) {
+               /* Multicast socketopts (ttl, membership) */
+               if (tr_opt >=2 && tr_opt <= 6)
+                       tr_opt += 30;
+       }
+       ret = sys32_setsockopt(fd, level, tr_opt, optval, optlen);
+       unlock_kernel();
+       return ret;
+}
+
+asmlinkage int sunos_getsockopt(int fd, int level, int optname,
+                               u32 optval, u32 optlen)
+{
+       int tr_opt = optname;
+       int ret;
+
+       lock_kernel();
+       if (level == SOL_IP) {
+               /* Multicast socketopts (ttl, membership) */
+               if (tr_opt >=2 && tr_opt <= 6)
+                       tr_opt += 30;
+       }
+       ret = sys32_getsockopt(fd, level, tr_opt, optval, optlen);
+       unlock_kernel();
+       return ret;
+}
index 61ed19b468f946177a48bb8cca326187399e515a..eda0ff32632ff92c711aeea916f6e03eaa3b6126 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.16 1997/06/16 05:37:41 davem Exp $
+/* $Id: systbls.S,v 1.21 1997/07/05 07:09:17 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -53,15 +53,15 @@ sys_call_table32:
        .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_no_modules
+/*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_no_modules, sys32_personality, sys_prof, sys_break, sys_lock
+/*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_no_modules, sys32_no_modules, sys32_no_modules, sys_getpgid
+/*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
@@ -111,7 +111,7 @@ sys_call_table:
        .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_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
@@ -130,72 +130,72 @@ sys_call_table:
 
        /* Now the 32-bit SunOS syscall table. */
 
-       .align 4
+       .align 8
        .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, sys_creat
-       .xword sys_link, sys_unlink, sunos_execv
-       .xword sys_chdir, sunos_nosys, sys_mknod
-       .xword sys_chmod, sys_chown, sunos_brk
-       .xword sunos_nosys, sys_lseek, sunos_getpid
+       .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 sys_access, sunos_nosys, sunos_nosys
-       .xword sys_sync, sys_kill, sys_newstat
-       .xword sunos_nosys, sys_newlstat, sys_dup
+       .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, sys_acct, sunos_nosys
-       .xword sunos_mctl, sunos_ioctl, sys_reboot
-       .xword sunos_nosys, sys_symlink, sys_readlink
-       .xword sys32_execve, sys_umask, sys_chroot
-       .xword sys_newfstat, sunos_nosys, sys_getpagesize
-       .xword sys_msync, sys_vfork, 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, sys_munmap
-       .xword sys_mprotect, sunos_madvise, sys_vhangup
-       .xword sunos_nosys, sunos_mincore, sys_getgroups
-       .xword sys_setgroups, sys_getpgrp, sunos_setpgrp
-       .xword sys_setitimer, sunos_nosys, sys_swapon
-       .xword sys_getitimer, sys_gethostname, sys_sethostname
+       .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 sys_fcntl, sunos_select, sunos_nop
+       .xword sys32_fcntl, sunos_select, sunos_nop
        .xword sys_fsync, sys_setpriority, sys_socket
-       .xword sys_connect, sunos_accept
+       .xword sys32_connect, sunos_accept
 /*100*/        .xword sys_getpriority, sunos_send, sunos_recv
-       .xword sunos_nosys, sys_bind, sunos_setsockopt
+       .xword sunos_nosys, sys32_bind, sunos_setsockopt
        .xword sys_listen, sunos_nosys, sunos_sigaction
        .xword sunos_sigblock, sunos_sigsetmask, sys_sigpause
-       .xword sys_sigstack, sys_recvmsg, sys_sendmsg
-       .xword sunos_nosys, sys_gettimeofday, sys_getrusage
+       .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, sys_recvfrom, sys_setreuid
-       .xword sys_setregid, sys_rename, sys_truncate
-       .xword sys_ftruncate, sys_flock, sunos_nosys
-       .xword sys_sendto, sys_shutdown, sys_socketpair
-       .xword sys_mkdir, sys_rmdir, sys_utimes
-       .xword sys_sigreturn, sunos_nosys, sys_getpeername
-       .xword sunos_gethostid, sunos_nosys, sys_getrlimit
-       .xword sys_setrlimit, sunos_killpg, sunos_nosys
+       .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 sys_getsockname, sunos_nosys, sunos_nosys
-       .xword sunos_poll, sunos_nosys, sunos_nosys
-       .xword sunos_getdirentries, sys_statfs, sys_fstatfs
-       .xword sys_umount, sunos_nosys, sunos_nosys
-       .xword sunos_getdomainname, sys_setdomainname
-       .xword sunos_nosys, sys_quotactl, sunos_nosys
-       .xword sunos_mount, sys_ustat, sunos_semsys
+/*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, sys_sigpending, 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
index 3f15fcb54e65b39a6f3dd4c5b38d81a3e4f5a18c..ad40a5fb5317e87bc2a7334cf36dd9d77261ce5e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.2 1997/04/10 03:02:35 davem Exp $
+/* $Id: time.c,v 1.3 1997/06/17 13:25:29 jj Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -146,9 +146,6 @@ static int has_low_battery(void)
        return (data1 == data2);        /* Was the write blocked? */
 }
 
-/* XXX HACK HACK HACK, delete me soon */
-static struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX];
-static int XXX_sbus_nranges;
 
 /* Probe for the real time clock chip. */
 __initfunc(static void clock_probe(void))
@@ -157,6 +154,10 @@ __initfunc(static void clock_probe(void))
        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;
+
        node = prom_getchild(prom_root_node);
        sbusnd = prom_searchsiblings(node, "sbus");
        node = prom_getchild(sbusnd);
index 824a3ddb4974413aa7441af6568265e7711aa7c5..ac3e79958b5df52b18d825da981318e32f31d7a6 100644 (file)
@@ -1,14 +1,15 @@
-/* $Id: traps.c,v 1.19 1997/06/05 06:22:49 davem Exp $
- * arch/sparc/kernel/traps.c
+/* $Id: traps.c,v 1.29 1997/07/05 09:52:38 davem Exp $
+ * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 /*
- * I hate traps on the sparc, grrr...
+ * I like traps on v9, :))))
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>  /* for jiffies */
 #include <linux/kernel.h>
 #include <linux/signal.h>
@@ -123,6 +124,8 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs)
        int i;
 #endif
 
+       if(strcmp(current->comm, "bash.sunos"))
+               return;
        printk("SYS[%s:%d]: PC(%016lx) <%3d> ",
               current->comm, current->pid, regs->tpc, (int)g1);
 #ifdef VERBOSE_SYSCALL_TRACING
@@ -153,53 +156,12 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs)
 
 unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs)
 {
-       printk("ret[%016lx]\n", retval);
+       if(!strcmp(current->comm, "bash.sunos"))
+               printk("ret[%016lx]\n", retval);
        return retval;
 }
 #endif /* SYSCALL_TRACING */
 
-#if 0
-void user_rtrap_report(struct pt_regs *regs)
-{
-       static int hits = 0;
-
-       /* Bwahhhhrggg... */
-       if(regs->tpc == 0x1f294UL && ++hits == 2) {
-               register unsigned long ctx asm("o4");
-               register unsigned long paddr asm("o5");
-               unsigned long cwp, wstate;
-
-               printk("RT[%016lx:%016lx] ", regs->tpc, regs->u_regs[UREG_I6]);
-               __asm__ __volatile__("rdpr %%cwp, %0" : "=r" (cwp));
-               __asm__ __volatile__("rdpr %%wstate, %0" : "=r" (wstate));
-               printk("CWP[%d] WSTATE[%016lx]\n"
-                      "TSS( ksp[%016lx] kpc[%016lx] wstate[%016lx] w_saved[%d] flgs[%x]"
-                      " cur_ds[%d] )\n", cwp, wstate,
-                      current->tss.ksp, current->tss.kpc, current->tss.wstate,
-                      (int) current->tss.w_saved, current->tss.flags,
-                      current->tss.current_ds);
-               __asm__ __volatile__("
-               rdpr    %%pstate, %%o3
-               wrpr    %%o3, %2, %%pstate
-               mov     %%g7, %%o5
-               mov     0x10, %%o4
-               ldxa    [%%o4] %3, %%o4
-               wrpr    %%o3, 0x0, %%pstate
-               " : "=r" (ctx), "=r" (paddr)
-                 : "i" (PSTATE_MG|PSTATE_IE), "i" (ASI_DMMU));
-
-               printk("MMU[ppgd(%016lx)sctx(%d)] ", paddr, ctx);
-               printk("mm->context(%016lx) mm->pgd(%p)\n",
-                      current->mm->context, current->mm->pgd);
-               printk("TASK: signal[%016lx] blocked[%016lx]\n",
-                      current->signal, current->blocked);
-               show_regs(regs);
-               while(1)
-                       barrier();
-       }
-}
-#endif
-
 void bad_trap (struct pt_regs *regs, long lvl)
 {
        lock_kernel ();
@@ -221,168 +183,44 @@ void bad_trap_tl1 (struct pt_regs *regs, long lvl)
 {
        char buffer[24];
        
-       lock_kernel ();
+       lock_kernel();
        sprintf (buffer, "Bad trap %lx at tl>0", lvl);
        die_if_kernel (buffer, regs);
+       unlock_kernel();
 }
 
 void data_access_exception (struct pt_regs *regs)
 {
-       lock_kernel ();
-       printk ("Unhandled data access exception ");
-       printk("sfsr %016lx sfar %016lx\n", spitfire_get_dsfsr(), spitfire_get_sfar());
-       die_if_kernel("Data access exception", regs);
+       send_sig(SIGSEGV, current, 1);
 }
 
 void do_dae(struct pt_regs *regs)
 {
-       printk("DAE: at %016lx\n", regs->tpc);
-       while(1)
-               barrier();
+       send_sig(SIGSEGV, current, 1);
 }
 
 void instruction_access_exception (struct pt_regs *regs)
 {
-       lock_kernel ();
-       printk ("Unhandled instruction access exception ");
-       printk("sfsr %016lx\n", spitfire_get_isfsr());
-       die_if_kernel("Instruction access exception", regs);
+       send_sig(SIGSEGV, current, 1);
 }
 
 void do_iae(struct pt_regs *regs)
 {
-       printk("IAE at %016lx\n", regs->tpc);
-       while(1)
-               barrier();
-}
-
-static unsigned long init_fsr = 0x0UL;
-static unsigned int init_fregs[64] __attribute__ ((aligned (64))) =
-                { ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
-                 ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
-                 ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
-                 ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
-                 ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
-                 ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
-                 ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
-                 ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U };
-
-void do_fpdis(struct pt_regs *regs)
-{
-       lock_kernel();
-
-       regs->tstate |= TSTATE_PEF;
-       fprs_write(FPRS_FEF);
-
-       /* This is allowed now because the V9 ABI varargs passes floating
-        * point args in floating point registers, so vsprintf() and sprintf()
-        * cause problems.  Luckily we never actually pass floating point values
-        * to those routines in the kernel and the code generated just does
-        * stores of them to the stack.  Therefore, for the moment this fix
-        * is sufficient. -DaveM
-        */
-       if(regs->tstate & TSTATE_PRIV)
-               goto out;
-
-#ifndef __SMP__
-       if(last_task_used_math == current)
-               goto out;
-       if(last_task_used_math) {
-               struct task_struct *fptask = last_task_used_math;
-
-               if(fptask->tss.flags & SPARC_FLAG_32BIT)
-                       fpsave32((unsigned long *)&fptask->tss.float_regs[0],
-                                &fptask->tss.fsr);
-               else
-                       fpsave((unsigned long *)&fptask->tss.float_regs[0],
-                              &fptask->tss.fsr);
-       }
-       last_task_used_math = current;
-       if(current->used_math) {
-               if(current->tss.flags & SPARC_FLAG_32BIT)
-                       fpload32(&current->tss.float_regs[0],
-                                &current->tss.fsr);
-               else
-                       fpload(&current->tss.float_regs[0],
-                              &current->tss.fsr);
-       } else {
-               /* Set inital sane state. */
-               fpload(&init_fregs[0], &init_fsr);
-               current->used_math = 1;
-       }
-#else
-       if(!current->used_math) {
-               fpload(&init_fregs[0], &init_fsr);
-               current->used_math = 1;
-       } else {
-               if(current->tss.flags & SPARC_FLAG_32BIT)
-                       fpload32(&current->tss.float_regs[0],
-                                &current->tss.fsr);
-               else
-                       fpload(&current->tss.float_regs[0],
-                              &current->tss.fsr);
-       }
-       current->flags |= PF_USEDFPU;
-#endif
-#ifndef __SMP__
-out:
-#endif
-       unlock_kernel();
+       send_sig(SIGSEGV, current, 1);
 }
 
-static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
-static unsigned long fake_fsr;
-
 void do_fpe_common(struct pt_regs *regs)
 {
-       static int calls = 0;
-#ifndef __SMP__
-       struct task_struct *fpt = last_task_used_math;
-#else
-       struct task_struct *fpt = current;
-#endif
-
-       lock_kernel();
-       fprs_write(FPRS_FEF);
-
-#ifndef __SMP__
-       if(!fpt) {
-#else
-       if(!(fpt->flags & PF_USEDFPU)) {
-#endif
-               fpsave(&fake_regs[0], &fake_fsr);
-               regs->tstate &= ~(TSTATE_PEF);
-               goto out;
-       }
-       if(fpt->tss.flags & SPARC_FLAG_32BIT)
-               fpsave32((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr);
-       else
-               fpsave((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr);
-       fpt->tss.sig_address = regs->tpc;
-       fpt->tss.sig_desc = SUBSIG_FPERROR;
-#ifdef __SMP__
-       fpt->flags &= ~PF_USEDFPU;
-#endif
        if(regs->tstate & TSTATE_PRIV) {
-               printk("WARNING: FPU exception from kernel mode. at pc=%016lx\n",
-                      regs->tpc);
                regs->tpc = regs->tnpc;
                regs->tnpc += 4;
-               calls++;
-               if(calls > 2)
-                       die_if_kernel("Too many Penguin-FPU traps from kernel mode",
-                                     regs);
-               goto out;
+       } else {
+               lock_kernel();
+               current->tss.sig_address = regs->tpc;
+               current->tss.sig_desc = SUBSIG_FPERROR;
+               send_sig(SIGFPE, current, 1);
+               unlock_kernel();
        }
-       send_sig(SIGFPE, fpt, 1);
-#ifndef __SMP__
-       last_task_used_math = NULL;
-#endif
-       regs->tstate &= ~TSTATE_PEF;
-       if(calls > 0)
-               calls = 0;
-out:
-       unlock_kernel();
 }
 
 void do_fpieee(struct pt_regs *regs)
@@ -397,16 +235,16 @@ void do_fpother(struct pt_regs *regs)
 
 void do_tof(struct pt_regs *regs)
 {
-       printk("TOF: at %016lx\n", regs->tpc);
-       while(1)
-               barrier();
+       if(regs->tstate & TSTATE_PRIV)
+               die_if_kernel("Penguin overflow trap from kernel mode", regs);
+       current->tss.sig_address = regs->tpc;
+       current->tss.sig_desc = SUBSIG_TAG; /* as good as any */
+       send_sig(SIGEMT, current, 1);
 }
 
 void do_div0(struct pt_regs *regs)
 {
-       printk("DIV0: at %016lx\n", regs->tpc);
-       while(1)
-               barrier();
+       send_sig(SIGILL, current, 1);
 }
 
 void instruction_dump (unsigned int *pc)
@@ -426,7 +264,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
        /* Amuse the user. */
        printk(
 "              \\|/ ____ \\|/\n"
-"              \"@'/ .` \\`@\"\n"
+"              \"@'/ .. \\`@\"\n"
 "              /_| \\__/ |_\\\n"
 "                 \\__U_/\n");
 
@@ -437,17 +275,15 @@ void die_if_kernel(char *str, struct pt_regs *regs)
                struct reg_window *rw = (struct reg_window *)
                        (regs->u_regs[UREG_FP] + STACK_BIAS);
 
-               if(rw) {
+               /* Stop the back trace when we hit userland or we
+                * find some badly aligned kernel stack.
+                */
+               while(rw                                        &&
+                     (((unsigned long) rw) >= PAGE_OFFSET)     &&
+                     !(((unsigned long) rw) & 0x7)) {
                        printk("Caller[%016lx]\n", rw->ins[7]);
                        rw = (struct reg_window *)
                                (rw->ins[6] + STACK_BIAS);
-                       if(rw) {
-                               printk("Caller[%016lx]\n", rw->ins[7]);
-                               rw = (struct reg_window *)
-                                       (rw->ins[6] + STACK_BIAS);
-                               if(rw)
-                                       printk("Caller[%016lx]\n", rw->ins[7]);
-                       }
                }
        }
        printk("Instruction DUMP:");
@@ -465,16 +301,6 @@ void do_illegal_instruction(struct pt_regs *regs)
        lock_kernel();
        if(tstate & TSTATE_PRIV)
                die_if_kernel("Kernel illegal instruction", regs);
-#if 1
-       {
-               unsigned int insn;
-
-               printk("Ill instr. at pc=%016lx ", pc);
-               get_user(insn, ((unsigned int *)pc));
-               printk("insn=[%08x]\n", insn);
-               show_regs(regs);
-       }
-#endif
        current->tss.sig_address = pc;
        current->tss.sig_desc = SUBSIG_ILLINST;
        send_sig(SIGILL, current, 1);
@@ -483,13 +309,11 @@ void do_illegal_instruction(struct pt_regs *regs)
 
 void mem_address_unaligned(struct pt_regs *regs)
 {
-       printk("AIEEE: do_mna at %016lx\n", regs->tpc);
-       show_regs(regs);
        if(regs->tstate & TSTATE_PRIV) {
-               printk("MNA from kernel, spinning\n");
-               sti();
-               while(1)
-                       barrier();
+               extern void kernel_unaligned_trap(struct pt_regs *regs,
+                                                 unsigned int insn);
+
+               return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
        } else {
                current->tss.sig_address = regs->tpc;
                current->tss.sig_desc = SUBSIG_PRIVINST;
@@ -499,16 +323,17 @@ void mem_address_unaligned(struct pt_regs *regs)
 
 void do_privop(struct pt_regs *regs)
 {
-       printk("PRIVOP: at %016lx\n", regs->tpc);
-       while(1)
-               barrier();
+       current->tss.sig_address = regs->tpc;
+       current->tss.sig_desc = SUBSIG_PRIVINST;
+       send_sig(SIGILL, current, 1);
 }
 
 void do_privact(struct pt_regs *regs)
 {
-       printk("PRIVACT: at %016lx\n", regs->tpc);
-       while(1)
-               barrier();
+       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,
@@ -537,11 +362,6 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon
        }
        current->tss.sig_address = pc;
        current->tss.sig_desc = SUBSIG_PRIVINST;
-#if 0
-       show_regs (regs);
-       instruction_dump ((unsigned long *) regs->tpc);
-       printk ("do_MNA!\n");
-#endif
        send_sig(SIGBUS, current, 1);
        unlock_kernel();
 }
@@ -554,6 +374,134 @@ void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc
        unlock_kernel();
 }
 
+/* Trap level 1 stuff or other traps we should never see... */
+void do_cee(struct pt_regs *regs)
+{
+       die_if_kernel("TL0: Cache Error Exception", regs);
+}
+
+void do_cee_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: Cache Error Exception", regs);
+}
+
+void do_dae_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: Data Access Exception", regs);
+}
+
+void do_iae_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: Instruction Access Exception", regs);
+}
+
+void do_div0_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: DIV0 Exception", regs);
+}
+
+void do_fpdis_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: FPU Disabled", regs);
+}
+
+void do_fpieee_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: FPU IEEE Exception", regs);
+}
+
+void do_fpother_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: FPU Other Exception", regs);
+}
+
+void do_ill_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: Illegal Instruction Exception", regs);
+}
+
+void do_irq_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: IRQ Exception", regs);
+}
+
+void do_lddfmna(struct pt_regs *regs)
+{
+       die_if_kernel("TL0: LDDF Exception", regs);
+}
+
+void do_lddfmna_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: LDDF Exception", regs);
+}
+
+void do_stdfmna(struct pt_regs *regs)
+{
+       die_if_kernel("TL0: STDF Exception", regs);
+}
+
+void do_stdfmna_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: STDF Exception", regs);
+}
+
+void do_paw(struct pt_regs *regs)
+{
+       die_if_kernel("TL0: Phys Watchpoint Exception", regs);
+}
+
+void do_paw_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: Phys Watchpoint Exception", regs);
+}
+
+void do_vaw(struct pt_regs *regs)
+{
+       die_if_kernel("TL0: Virt Watchpoint Exception", regs);
+}
+
+void do_vaw_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: Virt Watchpoint Exception", regs);
+}
+
+void do_tof_tl1(struct pt_regs *regs)
+{
+       die_if_kernel("TL1: Tag Overflow Exception", regs);
+}
+
+#ifdef CONFIG_EC_FLUSH_TRAP
+void cache_flush_trap(struct pt_regs *regs)
+{
+#ifndef __SMP__
+       unsigned node = linux_cpus[get_cpuid()].prom_node;
+#else
+#error SMP not supported on sparc64 yet
+#endif
+       int size = prom_getintdefault(node, "ecache-size", 512*1024);
+       int i, j;
+       unsigned long addr, page_nr;
+
+       regs->tpc = regs->tnpc;
+       regs->tnpc = regs->tnpc + 4;
+       if (!suser()) return;
+       size >>= PAGE_SHIFT;
+       addr = PAGE_OFFSET - PAGE_SIZE;
+       for (i = 0; i < size; i++) {
+               do {
+                       addr += PAGE_SIZE;
+                       page_nr = MAP_NR(addr);
+                       if (page_nr >= max_mapnr) {
+                               return;
+                       }
+               } while (!PageReserved (mem_map + page_nr));
+               /* E-Cache line size is 64B. Let us pollute it :)) */
+               for (j = 0; j < PAGE_SIZE; j += 64)
+                       __asm__ __volatile__ ("ldx [%0 + %1], %%g1" : : "r" (j), "r" (addr) : "g1");
+       }
+}
+#endif
+
 void trap_init(void)
 {
 }
index 8db708f076dde9b5d72104ae61abe8df3a468258..73bda96d9ea80f4bab339e19bab4b5a0be797d5f 100644 (file)
@@ -1,9 +1,11 @@
-/* $Id: ttable.S,v 1.13 1997/06/02 06:33:34 davem Exp $
+/* $Id: ttable.S,v 1.18 1997/07/05 09:52:41 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
+
        .globl  sparc64_ttable_tl0, sparc64_ttable_tl1
 
 sparc64_ttable_tl0:
@@ -18,7 +20,7 @@ tl0_privop:   TRAP(do_privop)
 tl0_resv012:   BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17)
 tl0_resv018:   BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
 tl0_resv01e:   BTRAP(0x1e) BTRAP(0x1f)
-tl0_fpdis:     TRAP(do_fpdis)
+tl0_fpdis:     TRAP_NOSAVE(do_fpdis)
 tl0_fpieee:    TRAP(do_fpieee)
 tl0_fpother:   TRAP(do_fpother)
 tl0_tof:       TRAP(do_tof)
@@ -124,7 +126,13 @@ tl0_resv15a:       BTRAP(0x15a) BTRAP(0x15b) BTRAP(0x15c) BTRAP(0x15d) BTRAP(0x15e)
 tl0_resv15f:   BTRAP(0x15f) BTRAP(0x160) BTRAP(0x161) BTRAP(0x162) BTRAP(0x163)
 tl0_resv164:   BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168)
 tl0_resv169:   BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) BTRAP(0x16d)
-tl0_resv16e:   BTRAP(0x16e) BTRAP(0x16f) BTRAP(0x170) BTRAP(0x171) BTRAP(0x172)
+tl0_gsctx:     TRAP(sparc64_get_context) TRAP(sparc64_set_context)
+tl0_resv170:   BTRAP(0x170) BTRAP(0x171) 
+#ifdef CONFIG_EC_FLUSH_TRAP
+                                         TRAP(cache_flush_trap)
+#else
+                                         BTRAP(0x172)
+#endif
 tl0_resv173:   BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177)
 tl0_resv178:   BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c)
 tl0_resv17d:   BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f)
@@ -151,7 +159,7 @@ tl1_resv012:        BTRAPTL1(0x12) BTRAPTL1(0x13) BTRAPTL1(0x14) BTRAPTL1(0x15)
 tl1_resv016:   BTRAPTL1(0x16) BTRAPTL1(0x17) BTRAPTL1(0x18) BTRAPTL1(0x19)
 tl1_resv01a:   BTRAPTL1(0x1a) BTRAPTL1(0x1b) BTRAPTL1(0x1c) BTRAPTL1(0x1d)
 tl1_resv01e:   BTRAPTL1(0x1e) BTRAPTL1(0x1f)
-tl1_fpdis:     TRAPTL1(do_fpdis_tl1)
+tl1_fpdis:     TRAP_NOSAVE(do_fpdis)
 tl1_fpieee:    TRAPTL1(do_fpieee_tl1)
 tl1_fpother:   TRAPTL1(do_fpother_tl1)
 tl1_tof:       TRAPTL1(do_tof_tl1)
index 685f8c892afe0abd6db4afb070b026f9a2b7eea3..12f90c21ca521a292cfb517a669ab1a292eeda39 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.1 1997/06/06 10:56:19 jj Exp $
+/* $Id: unaligned.c,v 1.3 1997/06/25 10:12:15 jj Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -18,7 +18,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
-#define DEBUG_MNA
+/* #define DEBUG_MNA */
 
 enum direction {
        load,    /* ld, ldd, ldh, ldsh */
@@ -205,19 +205,19 @@ __asm__ __volatile__ (                                                            \
        "stx    %%g7, [%0 + 8]\n"                                               \
 "0:\n\n\t"                                                                     \
        ".section __ex_table\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"                                           \
+       ".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"                                           \
        ".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"                                               \
-       ".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"                                           \
+       ".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"                                           \
        ".previous\n\t"                                                         \
        : : "r" (dst_addr), "r" (size), "r" (src_val), "r" (asi)                \
        : "l1", "l2", "g7", "g1", "cc");                                        \
index 2ac19a44026007e00081e3230a79531abfaff002..9502ac403694098ec3f106482824a66dac397313 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.8 1997/06/02 06:33:35 davem Exp $
+/* $Id: winfixup.S,v 1.15 1997/07/04 01:41:07 davem Exp $
  *
  * winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
@@ -31,6 +31,7 @@
 fill_fixup:
        rdpr            %tstate, %g1
        andcc           %g1, TSTATE_PRIV, %g0
+       clr             %g4
        be,pt           %xcc, window_scheisse_from_user_common
         and            %g1, TSTATE_CWP, %g1
 
@@ -53,25 +54,26 @@ fill_fixup:
        rdpr            %wstate, %g2                    ! Grab user mode wstate.
        wrpr            %g1, %cwp                       ! Get into the right window.
        sll             %g2, 3, %g2                     ! NORMAL-->OTHER
-       wrpr            %g0, 0x0, %canrestore           ! Standard etrap stuff.
 
+       wrpr            %g0, 0x0, %canrestore           ! Standard etrap stuff.
+       wr              %g0, 0x0, %fprs                 ! zap FPU just in case...
        wrpr            %g2, 0x0, %wstate               ! This must be consistant.
        wrpr            %g0, 0x0, %otherwin             ! We know this.
-       sethi           %uhi(KERNBASE), %g2             ! Set this up
-       sllx            %g2, 32, %g2                    ! for the iflush
        mov             PRIMARY_CONTEXT, %g1            ! Change contexts...
        stxa            %g0, [%g1] ASI_DMMU             ! Back into the nucleus.
-       flush           %g2                             ! Flush instruction buffers
+       flush           %g6                             ! Flush instruction buffers
        rdpr            %pstate, %l1                    ! Prepare to change globals.
-       mov             %g4, %o5                        ! Setup args for
-       mov             %g5, %o4                        ! final call to do_sparc64_fault.
 
+       mov             %g6, %o7                        ! Get current.
+       mov             %g5, %l5                        ! Fault address
+       clr             %l4                             ! It was a load, not a store
        wrpr            %g0, 0x0, %tl                   ! Out of trap levels.
        wrpr            %l1, (PSTATE_IE | PSTATE_AG), %pstate
-       sethi           %uhi(KERNBASE), %g4             ! Restore med-any global reg.
-       rd              %pic, %g6                       ! Get current as well.
+       sethi           %uhi(PAGE_OFFSET), %g4          ! Prepare page_offset global reg
+       mov             %o7, %g6
        b,pt            %xcc, window_scheisse_merge     ! And merge.
-        sllx           %g4, 32, %g4                    ! Finish med-any reg setup.
+
+        sllx           %g4, 32, %g4                    ! and finish it...
 
        /* Be very careful about usage of the alternate globals here.
         * You cannot touch %g4/%g5 as that has the fault information
@@ -82,17 +84,16 @@ fill_fixup:
         * do not touch %g7 or %g2 so we handle the two cases fine.
         */
 spill_fixup:
-       rd              %pic, %g1
-       ldx             [%g1 + AOFF_task_tss + AOFF_thread_flags], %g6
-       andcc           %g6, SPARC_FLAG_32BIT, %g0
-       ldx             [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6
-       sll             %g6, 3, %g3
-       add             %g1, %g3, %g3
+       ld              [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+       andcc           %g1, SPARC_FLAG_32BIT, %g0
+       ldx             [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+       sll             %g1, 3, %g3
+       add             %g6, %g3, %g3
        stx             %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
-       sll             %g6, 7, %g3
+       sll             %g1, 7, %g3
 
        bne,pt          %xcc, 1f
-        add            %g1, %g3, %g3
+        add            %g6, %g3, %g3
        stx             %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
        stx             %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
        stx             %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
@@ -110,43 +111,45 @@ spill_fixup:
        stx             %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
 
        stx             %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
-       stx             %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
        b,pt            %xcc, 2f
-        add            %g6, 1, %g6
-1:     std             %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
-       std             %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
-       std             %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-       std             %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-
-       std             %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-       std             %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-       std             %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-       std             %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
-       add             %g6, 1, %g6
-2:     stx             %g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+        stx            %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+1:     stw             %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+       stw             %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x04]
+       stw             %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+       stw             %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x0c]
+       stw             %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+
+       stw             %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x14]
+       stw             %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+       stw             %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x1c]
+       stw             %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+       stw             %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x24]
+       stw             %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+       stw             %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x2c]
+       stw             %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+
+       stw             %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x34]
+       stw             %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+       stw             %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x3c]
+2:     add             %g1, 1, %g1
+       stx             %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
        rdpr            %tstate, %g1
-       nop
-
        andcc           %g1, TSTATE_PRIV, %g0
        saved
+
        and             %g1, TSTATE_CWP, %g1
        be,a,pn         %xcc, window_scheisse_from_user_common
         or             %g4, 0x4, %g4                   ! we know it was a write
        retry
 window_scheisse_from_user_common:
-       nop
        wrpr            %g1, %cwp
-
        ba,pt           %xcc, etrap
         rd             %pc, %g7
-       mov             %l5, %o4
-       mov             %l4, %o5
 window_scheisse_merge:
-       srlx            %o4, PAGE_SHIFT, %o3
-       clr             %o1
-       sllx            %o3, PAGE_SHIFT, %o3
-       and             %o5, 0x4, %o2
+       srlx            %l5, PAGE_SHIFT, %o1
 
+       and             %l4, 0x4, %o2
+       sllx            %o1, PAGE_SHIFT, %o1
        call            do_sparc64_fault
         add            %sp, STACK_BIAS + REGWIN_SZ, %o0
        ba,pt           %xcc, rtrap
@@ -154,6 +157,7 @@ window_scheisse_merge:
 winfix_trampoline:
        andn            %g3, 0x7f, %g3
        add             %g3, 0x7c, %g3
+
        wrpr            %g3, %tnpc
        done
 
@@ -174,32 +178,31 @@ fill_fixup_mna:
        wrpr            %g0, 0x0, %canrestore           ! Standard etrap stuff.
        wrpr            %g2, 0x0, %wstate               ! This must be consistant.
        wrpr            %g0, 0x0, %otherwin             ! We know this.
-       sethi           %uhi(KERNBASE), %g2             ! Set this up
-       sllx            %g2, 32, %g2                    ! for the iflush
        mov             PRIMARY_CONTEXT, %g1            ! Change contexts...
        stxa            %g0, [%g1] ASI_DMMU             ! Back into the nucleus.
-       flush           %g2                             ! Flush instruction buffers
+       flush           %g6                             ! Flush instruction buffers
        rdpr            %pstate, %l1                    ! Prepare to change globals.
        mov             %g4, %o5                        ! Setup args for
        mov             %g5, %o4                        ! final call to do_sparc64_fault.
+       mov             %g6, %o7                        ! Stash away current.
        wrpr            %g0, 0x0, %tl                   ! Out of trap levels.
        wrpr            %l1, (PSTATE_IE | PSTATE_AG), %pstate
-       sethi           %uhi(KERNBASE), %g4             ! Restore med-any global reg.
-       rd              %pic, %g6                       ! Get current as well.
+       sethi           %uhi(PAGE_OFFSET), %g4          ! Set page_offset global reg.
+       mov             %o7, %g6                        ! Get current back.
        b,pt            %xcc, window_mna_merge          ! And merge.
-        sllx           %g4, 32, %g4                    ! Finish med-any reg setup.
+        sllx           %g4, 32, %g4                    ! Finish it.
+
 spill_fixup_mna:
-       rd              %pic, %g1
-       ldx             [%g1 + AOFF_task_tss + AOFF_thread_flags], %g6
-       andcc           %g6, SPARC_FLAG_32BIT, %g0
-       ldx             [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6
-       sll             %g6, 3, %g3
-       add             %g1, %g3, %g3
+       ld              [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+       andcc           %g1, SPARC_FLAG_32BIT, %g0
+       ldx             [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+       sll             %g1, 3, %g3
+       add             %g6, %g3, %g3
        stx             %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
-       sll             %g6, 7, %g3
+       sll             %g1, 7, %g3
 
        bne,pt          %xcc, 1f
-        add            %g1, %g3, %g3
+        add            %g6, %g3, %g3
        stx             %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
        stx             %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
        stx             %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
@@ -219,7 +222,7 @@ spill_fixup_mna:
        stx             %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
        stx             %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
        b,pt            %xcc, 2f
-        add            %g6, 1, %g6
+        add            %g1, 1, %g1
 1:     std             %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
        std             %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
        std             %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
@@ -229,8 +232,8 @@ spill_fixup_mna:
        std             %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
        std             %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
        std             %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
-       add             %g6, 1, %g6
-2:     stx             %g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+       add             %g1, 1, %g1
+2:     stx             %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
        rdpr            %tstate, %g1
        nop
 
index 56c506507cb91454977eab3538e0a4cd17147cdb..2377d99e26ba2e15de4fd195b368e72ff88316f9 100644 (file)
@@ -1,55 +1,25 @@
-# $Id: Makefile,v 1.7 1997/04/07 18:57:05 jj Exp $
+# $Id: Makefile,v 1.12 1997/06/25 10:12:18 jj Exp $
 # Makefile for Sparc library files..
 #
 
 CFLAGS := $(CFLAGS) -ansi
 
-OBJS  = memset.o blockops.o locks.o memcpy.o strlen.o strncmp.o \
+OBJS  = blockops.o locks.o strlen.o strncmp.o \
        memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
-       copy_to_user.o copy_from_user.o
+       VIScopy.o VISbzero.o VISmemset.o
 
 lib.a: $(OBJS)
        $(AR) rcs lib.a $(OBJS)
        sync
 
-blockops.o: blockops.S
-       $(CC) -ansi -c -o blockops.o blockops.S
+VIScopy.o: VIScopy.S VIS.h
+VISbzero.o: VISbzero.S VIS.h
 
-memset.o: memset.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o memset.o memset.S
+.S.s:
+       $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
 
-copy_to_user.o: copy_to_user.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o copy_to_user.o copy_to_user.S
-
-copy_from_user.o: copy_from_user.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o copy_from_user.o copy_from_user.S
-
-memcpy.o: memcpy.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o memcpy.o memcpy.S
-
-strlen.o: strlen.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o strlen.o strlen.S
-
-strncmp.o: strncmp.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o strncmp.o strncmp.S
-
-memcmp.o: memcmp.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o memcmp.o memcmp.S
-
-locks.o: locks.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o locks.o locks.S
-
-checksum.o: checksum.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o checksum.o checksum.S
-
-memscan.o: memscan.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o memscan.o memscan.S
-
-strncpy_from_user.o: strncpy_from_user.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o strncpy_from_user.o strncpy_from_user.S
-
-strlen_user.o: strlen_user.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o strlen_user.o strlen_user.S
+.S.o:
+       $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
 dep:
 
diff --git a/arch/sparc64/lib/VIS.h b/arch/sparc64/lib/VIS.h
new file mode 100644 (file)
index 0000000..01232a8
--- /dev/null
@@ -0,0 +1,113 @@
+/* $Id: VIS.h,v 1.3 1997/06/27 14:53:18 jj Exp $
+ * VIS.h: High speed copy/clear operations utilizing the UltraSparc
+ *        Visual Instruction Set.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+       /* VIS code can be used for numerous copy/set operation variants.
+        * It can be made to work in the kernel, one single instance,
+        * for all of memcpy, copy_to_user, and copy_from_user by setting
+        * the ASI src/dest globals correctly.  Furthermore it can
+        * be used for kernel-->kernel page copies as well, a hook label
+        * is put in here just for this purpose.
+        *
+        * For userland, compiling this without __KERNEL__ defined makes
+        * it work just fine as a generic libc bcopy and memcpy.
+        * If for userland it is compiled with a 32bit gcc (but you need
+        * -Wa,-Av9a), the code will just rely on lower 32bits of
+        * IEU registers, if you compile it with 64bit gcc (ie. define
+        * __sparc_v9__), the code will use full 64bit.
+        */
+
+#ifndef __VIS_H
+#define __VIS_H
+        
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#else
+#define ASI_P                  0x80 /* Primary, implicit                       */
+#define ASI_S                  0x81 /* Secondary, implicit                     */
+#define ASI_BLK_COMMIT_P       0xe0 /* Primary, blk store commit               */
+#define ASI_BLK_COMMIT_S       0xe1 /* Secondary, blk store commit             */
+#define ASI_BLK_P              0xf0 /* Primary, blk ld/st                      */
+#define ASI_BLK_S              0xf1 /* Secondary, blk ld/st                    */
+#define FPRS_FEF               0x04
+#endif
+
+       /* I'm telling you, they really did this chip right.
+        * Perhaps the SunSoft folks should visit some of the
+        * people in Sun Microelectronics and start some brain
+        * cell exchange program...
+        */
+#define ASI_BLK_XOR            (ASI_P ^ ASI_BLK_P)
+
+#define        asi_src                 %o3
+#define asi_dest               %o4
+
+#ifdef __KERNEL__
+#define ASI_SETSRC_BLK         wr      asi_src, 0, %asi;
+#define ASI_SETSRC_NOBLK       wr      asi_src, ASI_BLK_XOR, %asi;
+#define ASI_SETDST_BLK         wr      asi_dest, 0, %asi;
+#define ASI_SETDST_NOBLK       wr      asi_dest, ASI_BLK_XOR, %asi;
+#define ASIBLK                 %asi
+#define ASINORMAL              %asi
+#define LDUB                   lduba
+#define LDUH                   lduha
+#define LDUW                   lduwa
+#define LDX                    ldxa
+#define LDD                    ldda
+#define LDDF                   ldda
+#define LDBLK                  ldda
+#define STB                    stba
+#define STH                    stha
+#define STW                    stwa
+#define STD                    stda
+#define STX                    stxa
+#define STDF                   stda
+#define STBLK                  stda
+#else
+#define ASI_SETSRC_BLK
+#define ASI_SETSRC_NOBLK
+#define ASI_SETDST_BLK
+#define ASI_SETDST_NOBLK
+#define ASI_SETDST_SPECIAL
+#define ASIBLK                 %asi
+#define ASINORMAL
+#define LDUB                   ldub
+#define LDUH                   lduh
+#define LDUW                   lduw
+#define LDD                    ldd
+#define LDX                    ldx
+#define LDDF                   ldd
+#define LDBLK                  ldda
+#define STB                    stb
+#define STH                    sth
+#define STW                    stw
+#define STD                    std
+#define STX                    stx
+#define STDF                   std
+#define STBLK                  stda
+#endif
+
+#ifdef __KERNEL__
+
+#define REGS_64BIT
+
+#else
+
+#ifndef REGS_64BIT
+#ifdef __sparc_v9__
+#define REGS_64BIT
+#endif
+#endif
+
+#endif
+
+#ifndef REGS_64BIT
+#define        xcc     icc
+#endif
+
+#endif
diff --git a/arch/sparc64/lib/VISbzero.S b/arch/sparc64/lib/VISbzero.S
new file mode 100644 (file)
index 0000000..1afaf35
--- /dev/null
@@ -0,0 +1,246 @@
+/* $Id: VISbzero.S,v 1.4 1997/06/28 17:21:21 jj Exp $
+ * VISbzero.S: High speed clear operations utilizing the UltraSparc
+ *        Visual Instruction Set.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include "VIS.h"
+
+#ifdef __KERNEL__
+#define EXN(x,y,a,b,z)                                 \
+98:    x,y;                                    \
+       .section .fixup;                        \
+       .align  4;                              \
+99:    ba      VISbzerofixup_ret##z;           \
+        a, b, %o0;                             \
+       .section __ex_table;                    \
+       .align  8;                              \
+       .xword  98b, 99b;                       \
+       .text;                                  \
+       .align  4;
+#define EXC(x,y,a,b,c...)                      \
+98:    x,y;                                    \
+       .section .fixup;                        \
+       .align  4;                              \
+99:    c;                                      \
+       ba      VISbzerofixup_ret0;             \
+        a, b, %o0;                             \
+       .section __ex_table;                    \
+       .align  8;                              \
+       .xword  98b, 99b;                       \
+       .text;                                  \
+       .align  4;
+#define EXO1(x,y)                              \
+98:    x,y;                                    \
+       .section __ex_table;                    \
+       .align  8;                              \
+       .xword  98b, VISbzerofixup_reto1;       \
+       .text;                                  \
+       .align  4;
+#define EX(x,y,a,b) EXN(x,y,a,b,0)
+#define EX1(x,y,a,b) EXN(x,y,a,b,1)
+#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;         \
+       .text;                                  \
+       .align  4
+#else
+#define EX(x,y,a,b)            x,y
+#define EX1(x,y,a,b)           x,y
+#define EX2(x,y,a,b)           x,y
+#define EXC(x,y,a,b,c...)      x,y
+#define EXO1(x,y)              x,y
+#define EXT(a,b,c)
+#endif
+
+#define ZERO_BLOCKS(base, offset, source)                      \
+       STX     source, [base - offset - 0x38] ASINORMAL;       \
+       STX     source, [base - offset - 0x30] ASINORMAL;       \
+       STX     source, [base - offset - 0x28] ASINORMAL;       \
+       STX     source, [base - offset - 0x20] ASINORMAL;       \
+       STX     source, [base - offset - 0x18] ASINORMAL;       \
+       STX     source, [base - offset - 0x10] ASINORMAL;       \
+       STX     source, [base - offset - 0x08] ASINORMAL;       \
+       STX     source, [base - offset - 0x00] ASINORMAL;
+
+#ifdef __KERNEL__
+#define RETL   clr %o0
+#else
+#define RETL   mov %g3, %o0
+#endif
+
+       /* Well, bzero is a lot easier to get right than bcopy... */
+#ifdef __KERNEL__
+       .section        __ex_table,#alloc
+       .section        .fixup,#alloc,#execinstr
+#endif
+       .text
+       .align          32
+#ifdef __KERNEL__
+       .globl          __bzero, __bzero_noasi
+__bzero:
+       wr              %g0, ASI_P, %asi                ! LSU   Group
+__bzero_noasi:
+#else
+       .globl          bzero
+bzero_private:
+bzero:
+#ifndef REGS_64BIT
+       srl             %o1, 0, %o1
+#endif
+       mov             %o0, %g3
+#endif
+       cmp             %o1, 7
+       bleu,pn         %xcc, 17f
+        andcc          %o0, 3, %o2
+       be,a,pt         %xcc, 4f
+        andcc          %o0, 4, %g0
+       cmp             %o2, 3
+       be,pn           %xcc, 2f
+        EXO1(STB       %g0, [%o0 + 0x00] ASINORMAL)
+       cmp             %o2, 2
+       be,pt           %xcc, 2f
+        EX(STB         %g0, [%o0 + 0x01] ASINORMAL, sub %o1, 1)
+       EX(STB          %g0, [%o0 + 0x02] ASINORMAL, sub %o1, 2)
+2:     sub             %o2, 4, %o2
+       sub             %o0, %o2, %o0
+       add             %o1, %o2, %o1
+       andcc           %o0, 4, %g0
+4:     be,pt           %xcc, 2f
+        cmp            %o1, 128
+       EXO1(STW        %g0, [%o0] ASINORMAL)
+       sub             %o1, 4, %o1
+       add             %o0, 4, %o0
+2:     blu,pn          %xcc, 9f
+        andcc          %o0, 0x38, %o2
+       be,pn           %icc, 6f
+        mov            64, %o5
+       andcc           %o0, 8, %g0
+       be,pn           %icc, 1f
+        sub            %o5, %o2, %o5
+       EX(STX          %g0, [%o0] ASINORMAL, sub %o1, 0)
+       add             %o0, 8, %o0
+1:     andcc           %o5, 16, %g0
+       be,pn           %icc, 1f
+        sub            %o1, %o5, %o1
+       EX1(STX         %g0, [%o0] ASINORMAL, add %g0, 0)
+       EX1(STX         %g0, [%o0 + 8] ASINORMAL, sub %g0, 8)
+       add             %o0, 16, %o0
+1:     andcc           %o5, 32, %g0
+       be,pn           %icc, 7f
+        andncc         %o1, 0x3f, %o3
+       EX(STX          %g0, [%o0] ASINORMAL, add %o1, 32)
+       EX(STX          %g0, [%o0 + 8] ASINORMAL, add %o1, 24)
+       EX(STX          %g0, [%o0 + 16] ASINORMAL, add %o1, 16)
+       EX(STX          %g0, [%o0 + 24] ASINORMAL, add %o1, 8)
+       add             %o0, 32, %o0
+6:     andncc          %o1, 0x3f, %o3
+7:     be,pn           %xcc, 9f
+#ifdef __KERNEL__
+        rd             %asi, %g7
+       wr              %g0, FPRS_FEF, %fprs
+       wr              %g7, ASI_BLK_XOR, %asi
+#else
+        wr             %g0, ASI_BLK_P, %asi
+#endif
+       membar          #StoreStore | #LoadStore
+       fzero           %f0
+       andcc           %o3, 0xc0, %o2
+       and             %o1, 0x3f, %o1
+       fzero           %f2
+       andn            %o3, 0xff, %o3
+       faddd           %f0, %f2, %f4
+       fmuld           %f0, %f2, %f6
+       cmp             %o2, 64
+       faddd           %f0, %f2, %f8
+       fmuld           %f0, %f2, %f10
+       faddd           %f0, %f2, %f12
+       brz,pn          %o2, 10f
+        fmuld          %f0, %f2, %f14
+       be,pn           %icc, 2f
+        EXC(STBLK      %f0, [%o0 + 0x00] ASIBLK, add %o3, %o2, add %o2, %o1, %o2)
+       cmp             %o2, 128
+       be,pn           %icc, 2f
+        EXC(STBLK      %f0, [%o0 + 0x40] ASIBLK, add %o3, %o2, add %o2, %o1, %o2; sub %o2, 64, %o2)
+       EXC(STBLK       %f0, [%o0 + 0x80] ASIBLK, add %o3, %o2, add %o2, %o1, %o2; sub %o2, 128, %o2)
+2:     brz,pn          %o3, 12f
+        add            %o0, %o2, %o0
+10:    EX(STBLK        %f0, [%o0 + 0x00] ASIBLK, add %o3, %o1)
+       EXC(STBLK       %f0, [%o0 + 0x40] ASIBLK, add %o3, %o1, sub %o1, 64, %o1)
+       EXC(STBLK       %f0, [%o0 + 0x80] ASIBLK, add %o3, %o1, sub %o1, 128, %o1)
+       EXC(STBLK       %f0, [%o0 + 0xc0] ASIBLK, add %o3, %o1, sub %o1, 192, %o1)
+11:    subcc           %o3, 256, %o3
+       bne,pt          %xcc, 10b
+        add            %o0, 256, %o0
+12:
+#ifdef __KERNEL__
+       wr              %g0, 0, %fprs
+       wr              %g7, 0x0, %asi
+#endif
+       membar          #Sync
+9:     andcc           %o1, 0xf8, %o2
+       be,pn           %xcc, 13f
+        andcc          %o1, 7, %o1
+14:    rd              %pc, %o4
+       srl             %o2, 1, %o3
+       sub             %o4, %o3, %o4
+       jmpl            %o4 + (13f - 14b), %g0
+        add            %o0, %o2, %o0
+12:    ZERO_BLOCKS(%o0, 0xc8, %g0)
+       ZERO_BLOCKS(%o0, 0x88, %g0)
+       ZERO_BLOCKS(%o0, 0x48, %g0)
+       ZERO_BLOCKS(%o0, 0x08, %g0)
+       EXT(12b,13f,VISbzerofixup_zb)
+13:    be,pn           %xcc, 8f
+        andcc          %o1, 4, %g0
+       be,pn           %xcc, 1f
+        andcc          %o1, 2, %g0
+       EX(STW          %g0, [%o0] ASINORMAL, and %o1, 7)
+       add             %o0, 4, %o0
+1:     be,pn           %xcc, 1f
+        andcc          %o1, 1, %g0
+       EX(STH          %g0, [%o0] ASINORMAL, and %o1, 3)
+       add             %o0, 2, %o0
+1:     bne,a,pn        %xcc, 8f
+        EX(STB         %g0, [%o0] ASINORMAL, add %g0, 1)
+8:     retl
+        RETL
+17:    be,pn           %xcc, 13b
+        orcc           %o1, 0, %g0
+       be,pn           %xcc, 0f
+8:      add            %o0, 1, %o0
+       subcc           %o1, 1, %o1
+       bne,pt          %xcc, 8b
+        EX(STB         %g0, [%o0 - 1] ASINORMAL, add %o1, 1)
+0:     retl
+        RETL
+
+#ifdef __KERNEL__
+       .section        .fixup
+       .align          4
+VISbzerofixup_reto1:
+       mov             %o1, %o0
+VISbzerofixup_ret0:
+       retl
+        wr             %g0, 0, %fprs
+VISbzerofixup_ret1:
+       and             %o5, 0x30, %o5
+       add             %o5, %o1, %o5
+       ba,pt           %xcc, VISbzerofixup_ret0
+        add            %o0, %o5, %o0
+VISbzerofixup_ret2:
+       and             %o5, 0x20, %o5
+       add             %o5, %o1, %o5
+       ba,pt           %xcc, VISbzerofixup_ret0
+        add            %o0, %o5, %o0
+VISbzerofixup_zb:
+       andcc           %o1, 7, %o1
+       sll             %g2, 3, %g2
+       add             %o1, 256, %o1
+       ba,pt           %xcc, VISbzerofixup_ret0
+        sub            %o1, %g2, %o0
+#endif
diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S
new file mode 100644 (file)
index 0000000..ced9422
--- /dev/null
@@ -0,0 +1,1052 @@
+/* $Id: VIScopy.S,v 1.8 1997/06/28 17:21:22 jj Exp $
+ * VIScopy.S: High speed copy operations utilizing the UltraSparc
+ *            Visual Instruction Set.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include "VIS.h"
+
+       /* VIS code can be used for numerous copy/set operation variants.
+        * It can be made to work in the kernel, one single instance,
+        * for all of memcpy, copy_to_user, and copy_from_user by setting
+        * the ASI src/dest globals correctly.  Furthermore it can
+        * be used for kernel-->kernel page copies as well, a hook label
+        * is put in here just for this purpose.
+        *
+        * For userland, compiling this without __KERNEL__ defined makes
+        * it work just fine as a generic libc bcopy and memcpy.
+        * If for userland it is compiled with a 32bit gcc (but you need
+        * -Wa,-Av9a for as), the code will just rely on lower 32bits of
+        * IEU registers, if you compile it with 64bit gcc (ie. define
+        * __sparc_v9__), the code will use full 64bit.
+        */
+        
+#ifdef __KERNEL__
+#define FPU_CLEAN_RETL                         \
+       wr              %g0, 0, %fprs;          \
+       retl;                                   \
+        clr            %o0;
+#define FPU_RETL                               \
+       wr              %g0, 0, %fprs;          \
+       retl;                                   \
+        clr            %o0;
+#define NORMAL_RETL                            \
+       retl;                                   \
+        clr            %o0;
+#define EX(x,y,a,b)                            \
+98:    x,y;                                    \
+       .section .fixup;                        \
+       .align  4;                              \
+99:    ba      VIScopyfixup_ret;               \
+        a, b, %o0;                             \
+       .section __ex_table;                    \
+       .align  8;                              \
+       .xword  98b, 99b;                       \
+       .text;                                  \
+       .align  4;
+#define EX2(x,y,c,d,e,a,b)                     \
+98:    x,y;                                    \
+       .section .fixup;                        \
+       .align  4;                              \
+99:    c, d, e;                                \
+       ba      VIScopyfixup_ret;               \
+        a, b, %o0;                             \
+       .section __ex_table;                    \
+       .align  8;                              \
+       .xword  98b, 99b;                       \
+       .text;                                  \
+       .align  4;
+#define EXO2(x,y)                              \
+98:    x,y;                                    \
+       .section __ex_table;                    \
+       .align  8;                              \
+       .xword  98b, VIScopyfixup_reto2;        \
+       .text;                                  \
+       .align  4;
+#define EXVISN(x,y,n)                          \
+98:    x,y;                                    \
+       .section __ex_table;                    \
+       .align  8;                              \
+       .xword  98b, VIScopyfixup_vis##n;       \
+       .text;                                  \
+       .align  4;
+#define EXT(start,end,handler)                         \
+       .section __ex_table;                    \
+       .align  8;                              \
+       .xword  start, 0, end, handler;         \
+       .text;                                  \
+       .align  4;
+#else
+#define FPU_CLEAN_RETL \
+       retl;           \
+        mov    %g6, %o0;
+#define FPU_RETL       \
+       retl;           \
+        mov    %g6, %o0;
+#define NORMAL_RETL    \
+       retl;           \
+        mov    %g6, %o0;
+#define EX(x,y,a,b)            x,y
+#define EX2(x,y,c,d,e,a,b)     x,y
+#define EXO2(x,y)              x,y
+#define EXVISN(x,y,n)          x,y
+#define EXT(a,b,c)
+#endif
+#define EXVIS(x,y) EXVISN(x,y,0)
+#define EXVIS1(x,y) EXVISN(x,y,1)
+#define EXVIS2(x,y) EXVISN(x,y,2)
+#define EXVIS3(x,y) EXVISN(x,y,3)
+#define EXVIS4(x,y) EXVISN(x,y,4)
+#define EXVIS5(x,y) EXVISN(x,y,5)
+
+#define FREG_FROB(f1, f2, f3, f4, f5, f6, f7, f8, f9)          \
+       faligndata              %f1, %f2, %f48;                 \
+       faligndata              %f2, %f3, %f50;                 \
+       faligndata              %f3, %f4, %f52;                 \
+       faligndata              %f4, %f5, %f54;                 \
+       faligndata              %f5, %f6, %f56;                 \
+       faligndata              %f6, %f7, %f58;                 \
+       faligndata              %f7, %f8, %f60;                 \
+       faligndata              %f8, %f9, %f62;
+
+#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt)   \
+       EXVIS(LDBLK             [%src] ASIBLK, %fdest);         \
+       add                     %src, 0x40, %src;               \
+       ASI_SETDST_BLK                                          \
+       add                     %dest, 0x40, %dest;             \
+       subcc                   %len, 0x40, %len;               \
+       be,pn                   %xcc, jmptgt;                   \
+        EXVIS2(STBLK           %fsrc, [%dest - 0x40] ASIBLK);  \
+       ASI_SETSRC_BLK
+
+#define LOOP_CHUNK1(src, dest, len, branch_dest)               \
+       MAIN_LOOP_CHUNK(src, dest, f0,  f48, len, branch_dest)
+#define LOOP_CHUNK2(src, dest, len, branch_dest)               \
+       MAIN_LOOP_CHUNK(src, dest, f16, f48, len, branch_dest)
+#define LOOP_CHUNK3(src, dest, len, branch_dest)               \
+       MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest)
+
+#define STORE_SYNC(dest, fsrc)                                 \
+       EXVIS(STBLK             %fsrc, [%dest] ASIBLK);         \
+       add                     %dest, 0x40, %dest;
+
+#define STORE_JUMP(dest, fsrc, target)                         \
+       EXVIS3(STBLK            %fsrc, [%dest] ASIBLK);         \
+       add                     %dest, 0x40, %dest;             \
+       ba,pt                   %xcc, target;
+
+#ifndef __KERNEL__
+#define VISLOOP_PAD nop; nop; nop; nop; \
+                   nop; nop; nop; nop; \
+                   nop; nop; nop; nop; \
+                   nop; nop; nop;
+#else
+#define VISLOOP_PAD nop; nop; nop; nop; \
+                   nop; nop; nop; nop; \
+                   nop;
+#endif
+
+#define FINISH_VISCHUNK(dest, f0, f1, left)                    \
+       ASI_SETDST_NOBLK                                        \
+       subcc                   %left, 8, %left;                \
+       bl,pn                   %xcc, vis_out;                  \
+        faligndata             %f0, %f1, %f48;                 \
+       EXVIS4(STDF             %f48, [%dest] ASINORMAL);       \
+       add                     %dest, 8, %dest;
+
+#define UNEVEN_VISCHUNK(dest, f0, f1, left)                    \
+       subcc                   %left, 8, %left;                \
+       bl,pn                   %xcc, vis_out;                  \
+        fsrc1                  %f0, %f1;                       \
+       ba,a,pt                 %xcc, vis_slk;
+
+       /* Macros for non-VIS memcpy code. */
+#ifdef REGS_64BIT
+
+#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3)                        \
+       ASI_SETSRC_NOBLK                                                \
+       LDX                     [%src + offset + 0x00] ASINORMAL, %t0;  \
+       LDX                     [%src + offset + 0x08] ASINORMAL, %t1;  \
+       LDX                     [%src + offset + 0x10] ASINORMAL, %t2;  \
+       LDX                     [%src + offset + 0x18] ASINORMAL, %t3;  \
+       ASI_SETDST_NOBLK                                                \
+       STW                     %t0, [%dst + offset + 0x04] ASINORMAL;  \
+       srlx                    %t0, 32, %t0;                           \
+       STW                     %t0, [%dst + offset + 0x00] ASINORMAL;  \
+       STW                     %t1, [%dst + offset + 0x0c] ASINORMAL;  \
+       srlx                    %t1, 32, %t1;                           \
+       STW                     %t1, [%dst + offset + 0x08] ASINORMAL;  \
+       STW                     %t2, [%dst + offset + 0x14] ASINORMAL;  \
+       srlx                    %t2, 32, %t2;                           \
+       STW                     %t2, [%dst + offset + 0x10] ASINORMAL;  \
+       STW                     %t3, [%dst + offset + 0x1c] ASINORMAL;  \
+       srlx                    %t3, 32, %t3;                           \
+       STW                     %t3, [%dst + offset + 0x18] ASINORMAL;
+
+#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3)           \
+       ASI_SETSRC_NOBLK                                                \
+       LDX                     [%src + offset + 0x00] ASINORMAL, %t0;  \
+       LDX                     [%src + offset + 0x08] ASINORMAL, %t1;  \
+       LDX                     [%src + offset + 0x10] ASINORMAL, %t2;  \
+       LDX                     [%src + offset + 0x18] ASINORMAL, %t3;  \
+       ASI_SETDST_NOBLK                                                \
+       STX                     %t0, [%dst + offset + 0x00] ASINORMAL;  \
+       STX                     %t1, [%dst + offset + 0x08] ASINORMAL;  \
+       STX                     %t2, [%dst + offset + 0x10] ASINORMAL;  \
+       STX                     %t3, [%dst + offset + 0x18] ASINORMAL;  \
+       ASI_SETSRC_NOBLK                                                \
+       LDX                     [%src + offset + 0x20] ASINORMAL, %t0;  \
+       LDX                     [%src + offset + 0x28] ASINORMAL, %t1;  \
+       LDX                     [%src + offset + 0x30] ASINORMAL, %t2;  \
+       LDX                     [%src + offset + 0x38] ASINORMAL, %t3;  \
+       ASI_SETDST_NOBLK                                                \
+       STX                     %t0, [%dst + offset + 0x20] ASINORMAL;  \
+       STX                     %t1, [%dst + offset + 0x28] ASINORMAL;  \
+       STX                     %t2, [%dst + offset + 0x30] ASINORMAL;  \
+       STX                     %t3, [%dst + offset + 0x38] ASINORMAL;
+
+#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3)               \
+       ASI_SETSRC_NOBLK                                                \
+       LDX                     [%src - offset - 0x10] ASINORMAL, %t0;  \
+       LDX                     [%src - offset - 0x08] ASINORMAL, %t1;  \
+       ASI_SETDST_NOBLK                                                \
+       STW                     %t0, [%dst - offset - 0x0c] ASINORMAL;  \
+       srlx                    %t0, 32, %t2;                           \
+       STW                     %t2, [%dst - offset - 0x10] ASINORMAL;  \
+       STW                     %t1, [%dst - offset - 0x04] ASINORMAL;  \
+       srlx                    %t1, 32, %t3;                           \
+       STW                     %t3, [%dst - offset - 0x08] ASINORMAL;
+
+#define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1)                  \
+       ASI_SETSRC_NOBLK                                                \
+       LDX                     [%src - offset - 0x10] ASINORMAL, %t0;  \
+       LDX                     [%src - offset - 0x08] ASINORMAL, %t1;  \
+       ASI_SETDST_NOBLK                                                \
+       STX                     %t0, [%dst - offset - 0x10] ASINORMAL;  \
+       STX                     %t1, [%dst - offset - 0x08] ASINORMAL;
+
+#else /* !REGS_64BIT */
+
+#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3)                        \
+       lduw                    [%src + offset + 0x00], %t0;            \
+       lduw                    [%src + offset + 0x04], %t1;            \
+       lduw                    [%src + offset + 0x08], %t2;            \
+       lduw                    [%src + offset + 0x0c], %t3;            \
+       stw                     %t0, [%dst + offset + 0x00];            \
+       stw                     %t1, [%dst + offset + 0x04];            \
+       stw                     %t2, [%dst + offset + 0x08];            \
+       stw                     %t3, [%dst + offset + 0x0c];            \
+       lduw                    [%src + offset + 0x10], %t0;            \
+       lduw                    [%src + offset + 0x14], %t1;            \
+       lduw                    [%src + offset + 0x18], %t2;            \
+       lduw                    [%src + offset + 0x1c], %t3;            \
+       stw                     %t0, [%dst + offset + 0x10];            \
+       stw                     %t1, [%dst + offset + 0x14];            \
+       stw                     %t2, [%dst + offset + 0x18];            \
+       stw                     %t3, [%dst + offset + 0x1c];
+
+#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3)               \
+       lduw                    [%src - offset - 0x10], %t0;            \
+       lduw                    [%src - offset - 0x0c], %t1;            \
+       lduw                    [%src - offset - 0x08], %t2;            \
+       lduw                    [%src - offset - 0x04], %t3;            \
+       stw                     %t0, [%dst - offset - 0x10];            \
+       stw                     %t1, [%dst - offset - 0x0c];            \
+       stw                     %t2, [%dst - offset - 0x08];            \
+       stw                     %t3, [%dst - offset - 0x04];
+
+#endif /* !REGS_64BIT */
+
+#ifdef __KERNEL__
+               .section        __ex_table,#alloc
+               .section        .fixup,#alloc,#execinstr
+#endif
+
+               .text
+               .align                  32
+               .globl                  memcpy
+               .type                   memcpy,@function
+
+               .globl                  bcopy
+               .type                   bcopy,@function
+
+#ifdef __KERNEL__
+               .globl                  __memcpy
+               .type                   __memcpy,@function
+
+               .globl                  __memcpy_384plus
+               .type                   __memcpy_384plus,@function
+
+               .globl                  __memcpy_16plus
+               .type                   __memcpy_16plus,@function
+
+               .globl                  __memcpy_short
+               .type                   __memcpy_short,@function
+
+               .globl                  __memcpy_entry
+               .type                   __memcpy_entry,@function
+
+               .globl                  copy_page
+               .type                   copy_page,@function
+
+memcpy_private:
+__memcpy:
+memcpy:                mov             ASI_BLK_P, asi_src              ! IEU0  Group
+               brnz,pt         %o2, __memcpy_entry             ! CTI
+                mov            ASI_BLK_P, asi_dest             ! IEU1
+               retl
+                clr            %o0
+
+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
+
+               .align                  32
+               .globl                  __copy_from_user
+               .type                   __copy_from_user,@function
+__copy_from_user:mov           ASI_BLK_S, asi_src              ! IEU0  Group
+               brnz,pt         %o2, __memcpy_entry             ! CTI
+                mov            ASI_BLK_P, asi_dest             ! IEU1
+
+               .globl                  __copy_to_user
+               .type                   __copy_to_user,@function
+__copy_to_user:        mov             ASI_BLK_P, asi_src              ! IEU0  Group
+               brnz,pt         %o2, __memcpy_entry             ! CTI
+                mov            ASI_BLK_S, asi_dest             ! IEU1
+               retl                                            ! CTI   Group
+                clr            %o0                             ! IEU0  Group
+#endif
+
+bcopy:         or              %o0, 0, %g3                     ! IEU0  Group
+               addcc           %o1, 0, %o0                     ! IEU1
+               brgez,pt        %o2, memcpy_private             ! CTI
+                or             %g3, 0, %o1                     ! IEU0  Group
+               retl                                            ! CTI   Group brk forced
+                clr            %o0                             ! IEU0
+
+
+       .align                  32
+#ifdef __KERNEL__
+__memcpy_384plus:
+       andcc                   %o0, 7, %g2                     ! IEU1  Group
+#endif
+VIS_enter:
+       be,pt                   %xcc, dest_is_8byte_aligned     ! CTI
+        andcc                  %o0, 0x38, %g5                  ! IEU1  Group
+do_dest_8byte_align:
+       mov                     8, %g1                          ! IEU0
+       sub                     %g1, %g2, %g2                   ! IEU0  Group
+       andcc                   %o0, 1, %g0                     ! IEU1
+       be,pt                   %icc, 2f                        ! CTI
+        sub                    %o2, %g2, %o2                   ! IEU0  Group
+1:     ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDUB                 [%o1] ASINORMAL, %o5, 
+                               add %o2, %g2)                   ! Load  Group
+       add                     %o1, 1, %o1                     ! IEU0
+       add                     %o0, 1, %o0                     ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       subcc                   %g2, 1, %g2                     ! IEU1  Group
+       be,pn                   %xcc, 3f                        ! CTI
+        EX2(STB                %o5, [%o0 - 1] ASINORMAL,
+                               add %g2, 1, %g2,
+                               add %o2, %g2)                   ! Store
+2:     ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDUB                 [%o1] ASINORMAL, %o5, 
+                               add %o2, %g2)                   ! Load  Group
+       add                     %o0, 2, %o0                     ! IEU0
+       EX(LDUB                 [%o1 + 1] ASINORMAL, %g3,
+                               add %o2, %g2)                   ! Load  Group
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       subcc                   %g2, 2, %g2                     ! IEU1  Group
+       EX2(STB                 %o5, [%o0 - 2] ASINORMAL,
+                               add %g2, 2, %g2,
+                               add %o2, %g2)                   ! Store
+       add                     %o1, 2, %o1                     ! IEU0
+       bne,pt                  %xcc, 2b                        ! CTI   Group
+        EX2(STB                %g3, [%o0 - 1] ASINORMAL,
+                               add %g2, 1, %g2,
+                               add %o2, %g2)                   ! Store
+3:     andcc                   %o0, 0x38, %g5                  ! IEU1  Group
+dest_is_8byte_aligned:
+       be,pt                   %icc, dest_is_64byte_aligned    ! CTI
+#ifdef __KERNEL__
+        wr                     %g0, FPRS_FEF, %fprs            ! FPU   Group
+do_dest_64byte_align:
+       mov                     64, %g1                         ! IEU0  Group
+#else
+        mov                    64, %g1                         ! IEU0  Group
+do_dest_64byte_align:
+#endif
+       fmovd                   %f0, %f2                        ! FPU
+       sub                     %g1, %g5, %g5                   ! IEU0  Group
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       alignaddr               %o1, %g0, %g1                   ! GRU   Group
+       EXO2(LDDF               [%g1] ASINORMAL, %f4)           ! Load  Group
+       sub                     %o2, %g5, %o2                   ! IEU0
+1:     EX(LDDF                 [%g1 + 0x8] ASINORMAL, %f6,
+                               add %o2, %g5)                   ! Load  Group
+       add                     %g1, 0x8, %g1                   ! IEU0  Group
+       subcc                   %g5, 8, %g5                     ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       faligndata              %f4, %f6, %f0                   ! GRU   Group
+       EX2(STDF                %f0, [%o0] ASINORMAL,
+                               add %g5, 8, %g5,
+                               add %o2, %g5)                   ! Store
+       add                     %o1, 8, %o1                     ! IEU0  Group
+       be,pn                   %xcc, dest_is_64byte_aligned    ! CTI
+        add                    %o0, 8, %o0                     ! IEU1
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDDF                 [%g1 + 0x8] ASINORMAL, %f4,
+                               add %o2, %g5)                   ! Load  Group
+       add                     %g1, 8, %g1                     ! IEU0
+       subcc                   %g5, 8, %g5                     ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       faligndata              %f6, %f4, %f0                   ! GRU   Group
+       EX2(STDF                %f0, [%o0] ASINORMAL,
+                               add %g5, 8, %g5,
+                               add %o2, %g5)                   ! Store
+       add                     %o1, 8, %o1                     ! IEU0
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       bne,pt                  %xcc, 1b                        ! CTI   Group
+        add                    %o0, 8, %o0                     ! IEU0
+dest_is_64byte_aligned:
+       membar            #LoadStore | #StoreStore | #StoreLoad ! LSU   Group
+#ifndef __KERNEL__
+       wr                      %g0, ASI_BLK_P, %asi            ! LSU   Group
+#endif
+       subcc                   %o2, 0x40, %g7                  ! IEU1  Group
+       mov                     %o1, %g1                        ! IEU0
+       andncc                  %g7, (0x40 - 1), %g7            ! IEU1  Group
+       srl                     %g1, 3, %g2                     ! IEU0
+       sub                     %o2, %g7, %g3                   ! IEU0  Group
+       andn                    %o1, (0x40 - 1), %o1            ! IEU1
+       and                     %g2, 7, %g2                     ! IEU0  Group
+       andncc                  %g3, 0x7, %g3                   ! IEU1
+       fmovd                   %f0, %f2                        ! FPU
+       sub                     %g3, 0x10, %g3                  ! IEU0  Group
+       sub                     %o2, %g7, %o2                   ! IEU1
+       alignaddr               %g1, %g0, %g0                   ! GRU   Group
+       add                     %g1, %g7, %g1                   ! IEU0  Group
+       subcc                   %o2, %g3, %o2                   ! IEU1
+       ASI_SETSRC_BLK                                          ! LSU   Group
+       EXVIS1(LDBLK            [%o1 + 0x00] ASIBLK, %f0)       ! LSU   Group
+       add                     %g1, %g3, %g1                   ! IEU0
+       EXVIS1(LDBLK            [%o1 + 0x40] ASIBLK, %f16)      ! LSU   Group
+       sub                     %g7, 0x80, %g7                  ! IEU0
+       EXVIS(LDBLK             [%o1 + 0x80] ASIBLK, %f32)      ! LSU   Group
+                                                               ! Clk1  Group 8-(
+                                                               ! Clk2  Group 8-(
+                                                               ! Clk3  Group 8-(
+                                                               ! Clk4  Group 8-(
+vispc: rd                      %pc, %g5                        ! PDU   Group 8-(
+       addcc                   %g5, %lo(vis00 - vispc), %g5    ! IEU1  Group
+       sll                     %g2, 9, %g2                     ! IEU0
+       jmpl                    %g5 + %g2, %g0                  ! CTI   Group brk forced
+        addcc                  %o1, 0xc0, %o1                  ! IEU1  Group
+       .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)
+      FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)  LOOP_CHUNK3(o1, o0, g7, vis03)
+      b,pt                     %xcc, vis00+4; faligndata %f0, %f2, %f48
+vis01:FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)  STORE_JUMP(o0, f48, finish_f0) membar #Sync
+vis02:FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)  STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, check_finish_f16) add %o2, %g3, %g7
+vis03:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_JUMP(o0, f48, finish_f32) membar #Sync
+      VISLOOP_PAD
+vis10:FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) LOOP_CHUNK1(o1, o0, g7, vis11)
+      FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) LOOP_CHUNK2(o1, o0, g7, vis12)
+      FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)  LOOP_CHUNK3(o1, o0, g7, vis13)
+      b,pt                     %xcc, vis10+4; faligndata %f2, %f4, %f48
+vis11:FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)  STORE_JUMP(o0, f48, finish_f2) membar #Sync
+vis12:FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)  STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) STORE_JUMP(o0, f48, finish_f18) membar #Sync
+vis13:FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34) STORE_JUMP(o0, f48, finish_f34) membar #Sync
+      VISLOOP_PAD
+vis20:FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) LOOP_CHUNK1(o1, o0, g7, vis21)
+      FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) LOOP_CHUNK2(o1, o0, g7, vis22)
+      FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)  LOOP_CHUNK3(o1, o0, g7, vis23)
+      b,pt                     %xcc, vis20+4; faligndata %f4, %f6, %f48
+vis21:FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)  STORE_JUMP(o0, f48, finish_f4) membar #Sync
+vis22:FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)  STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) STORE_JUMP(o0, f48, finish_f20) membar #Sync
+vis23:FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36) STORE_JUMP(o0, f48, finish_f36) membar #Sync
+      VISLOOP_PAD
+vis30:FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) LOOP_CHUNK1(o1, o0, g7, vis31)
+      FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) LOOP_CHUNK2(o1, o0, g7, vis32)
+      FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)  LOOP_CHUNK3(o1, o0, g7, vis33)
+      b,pt                     %xcc, vis30+4; faligndata %f6, %f8, %f48
+vis31:FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)  STORE_JUMP(o0, f48, finish_f6) membar #Sync
+vis32:FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)  STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) STORE_JUMP(o0, f48, finish_f22) membar #Sync
+vis33:FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38) STORE_JUMP(o0, f48, finish_f38) membar #Sync
+      VISLOOP_PAD
+vis40:FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) LOOP_CHUNK1(o1, o0, g7, vis41)
+      FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) LOOP_CHUNK2(o1, o0, g7, vis42)
+      FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)  LOOP_CHUNK3(o1, o0, g7, vis43)
+      b,pt                     %xcc, vis40+4; faligndata %f8, %f10, %f48
+vis41:FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)  STORE_JUMP(o0, f48, finish_f8) membar #Sync
+vis42:FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)  STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) STORE_JUMP(o0, f48, finish_f24) membar #Sync
+vis43:FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40) STORE_JUMP(o0, f48, finish_f40) membar #Sync
+      VISLOOP_PAD
+vis50:FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) LOOP_CHUNK1(o1, o0, g7, vis51)
+      FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) LOOP_CHUNK2(o1, o0, g7, vis52)
+      FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) LOOP_CHUNK3(o1, o0, g7, vis53)
+      b,pt                     %xcc, vis50+4; faligndata %f10, %f12, %f48
+vis51:FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) STORE_JUMP(o0, f48, finish_f10) membar #Sync
+vis52:FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) STORE_JUMP(o0, f48, finish_f26) membar #Sync
+vis53:FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42) STORE_JUMP(o0, f48, finish_f42) membar #Sync
+      VISLOOP_PAD
+vis60:FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) LOOP_CHUNK1(o1, o0, g7, vis61)
+      FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) LOOP_CHUNK2(o1, o0, g7, vis62)
+      FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) LOOP_CHUNK3(o1, o0, g7, vis63)
+      b,pt                     %xcc, vis60+4; faligndata %f12, %f14, %f48
+vis61:FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) STORE_JUMP(o0, f48, finish_f12) membar #Sync
+vis62:FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) STORE_JUMP(o0, f48, finish_f28) membar #Sync
+vis63:FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44) STORE_JUMP(o0, f48, finish_f44) membar #Sync
+      VISLOOP_PAD
+vis70:FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) LOOP_CHUNK1(o1, o0, g7, vis71)
+      FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) LOOP_CHUNK2(o1, o0, g7, vis72)
+      FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) LOOP_CHUNK3(o1, o0, g7, vis73)
+      b,pt                     %xcc, vis70+4; faligndata %f14, %f16, %f48
+vis71:FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) STORE_JUMP(o0, f48, finish_f14) membar #Sync
+vis72:FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) STORE_JUMP(o0, f48, finish_f30) membar #Sync
+vis73:FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30) STORE_SYNC(o0, f48) membar #Sync
+      FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46) STORE_JUMP(o0, f48, finish_f46) membar #Sync
+      VISLOOP_PAD
+finish_f0:     FINISH_VISCHUNK(o0, f0,  f2,  g3)
+finish_f2:     FINISH_VISCHUNK(o0, f2,  f4,  g3)
+finish_f4:     FINISH_VISCHUNK(o0, f4,  f6,  g3)
+finish_f6:     FINISH_VISCHUNK(o0, f6,  f8,  g3)
+finish_f8:     FINISH_VISCHUNK(o0, f8,  f10, g3)
+finish_f10:    FINISH_VISCHUNK(o0, f10, f12, g3)
+finish_f12:    FINISH_VISCHUNK(o0, f12, f14, g3)
+finish_f14:    UNEVEN_VISCHUNK(o0, f14, f0,  g3)
+/* This is a special hack to speed up 8K page copy */
+check_finish_f16:
+               andcc           %g1, 7, %g0
+               bne,pn          %icc, finish_f16
+                cmp            %g7, 0x40
+               bne,pn          %icc, finish_f16
+                FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
+               membar #Sync
+               EXVIS1(STBLK    %f48, [%o0] ASIBLK)
+               b,pt            %xcc, vis_ret
+finish_f16:     membar         #Sync
+               FINISH_VISCHUNK(o0, f16, f18, g3)
+finish_f18:    FINISH_VISCHUNK(o0, f18, f20, g3)
+finish_f20:    FINISH_VISCHUNK(o0, f20, f22, g3)
+finish_f22:    FINISH_VISCHUNK(o0, f22, f24, g3)
+finish_f24:    FINISH_VISCHUNK(o0, f24, f26, g3)
+finish_f26:    FINISH_VISCHUNK(o0, f26, f28, g3)
+finish_f28:    FINISH_VISCHUNK(o0, f28, f30, g3)
+finish_f30:    UNEVEN_VISCHUNK(o0, f30, f0,  g3)
+finish_f32:    FINISH_VISCHUNK(o0, f32, f34, g3)
+finish_f34:    FINISH_VISCHUNK(o0, f34, f36, g3)
+finish_f36:    FINISH_VISCHUNK(o0, f36, f38, g3)
+finish_f38:    FINISH_VISCHUNK(o0, f38, f40, g3)
+finish_f40:    FINISH_VISCHUNK(o0, f40, f42, g3)
+finish_f42:    FINISH_VISCHUNK(o0, f42, f44, g3)
+finish_f44:    FINISH_VISCHUNK(o0, f44, f46, g3)
+finish_f46:    UNEVEN_VISCHUNK(o0, f46, f0,  g3)
+vis_slk:ASI_SETSRC_NOBLK                                       ! LSU   Group
+       EXVIS4(LDDF     [%o1] ASINORMAL, %f2)                   ! Load  Group
+       add             %o1, 8, %o1                             ! IEU0
+       subcc           %g3, 8, %g3                             ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       faligndata      %f0, %f2, %f8                           ! GRU   Group
+       EXVIS5(STDF     %f8, [%o0] ASINORMAL)                   ! Store
+       bl,pn           %xcc, vis_out                           ! CTI
+        add            %o0, 8, %o0                             ! IEU0  Group
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EXVIS4(LDDF     [%o1] ASINORMAL, %f0)                   ! Load  Group
+       add             %o1, 8, %o1                             ! IEU0
+       subcc           %g3, 8, %g3                             ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       faligndata      %f2, %f0, %f8                           ! GRU   Group
+       EXVIS5(STDF     %f8, [%o0] ASINORMAL)                   ! Store
+       bge,pt          %xcc, vis_slk                           ! CTI
+        add            %o0, 8, %o0                             ! IEU0  Group
+vis_out:brz,pt         %o2, vis_ret                            ! CTI   Group
+        mov            %g1, %o1                                ! IEU0
+vis_slp:ASI_SETSRC_NOBLK                                       ! LSU   Group
+       EXO2(LDUB       [%o1] ASINORMAL, %g5)                   ! LOAD
+       add             %o1, 1, %o1                             ! IEU0
+       add             %o0, 1, %o0                             ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       subcc           %o2, 1, %o2                             ! IEU1
+       bne,pt          %xcc, vis_slp                           ! CTI
+        EX(STB         %g5, [%o0 - 1] ASINORMAL,
+                       add %o2, 1)                             ! Store Group
+vis_ret:membar         #StoreLoad | #StoreStore                ! LSU   Group
+       FPU_CLEAN_RETL
+
+
+__memcpy_short:
+       andcc           %o2, 1, %g0                             ! IEU1  Group
+       be,pt           %icc, 2f                                ! CTI
+1:      ASI_SETSRC_NOBLK                                       ! LSU   Group
+       EXO2(LDUB       [%o1] ASINORMAL, %g5)                   ! LOAD  Group
+       add             %o1, 1, %o1                             ! IEU0
+       add             %o0, 1, %o0                             ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       subcc           %o2, 1, %o2                             ! IEU1  Group
+       be,pn           %xcc, short_ret                         ! CTI
+        EX(STB         %g5, [%o0 - 1] ASINORMAL,
+                       add %o2, 1)                             ! Store
+2:     ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EXO2(LDUB       [%o1] ASINORMAL, %g5)                   ! LOAD  Group
+       add             %o0, 2, %o0                             ! IEU0
+       EXO2(LDUB       [%o1 + 1] ASINORMAL, %o5)               ! LOAD  Group
+       add             %o1, 2, %o1                             ! IEU0
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       subcc           %o2, 2, %o2                             ! IEU1  Group
+       EX(STB          %g5, [%o0 - 2] ASINORMAL,
+                       add %o2, 2)                             ! Store
+       bne,pt          %xcc, 2b                                ! CTI
+        EX(STB         %o5, [%o0 - 1] ASINORMAL,
+                       add %o2, 1)                             ! Store
+short_ret:
+       NORMAL_RETL
+
+#ifndef __KERNEL__
+memcpy_private:
+memcpy:
+#ifndef REGS_64BIT
+       srl             %o2, 0, %o2                             ! IEU1  Group
+#endif 
+       brz,pn          %o2, short_ret                          ! CTI   Group
+        mov            %o0, %g6                                ! IEU0
+#endif
+__memcpy_entry:
+       cmp             %o2, 15                                 ! IEU1  Group
+       bleu,pn         %xcc, __memcpy_short                    ! CTI
+        cmp            %o2, (64 * 6)                           ! IEU1  Group
+       bgeu,pn         %xcc, VIS_enter                         ! CTI
+#ifdef __KERNEL__
+__memcpy_16plus:
+#endif
+        andcc          %o0, 7, %g2                             ! IEU1  Group
+       sub             %o0, %o1, %g5                           ! IEU0
+       andcc           %g5, 3, %o5                             ! IEU1  Group
+       bne,pn          %xcc, memcpy_noVIS_misaligned           ! CTI
+        andcc          %o1, 3, %g0                             ! IEU1  Group
+#ifdef REGS_64BIT
+       be,a,pt         %xcc, 3f                                ! CTI
+        andcc          %o1, 4, %g0                             ! IEU1  Group
+       andcc           %o1, 1, %g0                             ! IEU1  Group
+#else /* !REGS_64BIT */
+       be,pt           %xcc, 5f                                ! CTI
+        andcc          %o1, 1, %g0                             ! IEU1  Group
+#endif /* !REGS_64BIT */
+       be,pn           %xcc, 4f                                ! CTI
+        andcc          %o1, 2, %g0                             ! IEU1  Group
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EXO2(LDUB       [%o1] ASINORMAL, %g2)                   ! Load  Group
+       add             %o1, 1, %o1                             ! IEU0
+       add             %o0, 1, %o0                             ! IEU1
+       sub             %o2, 1, %o2                             ! IEU0  Group
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       bne,pn          %xcc, 5f                                ! CTI   Group
+        EX(STB         %g2, [%o0 - 1] ASINORMAL,
+                       add %o2, 1)                             ! Store
+4:     ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EXO2(LDUH       [%o1] ASINORMAL, %g2)                   ! Load  Group
+       add             %o1, 2, %o1                             ! IEU0
+       add             %o0, 2, %o0                             ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       sub             %o2, 2, %o2                             ! IEU0
+       EX(STH          %g2, [%o0 - 2] ASINORMAL,
+                       add %o2, 2)                             ! Store Group + bubble
+#ifdef REGS_64BIT
+5:     andcc           %o1, 4, %g0                             ! IEU1
+3:     be,a,pn         %xcc, 2f                                ! CTI
+        andcc          %o2, -128, %g7                          ! IEU1  Group
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EXO2(LDUW       [%o1] ASINORMAL, %g5)                   ! Load  Group
+       add             %o1, 4, %o1                             ! IEU0
+       add             %o0, 4, %o0                             ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       sub             %o2, 4, %o2                             ! IEU0  Group
+       EX(STW          %g5, [%o0 - 4] ASINORMAL,
+                       add %o2, 4)                             ! Store
+       andcc           %o2, -128, %g7                          ! IEU1  Group
+2:     be,pn           %xcc, 3f                                ! CTI
+        andcc          %o0, 4, %g0                             ! IEU1  Group
+       be,pn           %xcc, 82f + 4                           ! CTI   Group
+#else /* !REGS_64BIT */
+5:     andcc           %o2, -128, %g7                          ! IEU1
+       be,a,pn         %xcc, 41f                               ! CTI
+        andcc          %o2, 0x70, %g7                          ! IEU1  Group
+#endif /* !REGS_64BIT */
+5:     MOVE_BIGCHUNK(o1, o0, 0x00, g1, g3, g5, o5)
+       MOVE_BIGCHUNK(o1, o0, 0x20, g1, g3, g5, o5)
+       MOVE_BIGCHUNK(o1, o0, 0x40, g1, g3, g5, o5)
+       MOVE_BIGCHUNK(o1, o0, 0x60, g1, g3, g5, o5)
+       EXT(5b,35f,VIScopyfixup1)
+35:    subcc           %g7, 128, %g7                           ! IEU1  Group
+       add             %o1, 128, %o1                           ! IEU0
+       bne,pt          %xcc, 5b                                ! CTI
+        add            %o0, 128, %o0                           ! IEU0  Group
+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__
+       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
+        add            %o0, %g7, %o0                           ! IEU0  Group
+#else
+       sll             %g7, 1, %g5                             ! IEU0  Group
+       add             %o1, %g7, %o1                           ! IEU1
+       sub             %o5, %g5, %o5                           ! IEU0  Group
+       jmpl            %o5 + %lo(80f - 79b), %g0               ! CTI   Group brk forced
+        add            %o0, %g7, %o0                           ! IEU0  Group
+#endif
+36:    MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g5, o5)
+       MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g5, o5)
+       MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g5, o5)
+       MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g5, o5)
+       MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g5, o5)
+       MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g5, o5)
+       MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g5, o5)
+       EXT(36b,80f,VIScopyfixup2)
+80:    be,pt           %xcc, 81f                               ! CTI
+        andcc          %o2, 4, %g0                             ! IEU1
+#ifdef REGS_64BIT
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDX          [%o1] ASINORMAL, %g2,
+                       and %o2, 0xf)                           ! Load  Group
+       add             %o0, 8, %o0                             ! IEU0
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       EX(STW          %g2, [%o0 - 0x4] ASINORMAL,
+                       and %o2, 0xf)                           ! Store Group
+       add             %o1, 8, %o1                             ! IEU1
+       srlx            %g2, 32, %g2                            ! IEU0  Group
+       EX2(STW         %g2, [%o0 - 0x8] ASINORMAL,
+                       and %o2, 0xf, %o2,
+                       sub %o2, 4)                             ! Store
+#else /* !REGS_64BIT */
+       lduw            [%o1], %g2                              ! Load  Group
+       add             %o0, 8, %o0                             ! IEU0
+       lduw            [%o1 + 0x4], %g3                        ! Load  Group
+       add             %o1, 8, %o1                             ! IEU0
+       stw             %g2, [%o0 - 0x8]                        ! Store Group
+       stw             %g3, [%o0 - 0x4]                        ! Store Group
+#endif /* !REGS_64BIT */
+81:    be,pt           %xcc, 1f                                ! CTI
+        andcc          %o2, 2, %g0                             ! IEU1  Group
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDUW         [%o1] ASINORMAL, %g2,
+                       and %o2, 0x7)                           ! Load  Group
+       add             %o1, 4, %o1                             ! IEU0
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       EX(STW          %g2, [%o0] ASINORMAL,
+                       and %o2, 0x7)                           ! Store Group
+       add             %o0, 4, %o0                             ! IEU0
+1:     be,pt           %xcc, 1f                                ! CTI
+        andcc          %o2, 1, %g0                             ! IEU1  Group
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDUH         [%o1] ASINORMAL, %g2,
+                       and %o2, 0x3)                           ! Load  Group
+       add             %o1, 2, %o1                             ! IEU0
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       EX(STH          %g2, [%o0] ASINORMAL,
+                       and %o2, 0x3)                           ! Store Group
+       add             %o0, 2, %o0                             ! IEU0
+1:     be,pt           %xcc, normal_retl                       ! CTI
+        nop                                                    ! IEU1
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDUB         [%o1] ASINORMAL, %g2,
+                       add %g0, 1)                             ! Load  Group
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       EX(STB          %g2, [%o0] ASINORMAL,
+                       add %g0, 1)                             ! Store Group + bubble
+normal_retl:
+       NORMAL_RETL
+
+#ifdef REGS_64BIT
+82:    MOVE_BIGALIGNCHUNK(o1, o0, 0x00, g1, g3, g5, o5)
+       MOVE_BIGALIGNCHUNK(o1, o0, 0x40, g1, g3, g5, o5)
+       EXT(82b,37f,VIScopyfixup3)
+37:    subcc           %g7, 128, %g7                           ! IEU1  Group
+       add             %o1, 128, %o1                           ! IEU0
+       bne,pt          %xcc, 82b                               ! CTI
+        add            %o0, 128, %o0                           ! IEU0  Group
+       andcc           %o2, 0x70, %g7                          ! IEU1
+       be,pn           %xcc, 84f                               ! CTI
+        andcc          %o2, 8, %g0                             ! IEU1  Group
+                                                               ! 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
+        add            %o0, %g7, %o0                           ! IEU0  Group
+#endif
+38:    MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3)
+       EXT(38b,84f,VIScopyfixup4)
+84:    be,pt           %xcc, 85f                               ! CTI   Group
+        andcc          %o2, 4, %g0                             ! IEU1
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDX          [%o1] ASINORMAL, %g2,
+                       and %o2, 0xf)                           ! Load  Group
+       add             %o1, 8, %o1                             ! IEU0
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       add             %o0, 8, %o0                             ! IEU0  Group
+       EX(STX          %g2, [%o0 - 0x8] ASINORMAL,
+                       and %o2, 0xf)                           ! Store
+85:    be,pt           %xcc, 1f                                ! CTI
+        andcc          %o2, 2, %g0                             ! IEU1  Group
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDUW         [%o1] ASINORMAL, %g2,
+                       and %o2, 0x7)                           ! Load  Group
+       add             %o1, 4, %o1                             ! IEU0
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       add             %o0, 4, %o0                             ! IEU0  Group
+       EX(STW          %g2, [%o0 - 0x4] ASINORMAL,
+                       and %o2, 0x7)                           ! Store
+1:     be,pt           %xcc, 1f                                ! CTI
+        andcc          %o2, 1, %g0                             ! IEU1  Group
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDUH         [%o1] ASINORMAL, %g2,
+                       and %o2, 0x3)                           ! Load  Group
+       add             %o1, 2, %o1                             ! IEU0
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       add             %o0, 2, %o0                             ! IEU0  Group
+       EX(STH          %g2, [%o0 - 0x2] ASINORMAL,
+                       and %o2, 0x3)                           ! Store
+1:     be,pt           %xcc, 1f                                ! CTI
+        nop                                                    ! IEU0  Group
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDUB         [%o1] ASINORMAL, %g2,
+                       add %g0, 1)                             ! Load  Group
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       EX(STB          %g2, [%o0] ASINORMAL,
+                       add %g0, 1)                             ! Store Group + bubble
+1:     NORMAL_RETL
+#endif /* REGS_64BIT */
+
+memcpy_noVIS_misaligned:
+       brz,pt                  %g2, 2f                         ! CTI   Group
+        mov                    8, %g1                          ! IEU0
+       sub                     %g1, %g2, %g2                   ! IEU0  Group
+       sub                     %o2, %g2, %o2                   ! IEU0  Group
+1:     ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDUB                 [%o1] ASINORMAL, %g5,
+                               add %o2, %g2)                   ! Load  Group
+       add                     %o1, 1, %o1                     ! IEU0
+       add                     %o0, 1, %o0                     ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       subcc                   %g2, 1, %g2                     ! IEU1  Group
+       bne,pt                  %xcc, 1b                        ! CTI
+        EX2(STB                %g5, [%o0 - 1] ASINORMAL,
+                               add %o2, %g2, %o2,
+                               add %o2, 1)                     ! Store
+2:
+#ifdef __KERNEL__
+       wr                      %g0, FPRS_FEF, %fprs            ! FPU   Group
+#endif
+       andn                    %o2, 7, %g5                     ! IEU0  Group
+       and                     %o2, 7, %o2                     ! IEU1
+       fmovd                   %f0, %f2                        ! FPU
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       alignaddr               %o1, %g0, %g1                   ! GRU   Group
+       EXO2(LDDF               [%g1] ASINORMAL, %f4)           ! Load  Group
+1:     EX(LDDF                 [%g1 + 0x8] ASINORMAL, %f6,
+                               add %o2, %g5)                   ! Load  Group
+       add                     %g1, 0x8, %g1                   ! IEU0  Group
+       subcc                   %g5, 8, %g5                     ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       faligndata              %f4, %f6, %f0                   ! GRU   Group
+       EX2(STDF                %f0, [%o0] ASINORMAL,
+                               add %o2, %g5, %o2,
+                               add %o2, 8)                     ! Store
+       add                     %o1, 8, %o1                     ! IEU0  Group
+       be,pn                   %xcc, end_cruft                 ! CTI
+        add                    %o0, 8, %o0                     ! IEU1
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       EX(LDDF                 [%g1 + 0x8] ASINORMAL, %f4,
+                               add %o2, %g5)                   ! Load  Group
+       add                     %g1, 8, %g1                     ! IEU0
+       subcc                   %g5, 8, %g5                     ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       faligndata              %f6, %f4, %f0                   ! GRU   Group
+       EX2(STDF                %f0, [%o0] ASINORMAL,
+                               add %o2, %g5, %o2,
+                               add %o2, 8)                     ! Store
+       add                     %o1, 8, %o1                     ! IEU0
+       ASI_SETSRC_NOBLK                                        ! LSU   Group
+       bne,pn                  %xcc, 1b                        ! CTI   Group
+        add                    %o0, 8, %o0                     ! IEU0
+end_cruft:
+       brz,pn                  %o2, fpu_retl                   ! CTI   Group
+#ifndef __KERNEL__
+        nop                                                    ! IEU0
+#else
+        ASI_SETSRC_NOBLK                                       ! LSU   Group
+#endif
+       EXO2(LDUB       [%o1] ASINORMAL, %g5)                   ! LOAD
+       add             %o1, 1, %o1                             ! IEU0
+       add             %o0, 1, %o0                             ! IEU1
+       ASI_SETDST_NOBLK                                        ! LSU   Group
+       subcc           %o2, 1, %o2                             ! IEU1
+       bne,pt          %xcc, vis_slp                           ! CTI
+        EX(STB         %g5, [%o0 - 1] ASINORMAL,
+                       add %o2, 1)                             ! Store Group
+fpu_retl:
+       FPU_RETL
+
+#ifdef __KERNEL__
+               .section        .fixup
+               .align          4
+VIScopyfixup_reto2:
+               mov             %o2, %o0
+VIScopyfixup_ret:
+               retl
+                wr             %g0, 0, %fprs
+VIScopyfixup1: subcc           %g2, 18, %g2
+               bgeu,a,pt       %icc, VIScopyfixup1
+                sub            %g7, 32, %g7
+               rd              %pc, %g5
+               add             %g2, 18, %g2
+               add             %g2, 20, %g2
+               ldub            [%g5 + %g2], %g2
+               ba,a,pt         %xcc, 2f
+.byte          0, 0, 0, 0, 0, 0, 0, 4, 4, 8, 12, 12, 16, 20, 20, 24, 28, 28
+               .align          4
+VIScopyfixup2: mov             (7 * 16), %g7
+1:             subcc           %g2, 10, %g2
+               bgeu,a,pt       %icc, 1b
+                sub            %g7, 16, %g7
+               rd              %pc, %g5
+               add             %g2, 10, %g2
+               add             %g2, 20, %g2
+               ldub            [%g5 + %g2], %g2
+               ba,a,pt         %xcc, 4f
+.byte          0, 0, 0, 0, 0, 4, 4, 8, 12, 12
+               .align          4
+VIScopyfixup3: subcc           %g2, 10, %g2
+               bgeu,a,pt       %icc, VIScopyfixup3
+                sub            %g7, 32, %g7
+               rd              %pc, %g5
+               add             %g2, 10, %g2
+               add             %g2, 20, %g2
+               ldub            [%g5 + %g2], %g2
+               ba,a,pt         %xcc, 2f
+.byte          0, 0, 0, 0, 0, 0, 0, 8, 16, 24
+               .align          4
+2:             and             %g1, 0x7f, %g1
+               sub             %g7, %g2, %g7
+               ba,pt           %xcc, VIScopyfixup_ret
+                add            %g7, %g1, %o0
+VIScopyfixup4: mov             (7 * 16), %g7
+3:             subcc           %g2, 6, %g2
+               bgeu,a,pt       %icc, 3b
+                sub            %g7, 16, %g7
+               rd              %pc, %g5
+               add             %g2, 6, %g2
+               add             %g2, 20, %g2
+               ldub            [%g5 + %g2], %g2
+               ba,a,pt         %xcc, 4f
+.byte          0, 0, 0, 0, 0, 8
+               .align          4
+4:             and             %g1, 7, %g1
+               ba,pt           %xcc, VIScopyfixup_ret
+                add            %g7, %g1, %o0
+VIScopyfixup_vis3:
+               sub             %o2, 0x80, %o2
+VIScopyfixup_vis2:
+               add             %o2, 0x40, %o2
+VIScopyfixup_vis0:
+               add             %o2, 0x80, %o2
+VIScopyfixup_vis1:
+               add             %g7, %g3, %g7
+               ba,pt           %xcc, VIScopyfixup_ret
+                add            %o2, %g7, %o0
+VIScopyfixup_vis5:
+               add             %g3, 8, %g3
+VIScopyfixup_vis4:
+               add             %g3, 8, %g3
+               ba,pt           %xcc, VIScopyfixup_ret
+                add            %o2, %g3, %o0
+#endif
+
+#ifdef __KERNEL__
+               .text
+               .align          32
+
+               .globl          __memmove
+               .type           __memmove,@function
+
+               .globl          memmove
+               .type           memmove,@function
+
+memmove:
+__memmove:     cmp             %o0, %o1
+               blu,pt          %xcc, memcpy_private
+                sub            %o0, %o1, %g5
+               add             %o1, %o2, %g3
+               cmp             %g3, %o0
+               bleu,pt         %xcc, memcpy_private
+                add            %o1, %o2, %g5
+               add             %o0, %o2, %o5
+
+               sub             %g5, 1, %o1
+               sub             %o5, 1, %o0
+1:             ldub            [%o1], %g5
+               subcc           %o2, 1, %o2
+               sub             %o1, 1, %o1
+               stb             %g5, [%o0]
+               bne,pt          %icc, 1b
+                sub            %o0, 1, %o0
+
+               retl
+                clr            %o0
+#endif
diff --git a/arch/sparc64/lib/VISmemset.S b/arch/sparc64/lib/VISmemset.S
new file mode 100644 (file)
index 0000000..bdcba34
--- /dev/null
@@ -0,0 +1,228 @@
+/* $Id: VISmemset.S,v 1.4 1997/07/02 19:00:39 jj Exp $
+ * VISmemset.S: High speed memset operations utilizing the UltraSparc
+ *        Visual Instruction Set.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include "VIS.h"
+
+#ifdef REGS_64BIT
+#define SET_BLOCKS(base, offset, source)       \
+       stx     source, [base - offset - 0x18]; \
+       stx     source, [base - offset - 0x10]; \
+       stx     source, [base - offset - 0x08]; \
+       stx     source, [base - offset - 0x00];
+#else
+#define SET_BLOCKS(base, offset, source)       \
+       stw     source, [base - offset - 0x18]; \
+       stw     source, [base - offset - 0x14]; \
+       stw     source, [base - offset - 0x10]; \
+       stw     source, [base - offset - 0x0c]; \
+       stw     source, [base - offset - 0x08]; \
+       stw     source, [base - offset - 0x04]; \
+       stw     source, [base - offset - 0x00]; \
+       stw     source, [base - offset + 0x04];
+#endif
+
+#ifndef __KERNEL__
+/* So that the brz,a,pt in memset doesn't have to get through PLT, here we go... */
+#include "VISbzero.S"
+#endif
+
+#ifdef __KERNEL__
+#define RETL   clr %o0
+#else
+#define RETL   mov %g3, %o0
+#endif
+
+       /* Well, memset is a lot easier to get right than bcopy... */
+       .text
+       .align          32
+#ifdef __KERNEL__
+       .globl          __memset
+__memset:
+#endif
+       .globl          memset
+memset:
+#ifndef __KERNEL__
+       brz,a,pt        %o1, bzero_private
+        mov            %o2, %o1
+#ifndef REGS_64BIT
+       srl             %o2, 0, %o2
+#endif
+       mov             %o0, %g3
+#endif
+       cmp             %o2, 7
+       bleu,pn         %xcc, 17f
+        andcc          %o0, 3, %g5
+       be,pt           %xcc, 4f
+        and            %o1, 0xff, %o1
+       cmp             %g5, 3
+       be,pn           %xcc, 2f
+        stb            %o1, [%o0 + 0x00]
+       cmp             %g5, 2
+       be,pt           %xcc, 2f
+        stb            %o1, [%o0 + 0x01]
+       stb             %o1, [%o0 + 0x02]
+2:     sub             %g5, 4, %g5
+       sub             %o0, %g5, %o0
+       add             %o2, %g5, %o2
+4:     sllx            %o1, 8, %g1
+       andcc           %o0, 4, %g0
+       or              %o1, %g1, %o1
+       sllx            %o1, 16, %g1
+       or              %o1, %g1, %o1
+       be,pt           %xcc, 2f
+#ifdef REGS_64BIT
+        sllx           %o1, 32, %g1
+#else
+        cmp            %o2, 128
+#endif
+       stw             %o1, [%o0]
+       sub             %o2, 4, %o2
+       add             %o0, 4, %o0
+2:
+#ifdef REGS_64BIT
+       cmp             %o2, 128
+       or              %o1, %g1, %o1
+#endif
+       blu,pn          %xcc, 9f
+        andcc          %o0, 0x38, %g5
+       be,pn           %icc, 6f
+        mov            64, %o5
+       andcc           %o0, 8, %g0
+       be,pn           %icc, 1f
+        sub            %o5, %g5, %o5
+#ifdef REGS_64BIT
+       stx             %o1, [%o0]
+#else
+       stw             %o1, [%o0]
+       stw             %o1, [%o0 + 4]
+#endif
+       add             %o0, 8, %o0
+1:     andcc           %o5, 16, %g0
+       be,pn           %icc, 1f
+        sub            %o2, %o5, %o2
+#ifdef REGS_64BIT
+       stx             %o1, [%o0]
+       stx             %o1, [%o0 + 8]
+#else
+       stw             %o1, [%o0]
+       stw             %o1, [%o0 + 4]
+       stw             %o1, [%o0 + 8]
+       stw             %o1, [%o0 + 12]
+#endif
+       add             %o0, 16, %o0
+1:     andcc           %o5, 32, %g0
+       be,pn           %icc, 7f
+        andncc         %o2, 0x3f, %o3
+#ifdef REGS_64BIT
+       stx             %o1, [%o0]
+       stx             %o1, [%o0 + 8]
+       stx             %o1, [%o0 + 16]
+       stx             %o1, [%o0 + 24]
+#else
+       stw             %o1, [%o0]
+       stw             %o1, [%o0 + 4]
+       stw             %o1, [%o0 + 8]
+       stw             %o1, [%o0 + 12]
+       stw             %o1, [%o0 + 16]
+       stw             %o1, [%o0 + 20]
+       stw             %o1, [%o0 + 24]
+       stw             %o1, [%o0 + 28]
+#endif
+       add             %o0, 32, %o0
+7:     be,pn           %xcc, 9f
+#ifdef __KERNEL__
+        wr             %g0, FPRS_FEF, %fprs
+#endif
+       ldd             [%o0 - 8], %f0
+18:    wr              %g0, ASI_BLK_P, %asi
+       membar          #StoreStore | #LoadStore
+       andcc           %o3, 0xc0, %g5
+       and             %o2, 0x3f, %o2
+       fmovd           %f0, %f2
+       fmovd           %f0, %f4
+       andn            %o3, 0xff, %o3
+       fmovd           %f0, %f6
+       cmp             %g5, 64
+       fmovd           %f0, %f8
+       fmovd           %f0, %f10
+       fmovd           %f0, %f12
+       brz,pn          %g5, 10f
+        fmovd          %f0, %f14
+       be,pn           %icc, 2f
+        stda           %f0, [%o0 + 0x00] %asi
+       cmp             %g5, 128
+       be,pn           %icc, 2f
+        stda           %f0, [%o0 + 0x40] %asi
+       stda            %f0, [%o0 + 0x80] %asi
+2:     brz,pn          %o3, 12f
+        add            %o0, %g5, %o0
+10:    stda            %f0, [%o0 + 0x00] %asi
+       stda            %f0, [%o0 + 0x40] %asi
+       stda            %f0, [%o0 + 0x80] %asi
+       stda            %f0, [%o0 + 0xc0] %asi
+11:    subcc           %o3, 256, %o3
+       bne,pt          %xcc, 10b
+        add            %o0, 256, %o0
+12:
+#ifdef __KERNEL__
+       wr              %g0, 0, %fprs
+#endif
+       membar          #Sync
+9:     andcc           %o2, 0x78, %g5
+       be,pn           %xcc, 13f
+        andcc          %o2, 7, %o2
+14:    rd              %pc, %o4
+#ifdef REGS_64BIT
+       srl             %g5, 1, %o3
+       sub             %o4, %o3, %o4
+#else
+       sub             %o4, %g5, %o4
+#endif
+       jmpl            %o4 + (13f - 14b), %g0
+        add            %o0, %g5, %o0
+12:    SET_BLOCKS(%o0, 0x68, %o1)
+       SET_BLOCKS(%o0, 0x48, %o1)
+       SET_BLOCKS(%o0, 0x28, %o1)
+       SET_BLOCKS(%o0, 0x08, %o1)
+13:    be,pn           %xcc, 8f
+        andcc          %o2, 4, %g0
+       be,pn           %xcc, 1f
+        andcc          %o2, 2, %g0
+       stw             %o1, [%o0]
+       add             %o0, 4, %o0
+1:     be,pn           %xcc, 1f
+        andcc          %o2, 1, %g0
+       sth             %o1, [%o0]
+       add             %o0, 2, %o0
+1:     bne,a,pn        %xcc, 8f
+        stb            %o1, [%o0]
+8:     retl
+        RETL
+17:    brz,pn          %o2, 0f
+8:      add            %o0, 1, %o0
+       subcc           %o2, 1, %o2
+       bne,pt          %xcc, 8b
+        stb            %o1, [%o0 - 1]
+0:     retl
+        RETL
+6:
+#ifdef REGS_64BIT
+       stx             %o1, [%o0]
+#else
+       stw             %o1, [%o0]
+       stw             %o1, [%o0 + 4]
+#endif
+       andncc          %o2, 0x3f, %o3
+       be,pn           %xcc, 9b
+#ifdef __KERNEL__
+        wr             %g0, FPRS_FEF, %fprs
+#else
+        nop
+#endif
+       ba,pt           %xcc, 18b
+        ldd            [%o0], %f0
index d3ed456ca2de236a72452f5412fca62e6a673753..59083aa028b6c08590b954bb8e6873fd6bf99da1 100644 (file)
-/* $Id: blockops.S,v 1.7 1997/06/14 21:27:55 davem Exp $
+/* $Id: blockops.S,v 1.10 1997/06/24 17:29:10 jj Exp $
  * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
-#include <asm/asi.h>
+#include "VIS.h"
 
-#undef VIS_BLOCKOPS
+       .text
+       .align          32
 
-       /* Zero out 256 bytes of memory at (buf + offset). */
-#define BLAST_BLOCK(buf, offset)                               \
-       stda            %f48, [buf + offset + 0x00] %asi;       \
-       stda            %f48, [buf + offset + 0x40] %asi;       \
-       stda            %f48, [buf + offset + 0x80] %asi;       \
-       stda            %f48, [buf + offset + 0xc0] %asi;
+       .globl          __bfill64
+__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
+       mov             32, %g2                         ! IEU0  Group
 
-       /* Copy 256 bytes of memory at (src + offset) to
-        * (dst + offset).
+       /* Cannot perform real arithmatic on the pattern, that can
+        * lead to fp_exception_other ;-)
         */
-#define MIRROR_BLOCK(dst, src, offset, sync)                   \
-       ldda            [src + offset + 0x000] %asi, %f0;       \
-       ldda            [src + offset + 0x040] %asi, %f16;      \
-       ldda            [src + offset + 0x080] %asi, %f32;      \
-       ldda            [src + offset + 0x0c0] %asi, %f48;      \
-       membar          sync;                                   \
-       stda            %f0, [dst + offset + 0x000] %asi;       \
-       stda            %f16, [dst + offset + 0x040] %asi;      \
-       stda            %f32, [dst + offset + 0x080] %asi;      \
-       stda            %f48, [dst + offset + 0x0c0] %asi;
+       fmovd           %f48, %f50                      ! FPA   Group
+       fmovd           %f48, %f52                      ! FPA   Group
+       fmovd           %f48, %f54                      ! FPA   Group
+       fmovd           %f48, %f56                      ! FPA   Group
+       fmovd           %f48, %f58                      ! FPA   Group
+       fmovd           %f48, %f60                      ! FPA   Group
+       fmovd           %f48, %f62                      ! FPA   Group
 
-       .text
-       .align  4
-
-#ifdef VIS_BLOCKOPS
-       .globl          __bzero_1page
-__bzero_1page:
-       /* %o0 = buf */
-       mov             %o0, %o1
-       wr              %g0, ASI_BLK_P, %asi
-       mov             0x08, %g2
-       membar          #Sync|#StoreLoad
-       fzero           %f48
-       fzero           %f50
-       fzero           %f52
-       fzero           %f54
-       fzero           %f56
-       fzero           %f58
-       fzero           %f60
-       fzero           %f62
-1:
-       BLAST_BLOCK(%o0, 0x000)
-       BLAST_BLOCK(%o0, 0x100)
-       BLAST_BLOCK(%o0, 0x200)
-       BLAST_BLOCK(%o0, 0x300)
-       subcc           %g2, 1, %g2
-       bne,pt          %icc, 1b
-        add            %o0, 0x400, %o0
+1:     stda            %f48, [%o0 + 0x00] %asi         ! Store Group
+       stda            %f48, [%o0 + 0x40] %asi         ! Store Group
+       stda            %f48, [%o0 + 0x80] %asi         ! Store Group
+       stda            %f48, [%o0 + 0xc0] %asi         ! Store Group
+       subcc           %g2, 1, %g2                     ! IEU1  Group
+       bne,pt          %icc, 1b                        ! CTI
+        add            %o0, 0x100, %o0                 ! IEU0
+       membar          #Sync                           ! LSU   Group
 
-       membar          #Sync|#LoadStore|#StoreStore
-
-       retl
-        mov            %o1, %o0
-#else
-#define BZERO_256BYTES(base)                                           \
-       stx     %g0, [base + 0x00];     stx     %g0, [base + 0x08];     \
-       stx     %g0, [base + 0x10];     stx     %g0, [base + 0x18];     \
-       stx     %g0, [base + 0x20];     stx     %g0, [base + 0x28];     \
-       stx     %g0, [base + 0x30];     stx     %g0, [base + 0x38];     \
-       stx     %g0, [base + 0x40];     stx     %g0, [base + 0x48];     \
-       stx     %g0, [base + 0x50];     stx     %g0, [base + 0x58];     \
-       stx     %g0, [base + 0x60];     stx     %g0, [base + 0x68];     \
-       stx     %g0, [base + 0x70];     stx     %g0, [base + 0x78];     \
-       stx     %g0, [base + 0x80];     stx     %g0, [base + 0x88];     \
-       stx     %g0, [base + 0x90];     stx     %g0, [base + 0x98];     \
-       stx     %g0, [base + 0xa0];     stx     %g0, [base + 0xa8];     \
-       stx     %g0, [base + 0xb0];     stx     %g0, [base + 0xb8];     \
-       stx     %g0, [base + 0xc0];     stx     %g0, [base + 0xc8];     \
-       stx     %g0, [base + 0xd0];     stx     %g0, [base + 0xd8];     \
-       stx     %g0, [base + 0xe0];     stx     %g0, [base + 0xe8];     \
-       stx     %g0, [base + 0xf0];     stx     %g0, [base + 0xf8];
+       jmpl            %o7 + 0x8, %g0                  ! CTI   Group brk forced
+        wr             %g0, 0, %fprs                   ! FPU   Group
 
        .align          32
        .globl          __bzero_1page
 __bzero_1page:
-       mov             32, %g1
-1:
-       BZERO_256BYTES(%g2)
-       subcc           %g1, 1, %g1
-       bne,pt          %icc, 1b
-        add            %g2, 0x100, %g2
-       jmpl            %o7 + 0x8, %g0
-        mov            %g3, %o7
-#endif
-
-       .globl          __bfill64
-__bfill64:
-#if 1
-       /* %o0 = buf, %o1 = 64-bit pattern */
-#define FILL_BLOCK(buf, offset) \
-       stx     %o1, [buf + offset + 0x38]; \
-       stx     %o1, [buf + offset + 0x30]; \
-       stx     %o1, [buf + offset + 0x28]; \
-       stx     %o1, [buf + offset + 0x20]; \
-       stx     %o1, [buf + offset + 0x18]; \
-       stx     %o1, [buf + offset + 0x10]; \
-       stx     %o1, [buf + offset + 0x08]; \
-       stx     %o1, [buf + offset + 0x00];
-
-       mov     0x20, %g2
-1:
-       FILL_BLOCK(%o0, 0x00)
-       FILL_BLOCK(%o0, 0x40)
-       FILL_BLOCK(%o0, 0x80)
-       FILL_BLOCK(%o0, 0xc0)
-       subcc   %g2, 1, %g2
-       bne,pt  %icc, 1b
-        add    %o0, 0x100, %o0
-       retl
-        nop
-#undef FILL_BLOCK
-
-#else
-       /* %o0 = buf */
-       stx             %o1, [%sp + 0x7ff + 128]
-       wr              %g0, ASI_BLK_P, %asi
-       mov             0x08, %g2
-       ldd             [%sp + 0x7ff + 128], %f48
-       membar          #Sync|#StoreLoad
-       fmovd           %f48, %f50
-       fmovd           %f48, %f52
-       fmovd           %f48, %f54
-       fmovd           %f48, %f56
-       fmovd           %f48, %f58
-       fmovd           %f48, %f60
-       fmovd           %f48, %f62
-1:
-       BLAST_BLOCK(%o0, 0x000)
-       BLAST_BLOCK(%o0, 0x100)
-       BLAST_BLOCK(%o0, 0x200)
-       BLAST_BLOCK(%o0, 0x300)
-       subcc           %g2, 1, %g2
-       bne,pt          %icc, 1b
-        add            %o0, 0x400, %o0
-
-       retl
-        membar         #Sync|#LoadStore|#StoreStore
-#endif
+       wr              %g0, FPRS_FEF, %fprs            ! FPU   Group
+       fzero           %f0                             ! FPA   Group
+       mov             32, %g1                         ! IEU0
+       fzero           %f2                             ! FPA   Group
+       faddd           %f0, %f2, %f4                   ! FPA   Group
+       fmuld           %f0, %f2, %f6                   ! FPM
+       faddd           %f0, %f2, %f8                   ! FPA   Group
+       fmuld           %f0, %f2, %f10                  ! FPM
 
-#if 0
-       .globl          __copy_1page
-__copy_1page:
-       /* %o0 = dst, %o1 = src */
-       or              %g0, 0x08, %g1
-       wr              %g0, ASI_BLK_P, %asi
-       membar          #Sync|#StoreLoad
-1:
-       MIRROR_BLOCK(%o0, %o1, 0x000, #Sync)
-       MIRROR_BLOCK(%o0, %o1, 0x100, #Sync)
-       MIRROR_BLOCK(%o0, %o1, 0x200, #Sync)
-       MIRROR_BLOCK(%o0, %o1, 0x300, #Sync)
-       subcc           %g1, 1, %g1
-       add             %o0, 0x400, %o0
-       bne,pt          %icc, 1b
-        add            %o1, 0x400, %o1
+       faddd           %f0, %f2, %f12                  ! FPA   Group
+       fmuld           %f0, %f2, %f14                  ! FPM
+       wr              %g0, ASI_BLK_P, %asi            ! LSU   Group
+       membar          #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
+       stda            %f0, [%o0 + 0xc0] %asi          ! Store Group
 
-       retl
-        membar         #Sync|#LoadStore|#StoreStore
-#endif
+       subcc           %g1, 1, %g1                     ! IEU1
+       bne,pt          %icc, 1b                        ! CTI
+        add            %o0, 0x100, %o0                 ! IEU0  Group
+       membar          #Sync                           ! LSU   Group
+       jmpl            %o7 + 0x8, %g0                  ! CTI   Group brk forced
+        wr             %g0, 0, %fprs                   ! FPU   Group
index 10eebb8df3351dddb95d40808bc4fab93ec1d21a..179e17960e76f6178c03a08a34669d2c07d97d68 100644 (file)
 #include <asm/head.h>
 #include <asm/ptrace.h>
 #include <asm/asi.h>
+#include <asm/page.h>
 
-#define CSUM_BIGCHUNK(buf, offset, sum, t0, t1, t2, t3, t4, t5)        \
-       ldd     [buf + offset + 0x00], t0;                      \
-       ldd     [buf + offset + 0x08], t2;                      \
-       addccc  t0, sum, sum;                                   \
-       addccc  t1, sum, sum;                                   \
-       ldd     [buf + offset + 0x10], t4;                      \
-       addccc  t2, sum, sum;                                   \
-       addccc  t3, sum, sum;                                   \
-       ldd     [buf + offset + 0x18], t0;                      \
-       addccc  t4, sum, sum;                                   \
-       addccc  t5, sum, sum;                                   \
-       addccc  t0, sum, sum;                                   \
-       addccc  t1, sum, sum;
+       /* The problem with the "add with carry" instructions on Ultra
+        * 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 somehow, but
+        * this requires more reasoning on my part...
+        *
+        * Assuming ecache hits and branches predicted well, this
+        * can be expected to run at a rate of 16 cycles per 64-bytes
+        * of data summed.  (the old code summed 32 bytes in 20
+        * cycles, with numerous bubbles and unnecessary stalls)
+        */
+#define CSUM_ECACHE_LOAD(buf, offset, t0, t1, t2, t3, t4, t5, t6, t7)                  \
+       ldx     [buf + offset + 0x00], t0;                                              \
+       ldx     [buf + offset + 0x08], t1;                                              \
+       ldx     [buf + offset + 0x10], t2;                                              \
+       ldx     [buf + offset + 0x18], t3;                                              \
+       ldx     [buf + offset + 0x20], t4;                                              \
+       ldx     [buf + offset + 0x28], t5;                                              \
+       ldx     [buf + offset + 0x30], t6;                                              \
+       ldx     [buf + offset + 0x38], t7;                                              \
+       nop; nop;       /* THIS IS CRITICAL!!!!!!!!! */
+
+#define CSUM_ECACHE_BLOCK_LDNEXT(buf, offset, sum, t0, t1, t2, t3, t4, t5, t6, t7)     \
+       addcc           sum, t0, sum;                                                   \
+       bcc,pt          %xcc, 11f;                                                      \
+        ldx            [buf + offset + 0x00], t0;                                      \
+       add             sum, 1, sum;                                                    \
+11:    addcc           sum, t1, sum;                                                   \
+       bcc,pt          %xcc, 12f;                                                      \
+        ldx            [buf + offset + 0x08], t1;                                      \
+       add             sum, 1, sum;                                                    \
+12:    addcc           sum, t2, sum;                                                   \
+       bcc,pt          %xcc, 13f;                                                      \
+        ldx            [buf + offset + 0x10], t2;                                      \
+       add             sum, 1, sum;                                                    \
+13:    addcc           sum, t3, sum;                                                   \
+       bcc,pt          %xcc, 14f;                                                      \
+        ldx            [buf + offset + 0x18], t3;                                      \
+       add             sum, 1, sum;                                                    \
+14:    addcc           sum, t4, sum;                                                   \
+       bcc,pt          %xcc, 15f;                                                      \
+        ldx            [buf + offset + 0x20], t4;                                      \
+       add             sum, 1, sum;                                                    \
+15:    addcc           sum, t5, sum;                                                   \
+       bcc,pt          %xcc, 16f;                                                      \
+        ldx            [buf + offset + 0x28], t5;                                      \
+       add             sum, 1, sum;                                                    \
+16:    addcc           sum, t6, sum;                                                   \
+       bcc,pt          %xcc, 17f;                                                      \
+        ldx            [buf + offset + 0x30], t6;                                      \
+       add             sum, 1, sum;                                                    \
+17:    addcc           sum, t7, sum;                                                   \
+       bcc,pt          %xcc, 18f;                                                      \
+        ldx            [buf + offset + 0x38], t7;                                      \
+       add             sum, 1, sum;                                                    \
+18:    nop; nop;       /* DO NOT TOUCH! */
+
+#define CSUM_ECACHE_BLOCK(sum, t0, t1, t2, t3, t4, t5, t6, t7)                         \
+       addcc           sum, t0, sum;                                                   \
+       bcs,a,pn        %xcc, 21f;                                                      \
+        add            sum, 1, sum;                                                    \
+21:    addcc           sum, t1, sum;                                                   \
+       bcs,a,pn        %xcc, 22f;                                                      \
+        add            sum, 1, sum;                                                    \
+22:    addcc           sum, t2, sum;                                                   \
+       bcs,a,pn        %xcc, 23f;                                                      \
+        add            sum, 1, sum;                                                    \
+23:    addcc           sum, t3, sum;                                                   \
+       bcs,a,pn        %xcc, 24f;                                                      \
+        add            sum, 1, sum;                                                    \
+24:    addcc           sum, t4, sum;                                                   \
+       bcs,a,pn        %xcc, 25f;                                                      \
+        add            sum, 1, sum;                                                    \
+25:    addcc           sum, t5, sum;                                                   \
+       bcs,a,pn        %xcc, 26f;                                                      \
+        add            sum, 1, sum;                                                    \
+26:    addcc           sum, t6, sum;                                                   \
+       bcs,a,pn        %xcc, 27f;                                                      \
+        add            sum, 1, sum;                                                    \
+27:    addcc           sum, t7, sum;                                                   \
+       bcs,a,pn        %xcc, 28f;                                                      \
+        add            sum, 1, sum;                                                    \
+28:
 
-#define CSUM_LASTCHUNK(buf, offset, sum, t0, t1, t2, t3)       \
-       ldd     [buf - offset - 0x08], t0;                      \
-       ldd     [buf - offset - 0x00], t2;                      \
-       addccc  t0, sum, sum;                                   \
-       addccc  t1, sum, sum;                                   \
-       addccc  t2, sum, sum;                                   \
-       addccc  t3, sum, sum;
+#define CSUM_LASTCHUNK(buf, offset, sum, t0, t1)                                       \
+       ldx             [buf - offset - 0x08], t0;                                      \
+       ldx             [buf - offset - 0x00], t1;                                      \
+       addcc           t0, sum, sum;                                                   \
+       bcs,a,pn        %xcc, 31f;                                                      \
+        add            sum, 1, sum;                                                    \
+31:    addcc           t1, sum, sum;                                                   \
+       bcs,a,pn        %xcc, 32f;                                                      \
+        add            sum, 1, sum;                                                    \
+32:
 
-       /* Do end cruft out of band to get better cache patterns. */
+       .text
+       /* Keep this garbage from swiping the icache. */
 csum_partial_end_cruft:
-       andcc   %o1, 8, %g0                     ! check how much
-       be,pn   %icc, 1f                        ! caller asks %o1 & 0x8
-        and    %o1, 4, %g5                     ! nope, check for word remaining
-       ldd     [%o0], %g2                      ! load two
-       addcc   %g2, %o2, %o2                   ! add first word to sum
-       addccc  %g3, %o2, %o2                   ! add second word as well
-       add     %o0, 8, %o0                     ! advance buf ptr
-       addc    %g0, %o2, %o2                   ! add in final carry
-1:     brz,pn  %g5, 1f                         ! nope, skip this code
-        andcc  %o1, 3, %o1                     ! check for trailing bytes
-       ld      [%o0], %g2                      ! load it
-       addcc   %g2, %o2, %o2                   ! add to sum
-       add     %o0, 4, %o0                     ! advance buf ptr
-       addc    %g0, %o2, %o2                   ! add in final carry
-1:     brz,pn  %o1, 1f                         ! no trailing bytes, return
-        addcc  %o1, -1, %g0                    ! only one byte remains?
-       bne,pn  %icc, 2f                        ! at least two bytes more
-        subcc  %o1, 2, %o1                     ! only two bytes more?
-       ba,pt   %xcc, 4f                        ! only one byte remains
-        clr    %o4                             ! clear fake hword value
-2:     lduh    [%o0], %o4                      ! get hword
-       be,pn   %icc, 6f                        ! jmp if only hword remains
-        add    %o0, 2, %o0                     ! advance buf ptr either way
-       sll     %o4, 16, %o4                    ! create upper hword
-4:     ldub    [%o0], %o5                      ! get final byte
-       sll     %o5, 8, %o5                     ! put into place
-       or      %o5, %o4, %o4                   ! coalese with hword (if any)
-6:     addcc   %o4, %o2, %o2                   ! add to sum
-1:     sllx    %g4, 32, %g4                    ! give gfp back
-       addc    %g0, %o2, %o0                   ! add final carry into retval
-       retl                                    ! get outta here
-        srl    %o0, 0, %o0
+       andcc           %o1, 8, %g0                     ! IEU1  Group
+       be,pn           %icc, 1f                        ! CTI
+        and            %o1, 4, %g5                     ! IEU0
+       ldx             [%o0 + 0x00], %g2               ! Load  Group
+       add             %o0, 0x8, %o0                   ! IEU0
+       addcc           %g2, %o2, %o2                   ! IEU1  Group + 2 bubbles
+       bcs,a,pn        %xcc, 1f                        ! CTI
+        add            %o2, 1, %o2                     ! IEU0  4 clocks (mispredict)
+1:     andcc           %o1, 2, %g0                     ! IEU1  Group
+       brz,pn          %g5, 1f                         ! CTI   Group (needs IEU1)
+        clr            %g2                             ! IEU0
+       ld              [%o0], %g2                      ! Load
+       add             %o0, 4, %o0                     ! IEU0  Group
+       sllx            %g2, 32, %g2                    ! IEU0  Group + 2 bubbles
+1:     and             %o1, 1, %o1                     ! IEU1
+       be,pn           %icc, 1f                        ! CTI
+        clr            %o4                             ! IEU0  Group
+       lduh            [%o0], %o4                      ! Load
+       add             %o0, 2, %o0                     ! IEU1
+       sll             %o4, 16, %o4                    ! IEU0  Group + 2 bubbles
+1:     brz,pn          %o1, 1f                         ! CTI
+        clr            %o5                             ! IEU1
+       ldub            [%o0], %o5                      ! Load  Group
+       sll             %o5, 8, %o5                     ! IEU0  Group + 2 bubbles
+1:     or              %g2, %o4, %o4                   ! IEU1
+       or              %o5, %o4, %o4                   ! IEU0  Group
+       addcc           %o4, %o2, %o2                   ! IEU1  Group (regdep)
+       bcc,pt          %xcc, cfold                     ! CTI
+        sethi          %uhi(PAGE_OFFSET), %g4          ! IEU0
+1:     b,pt            %xcc, cfold                     ! CTI   Group
+        add            %o2, 1, %o2                     ! IEU0
 
-       /* Also do alignment out of band to get better cache patterns. */
-csum_partial_fix_alignment:
+csum_partial_fixit:
+       bl,pn           %icc, cpte                      ! CTI   Group
+        and            %o1, 0xf, %o3                   ! IEU0
+       andcc           %o0, 0x2, %g0                   ! IEU1
+       be,pn           %icc, 1f                        ! CTI   Group
+        and            %o0, 0x4, %g7                   ! IEU0
+       lduh            [%o0 + 0x00], %g2               ! Load
+       sub             %o1, 2, %o1                     ! IEU0  Group
+       addcc           %o0, 2, %o0                     ! IEU1
+       and             %o0, 0x4, %g7                   ! IEU0  Group
+       sll             %g2, 16, %g2                    ! IEU0  Group (no load stall)
+       addcc           %g2, %o2, %o2                   ! IEU1  Group (regdep)
+       bcc,pt          %icc, 0f                        ! CTI
+        andn           %o1, 0xff, %o3                  ! IEU0
+       srl             %o2, 16, %g2                    ! IEU0  Group
+       b,pt            %xcc, 9f                        ! CTI
+        add            %g2, 1, %g2                     ! IEU1
+0:     srl             %o2, 16, %g2                    ! IEU0  Group 8-(
+9:     sll             %o2, 16, %o2                    ! IEU0  Group 8-(
+       sll             %g2, 16, %g3                    ! IEU0  Group 8-(
+       srl             %o2, 16, %o2                    ! IEU0  Group 8-(
+       or              %g3, %o2, %o2                   ! IEU1
+1:     brnz,pt         %g7, 2f                         ! CTI   Group
+        sub            %o1, 4, %o1                     ! IEU0
+       b,pt            %xcc, csum_partial_aligned      ! CTI   Group
+        add            %o1, 4, %o1                     ! IEU0
+2:     ld              [%o0 + 0x00], %g2               ! Load  Group
+       add             %o0, 4, %o0                     ! IEU0
+       andn            %o1, 0xff, %o3                  ! IEU1
+       addcc           %g2, %o2, %o2                   ! IEU1  Group + 2 bubbles
+       bcc,pt          %xcc, csum_partial_aligned      ! CTI
+        nop                                            ! IEU0
+       b,pt            %xcc, csum_partial_aligned      ! CTI   Group
+        add            %o2, 1, %o2                     ! IEU0
 
-       /* The common case is to get called with a nicely aligned
-        * buffer of size 0x20.  Follow the code path for that case.
-        */
-       .globl  csum_partial
+       .align          32
+       .globl          csum_partial
 csum_partial:                                          /* %o0=buf, %o1=len, %o2=sum */
-       srl     %o1, 0, %o1                             ! doof scheiss
-       andcc   %o0, 0x7, %g0                           ! alignment problems?
-       srl     %o2, 0, %o2
-       be,pt   %icc, csum_partial_fix_aligned          ! yep, handle it
-        andn   %o1, 0x7f, %o3                          ! num loop iterations
-       cmp     %o1, 6
-       bl,pn   %icc, cpte - 0x4
-        andcc  %o0, 0x2, %g0
-       be,pn   %icc, 1f
-        and    %o0, 0x4, %g7
-       lduh    [%o0 + 0x00], %g2
-       sub     %o1, 2, %o1
-       add     %o0, 2, %o0
-       sll     %g2, 16, %g2
-       addcc   %g2, %o2, %o2
-       srl     %o2, 16, %g3
-       addc    %g0, %g3, %g2
-       sll     %o2, 16, %o2
-       and     %o0, 0x4, %g7
-       sll     %g2, 16, %g3
-       srl     %o2, 16, %o2
-       or      %g3, %o2, %o2
-1:     brz,pn  %g7, csum_partial_fix_aligned
-        andn   %o1, 0x7f, %o3
-       ld      [%o0 + 0x00], %g2
-       sub     %o1, 4, %o1
-       addcc   %g2, %o2, %o2
-       add     %o0, 4, %o0
-       andn    %o1, 0x7f, %o3
-       addc    %g0, %o2, %o2
-csum_partial_fix_aligned:
-       brz,pt  %o3, 3f                                 ! none to do
-        andcc  %o1, 0x70, %g1                          ! clears carry flag too
-5:     CSUM_BIGCHUNK(%o0, 0x00, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
-       CSUM_BIGCHUNK(%o0, 0x20, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
-       CSUM_BIGCHUNK(%o0, 0x40, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
-       CSUM_BIGCHUNK(%o0, 0x60, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
-       addc    %g0, %o2, %o2                           ! sink in final carry
-       subcc   %o3, 128, %o3                           ! detract from loop iters
-       bne,pt  %icc, 5b                                ! more to do
-        add    %o0, 128, %o0                           ! advance buf ptr
-3:     brz,pn  %g1, cpte                               ! nope
-        andcc  %o1, 0xf, %o3                           ! anything left at all?
-10:    rd      %pc, %g7                                ! get pc
-       srl     %g1, 1, %o4                             ! compute offset
-       sub     %g7, %g1, %g7                           ! adjust jmp ptr
-       sub     %g7, %o4, %g7                           ! final jmp ptr adjust
-       jmp     %g7 + (11f-10b)                         ! enter the table
-        add    %o0, %g1, %o0                           ! advance buf ptr
-cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5)
-       CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3, %g4, %g5)
-       CSUM_LASTCHUNK(%o0, 0x48, %o2, %g2, %g3, %g4, %g5)
-       CSUM_LASTCHUNK(%o0, 0x38, %o2, %g2, %g3, %g4, %g5)
-       CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3, %g4, %g5)
-       CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3, %g4, %g5)
-       CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3, %g4, %g5)
-11:    addc    %g0, %o2, %o2                           ! fetch final carry
-       andcc   %o1, 0xf, %o3                           ! anything left at all?
-cpte:  brnz,pn %o3, csum_partial_end_cruft             ! yep, handle it
-        sethi  %uhi(KERNBASE), %g4
-       mov     %o2, %o0                                ! return computed csum
-       retl                                            ! get outta here
-        sllx   %g4, 32, %g4                            ! give gfp back
+       andcc           %o0, 0x7, %g0                   ! IEU1  Group
+       srl             %o1, 0, %o1                     ! IEU0
+       srl             %o2, 0, %o2                     ! IEU0  Group
+       be,pt           %icc, csum_partial_aligned      ! CTI
+        andn           %o1, 0xff, %o3                  ! IEU1
+       b,pt            %xcc, csum_partial_fixit        ! CTI   Group
+        cmp            %o1, 6                          ! IEU0
+       nop
+csum_partial_aligned:
+       brz,pt          %o3, 3f                         ! CTI   Group
+        and            %o1, 0xf0, %g1                  ! IEU0
+5:     CSUM_ECACHE_LOAD(        %o0, 0x000,      %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
+       CSUM_ECACHE_BLOCK_LDNEXT(%o0, 0x040, %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
+       CSUM_ECACHE_BLOCK_LDNEXT(%o0, 0x080, %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
+       CSUM_ECACHE_BLOCK_LDNEXT(%o0, 0x0c0, %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
+       CSUM_ECACHE_BLOCK(                   %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
+       subcc           %o3, 256, %o3                   ! IEU1  Group
+       bne,pt          %icc, 5b                        ! CTI
+        add            %o0, 256, %o0                   ! IEU0
+       and             %o1, 0xf0, %g1                  ! IEU0  Group
+3:     brz,pn          %g1, cpte                       ! CTI
+        and            %o1, 0xf, %o3                   ! IEU1  Group
+10:    rd              %pc, %g7                        ! LSU   Group + 4 clocks
+       sll             %g1, 1, %o4                     ! IEU0  Group
+       sub             %g7, %o4, %g7                   ! IEU1
+       jmp             %g7 + %lo(cpte - 10b)           ! CTI   Group brk forced
+        add            %o0, %g1, %o0                   ! IEU0
+cptbl: CSUM_LASTCHUNK(%o0, 0xe8, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0xd8, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0xc8, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0xb8, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0xa8, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x98, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x88, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x78, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x48, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x38, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3)
+       CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3)
+cpte:  brnz,pn         %o3, csum_partial_end_cruft     ! CTI   Group
+        sethi          %uhi(PAGE_OFFSET), %g4          ! IEU0
+cfold: sllx            %o2, 32, %o0                    ! IEU0  Group
+       addcc           %o2, %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
 
        .globl __csum_partial_copy_start, __csum_partial_copy_end
 __csum_partial_copy_start:
 
-#define EX(x,y,a,b,z)                           \
-98:     x,y;                                    \
-        .section .fixup,z##alloc,z##execinstr;  \
-        .align  4;                              \
-99:     ba,pt %xcc, 30f;                        \
-         a, b, %o3;                             \
-        .section __ex_table,z##alloc;           \
-        .align  8;                              \
-        .xword   98b, 99b;                      \
-        .text;                                  \
-        .align  4
+       /* 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;                                    \
+       nop; nop; /* DO NOT TOUCH THIS!!!!! */
 
-#define EX2(x,y,z)                             \
-98:     x,y;                                    \
-        .section __ex_table,z##alloc;           \
-        .align  8;                              \
-        .xword   98b, 30f;                      \
-        .text;                                  \
-        .align  4
+#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;                                                   \
+       bcc,pt          %xcc, 11f;                                                      \
+        ldxa           [src + off + 0x00] %asi, t0;                                    \
+       add             sum, 1, sum;                                                    \
+11:    stx             t1, [dest + 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;                                                   \
+       bcc,pt          %xcc, 13f;                                                      \
+        ldxa           [src + off + 0x10] %asi, t2;                                    \
+       add             sum, 1, sum;                                                    \
+13:    stx             t3, [dest + 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;                                                   \
+       bcc,pt          %xcc, 15f;                                                      \
+        ldxa           [src + off + 0x20] %asi, t4;                                    \
+       add             sum, 1, sum;                                                    \
+15:    stx             t5, [dest + 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;                                                   \
+       bcc,pt          %xcc, 17f;                                                      \
+        ldxa           [src + off + 0x30] %asi, t6;                                    \
+       add             sum, 1, sum;                                                    \
+17:    stx             t7, [dest + off - 0x08];                                        \
+       addcc           sum, t7, sum;                                                   \
+       bcc,pt          %xcc, 18f;                                                      \
+        ldxa           [src + off + 0x38] %asi, t7;                                    \
+       add             sum, 1, sum;                                                    \
+18:
 
-#define EX3(x,y,z)                             \
-98:     x,y;                                    \
-        .section __ex_table,z##alloc;           \
-        .align  8;                              \
-        .xword   98b, 96f;                      \
-        .text;                                  \
-        .align  4
+#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;                                                   \
+       srlx            t0, 32, t0;                                                     \
+       stw             t0, [dest + 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;                                                   \
+       srlx            t1, 32, t1;                                                     \
+       stw             t1, [dest + 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;                                                   \
+       srlx            t2, 32, t2;                                                     \
+       stw             t2, [dest + 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;                                                   \
+       srlx            t3, 32, t3;                                                     \
+       stw             t3, [dest + 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;                                                   \
+       srlx            t4, 32, t4;                                                     \
+       stw             t4, [dest + 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;                                                   \
+       srlx            t5, 32, t5;                                                     \
+       stw             t5, [dest + 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;                                                   \
+       srlx            t6, 32, t6;                                                     \
+       stw             t6, [dest + 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;                                                   \
+       srlx            t7, 32, t7;                                                     \
+       stw             t7, [dest + off - 0x08];                                        \
+       bcc,pt          %xcc, 28f;                                                      \
+        ldxa           [src + off + 0x38] %asi, t7;                                    \
+       add             sum, 1, sum;                                                    \
+28:
 
-#define EXT(start,end,handler,z)                \
-        .section __ex_table,z##alloc;           \
-        .align  8;                              \
-        .xword   start, 0, end, handler;        \
-        .text;                                  \
-        .align  4
+#define CSUMCOPY_EC_STALIGNED(dest, off, sum, 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;                                                   \
+       bcc,pt          %xcc, 32f;                                                      \
+        stx            t1, [dest + 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;                                                   \
+       bcc,pt          %xcc, 34f;                                                      \
+        stx            t3, [dest + 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;                                                   \
+       bcc,pt          %xcc, 36f;                                                      \
+        stx            t5, [dest + 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;                                                   \
+       bcc,pt          %xcc, 38f;                                                      \
+        stx            t7, [dest + off + 0x38];                                        \
+       add             sum, 1, sum;                                                    \
+38:
 
-       /* This aligned version executes typically in 8.5 superscalar cycles, this
-        * is the best I can do.  I say 8.5 because the final add will pair with
-        * the next ldd in the main unrolled loop.  Thus the pipe is always full.
-        * If you change these macros (including order of instructions),
-        * please check the fixup code below as well.
-        */
-#define CSUMCOPY_BIGCHUNK_ALIGNED(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7)  \
-       ldda    [src + off + 0x00] %asi, t0;                                            \
-       ldda    [src + off + 0x08] %asi, t2;                                            \
-       addccc  t0, sum, sum;                                                           \
-       ldda    [src + off + 0x10] %asi, t4;                                            \
-       addccc  t1, sum, sum;                                                           \
-       ldda    [src + off + 0x18] %asi, t6;                                            \
-       addccc  t2, sum, sum;                                                           \
-       std     t0, [dst + off + 0x00];                                                 \
-       addccc  t3, sum, sum;                                                           \
-       std     t2, [dst + off + 0x08];                                                 \
-       addccc  t4, sum, sum;                                                           \
-       std     t4, [dst + off + 0x10];                                                 \
-       addccc  t5, sum, sum;                                                           \
-       std     t6, [dst + off + 0x18];                                                 \
-       addccc  t6, sum, sum;                                                           \
-       addccc  t7, sum, sum;
+#define CSUMCOPY_EC_STUNALIGN(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)          \
+       stw             t0, [dest + 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;                                                   \
+       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;                                                   \
+       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;                                                   \
+       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;                                                   \
+       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;                                                   \
+       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;                                                   \
+       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;                                                   \
+       srlx            t7, 32, t7;                                                     \
+       bcc,pt          %xcc, 48f;                                                      \
+        stw            t7, [dest + off + 0x38];                                        \
+       add             sum, 1, sum;                                                    \
+48:
 
-       /* 12 superscalar cycles seems to be the limit for this case,
-        * because of this we thus do all the ldd's together to get
-        * Viking MXCC into streaming mode.  Ho hum...
-        */
-#define CSUMCOPY_BIGCHUNK(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7)  \
-       ldda    [src + off + 0x00] %asi, t0;                                    \
-       ldda    [src + off + 0x08] %asi, t2;                                    \
-       ldda    [src + off + 0x10] %asi, t4;                                    \
-       ldda    [src + off + 0x18] %asi, t6;                                    \
-       st      t0, [dst + off + 0x00];                                         \
-       addccc  t0, sum, sum;                                                   \
-       st      t1, [dst + off + 0x04];                                         \
-       addccc  t1, sum, sum;                                                   \
-       st      t2, [dst + off + 0x08];                                         \
-       addccc  t2, sum, sum;                                                   \
-       st      t3, [dst + off + 0x0c];                                         \
-       addccc  t3, sum, sum;                                                   \
-       st      t4, [dst + off + 0x10];                                         \
-       addccc  t4, sum, sum;                                                   \
-       st      t5, [dst + off + 0x14];                                         \
-       addccc  t5, sum, sum;                                                   \
-       st      t6, [dst + off + 0x18];                                         \
-       addccc  t6, sum, sum;                                                   \
-       st      t7, [dst + off + 0x1c];                                         \
-       addccc  t7, sum, sum;
+#define CSUMCOPY_LASTCHUNK(src, dst, sum, 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];                                         \
+       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];                                         \
+       srlx            t1, 32, t1;                                                     \
+       bcc,pt          %xcc, 52f;                                                      \
+        stw            t1, [dst - off - 0x00];                                         \
+       add             sum, 1, sum;                                                    \
+52:
 
-       /* Yuck, 6 superscalar cycles... */
-#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1, t2, t3) \
-       ldda    [src - off - 0x08] %asi, t0;                    \
-       ldda    [src - off - 0x00] %asi, t2;                    \
-       addccc  t0, sum, sum;                                   \
-       st      t0, [dst - off - 0x08];                         \
-       addccc  t1, sum, sum;                                   \
-       st      t1, [dst - off - 0x04];                         \
-       addccc  t2, sum, sum;                                   \
-       st      t2, [dst - off - 0x00];                         \
-       addccc  t3, sum, sum;                                   \
-       st      t3, [dst - off + 0x04];
-
-       /* Handle the end cruft code out of band for better cache patterns. */
 cc_end_cruft:
-       andcc   %o3, 8, %g0             ! begin checks for that code
-       be,pn   %icc, 1f
-        and    %o3, 4, %g5
-       EX(ldda [%o0 + 0x00] %asi, %g2, and %o3, 0xf,#)
-       add     %o1, 8, %o1
-       addcc   %g2, %g7, %g7
-       add     %o0, 8, %o0
-       addccc  %g3, %g7, %g7
-       EX2(st  %g2, [%o1 - 0x08],#)
-       addc    %g0, %g7, %g7
-       EX2(st  %g3, [%o1 - 0x04],#)
-1:     brz,pt  %g5, 1f
-        andcc  %o3, 3, %o3
-       EX(lda  [%o0 + 0x00] %asi, %g2, add %o3, 4,#)
-       add     %o1, 4, %o1
-       addcc   %g2, %g7, %g7
-       EX2(st  %g2, [%o1 - 0x04],#)
-       addc    %g0, %g7, %g7
-       add     %o0, 4, %o0
-1:     brz,pn  %o3, 1f
-        addcc  %o3, -1, %g0
-       bne,pn  %icc, 2f
-        subcc  %o3, 2, %o3
-       ba,pt   %xcc, 4f
-        clr    %o4
-2:     EX(lduha [%o0 + 0x00] %asi, %o4, add %o3, 2,#)
-       add     %o0, 2, %o0
-       EX2(sth %o4, [%o1 + 0x00],#)
-       be,pn   %icc, 6f
-        add    %o1, 2, %o1
-       sll     %o4, 16, %o4
-4:     EX(lduba [%o0 + 0x00] %asi, %o5, add %g0, 1,#)
-       EX2(stb %o5, [%o1 + 0x00],#)
-       sll     %o5, 8, %o5
-       or      %o5, %o4, %o4
-6:     addcc   %o4, %g7, %g7
-1:     sllx    %g4, 32, %g4
-       addc    %g0, %g7, %o0
-       retl
-        srl    %o0, 0, %o0
+       andcc           %o3, 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
+       srlx            %g2, 32, %g2            ! IEU0
+       bcc,pt          %xcc, 1f                ! CTI   Group
+        stw            %g2, [%o1 - 0x08]       ! Store
+       add             %g7, 1, %g7             ! 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
+       sllx            %g2, 32, %g2            ! IEU0
+1:     andcc           %o3, 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
+       sll             %o4, 16, %o4            ! IEU0
+1:     andcc           %o3, 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
+       sll             %o5, 8, %o5             ! IEU0
+1:     or              %g2, %o4, %o4           ! IEU1
+       or              %o5, %o4, %o4           ! IEU0  Group
+       addcc           %o4, %g7, %g7           ! IEU1
+       bcc,pt          %xcc, ccfold            ! CTI
+        sethi          %uhi(PAGE_OFFSET), %g4  ! IEU0  Group
+       b,pt            %xcc, ccfold            ! CTI
+        add            %g7, 1, %g7             ! IEU1
 
-       /* Sun, you just can't beat me, you just can't.  Stop trying,
-        * give up.  I'm serious, I am going to kick the living shit
-        * out of you, game over, lights out.
-        */
-       .align  8
-       .globl  __csum_partial_copy_sparc_generic
-__csum_partial_copy_sparc_generic:
-                                       /* %o0=src, %o1=dest, %g1=len, %g7=sum */
-       srl     %g7, 0, %g7             ! you neve know...
-       xor     %o0, %o1, %o4           ! get changing bits
-       srl     %g1, 0, %g1             ! doof scheiss
-       andcc   %o4, 3, %g0             ! check for mismatched alignment
-       bne,pn  %icc, ccslow            ! better this than unaligned/fixups
-        andcc  %o0, 7, %g0             ! need to align things?
-       be,pt   %icc, cc_dword_aligned  ! yes, we check for short lengths there
-        andn   %g1, 0x7f, %g2          ! can we use unrolled loop?
-       cmp     %g1, 6
-       bl,a,pn %icc, ccte
-        andcc  %g1, 0xf, %o3
-       andcc   %o0, 0x1, %g0
-       bne,pn  %icc, ccslow
-        andcc  %o0, 0x2, %g0
-       be,pn   %icc, 1f
-        andcc  %o0, 0x4, %g0
-       EX(lduha [%o0 + 0x00] %asi, %g4, add %g1, 0,#)
-       sub     %g1, 2, %g1
-       EX2(sth %g4, [%o1 + 0x00],#)
-       add     %o0, 2, %o0
-       sll     %g4, 16, %g4
-       addcc   %g4, %g7, %g7
-       add     %o1, 2, %o1
-       srl     %g7, 16, %g3
-       addc    %g0, %g3, %g4
-       sll     %g7, 16, %g7
-       sll     %g4, 16, %g3
-       srl     %g7, 16, %g7
-       andcc   %o0, 0x4, %g0
-       or      %g3, %g7, %g7
-1:     be,pt   %icc, 3f
-        andn   %g1, 0x7f, %g2
-       EX(lda  [%o0 + 0x00] %asi, %g4, add %g1, 0,#)
-       sub     %g1, 4, %g1
-       EX2(st  %g4, [%o1 + 0x00],#)
-       add     %o0, 4, %o0
-       addcc   %g4, %g7, %g7
-       add     %o1, 4, %o1
-       andn    %g1, 0x7f, %g2
-       addc    %g0, %g7, %g7
+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
+       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
+       sll             %g4, 16, %g3            ! IEU0  Group + 1 bubble
+       addcc           %g3, %g7, %g7           ! IEU1
+       bcc,pt          %xcc, 0f                ! CTI
+        srl            %g7, 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
+       sll             %g3, 16, %g3            ! IEU0  Group
+       srl             %g7, 16, %g7            ! IEU0  Group
+       or              %g3, %g7, %g7           ! 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
+       bcc,pt          %xcc, cc_dword_aligned  ! CTI
+        andn           %g1, 0xff, %g2          ! IEU0  Group
+       b,pt            %xcc, cc_dword_aligned  ! CTI   4 clocks (mispredict)
+        add            %g7, 1, %g7             ! 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
+       andcc           %o4, 3, %g0             ! IEU1  Group
+       srl             %g1, 0, %g1             ! IEU0
+       bne,pn          %icc, ccslow            ! CTI
+        andcc          %o0, 7, %g0             ! IEU1  Group
+       be,pt           %icc, cc_dword_aligned  ! CTI
+        andn           %g1, 0xff, %g2          ! IEU0
+       b,pt            %xcc, cc_fixit          ! CTI   Group
+        cmp            %g1, 6                  ! IEU1
 cc_dword_aligned:
-3:     brz,pn  %g2, 3f                 ! nope, less than one loop remains
-        andcc  %o1, 4, %g0             ! dest aligned on 4 or 8 byte boundry?
-       be,pn   %icc, ccdbl + 4         ! 8 byte aligned, kick ass
-5:     CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-10:    EXT(5b, 10b, 20f,#)             ! note for exception handling
-       sub     %g1, 128, %g1           ! detract from length
-       addc    %g0, %g7, %g7           ! add in last carry bit
-       andncc  %g1, 0x7f, %g0          ! more to csum?
-       add     %o0, 128, %o0           ! advance src ptr
-       bne,pt  %icc, 5b                ! we did not go negative, continue looping
-        add    %o1, 128, %o1           ! advance dest ptr
-3:     andcc   %g1, 0x70, %o2          ! can use table?
-ccmerge:be,pn  %icc, ccte              ! nope, go and check for end cruft
-        andcc  %g1, 0xf, %o3           ! get low bits of length (clears carry btw)
-       srl     %o2, 1, %o4             ! begin negative offset computation
-13:    rd      %pc, %o5                ! set up table ptr end
-       add     %o0, %o2, %o0           ! advance src ptr
-       sub     %o5, %o4, %o5           ! continue table calculation
-       sll     %o2, 1, %g2             ! constant multiplies are fun...
-       sub     %o5, %g2, %o5           ! some more adjustments
-       jmpl    %o5 + (12f-13b), %g0    ! jump into it, duff style, wheee...
-        add    %o1, %o2, %o1           ! advance dest ptr (carry is clear btw)
-cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3,%g4,%g5)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x48,%g2,%g3,%g4,%g5)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x38,%g2,%g3,%g4,%g5)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3,%g4,%g5)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3,%g4,%g5)
-       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5)
-12:    EXT(cctbl, 12b, 22f,#)          ! note for exception table handling
-       addc    %g0, %g7, %g7
-       andcc   %g1, 0xf, %o3           ! check for low bits set
-ccte:  bne,pn  %icc, cc_end_cruft      ! something left, handle it out of band
-        sethi  %uhi(KERNBASE), %g4     ! restore gfp
-       mov     %g7, %o0                ! give em the computed checksum
-       sllx    %g4, 32, %g4            ! finish gfp restoration
-       retl                            ! return
-        srl    %o0, 0, %o0
-ccdbl: CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-       CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-11:    EXT(ccdbl, 11b, 21f,#)          ! note for exception table handling
-       sub     %g1, 128, %g1           ! detract from length
-       addc    %g0, %g7, %g7           ! add in last carry bit
-       andncc  %g1, 0x7f, %g0          ! more to csum?
-       add     %o0, 128, %o0           ! advance src ptr
-       bne,pt  %icc, ccdbl             ! we did not go negative, continue looping
-        add    %o1, 128, %o1           ! advance dest ptr
-       ba,pt   %xcc, ccmerge           ! finish it off, above
-        andcc  %g1, 0x70, %o2          ! can use table? (clears carry btw)
+       brz,pn          %g2, 3f                 ! CTI   Group
+        andcc          %o1, 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)
+10:
+       sub             %g1, 256, %g1           ! IEU0  Group
+       add             %o0, 256, %o0           ! IEU1
+       andncc          %g1, 0xff, %g0          ! IEU1  Group
+       bne,pt          %icc, 5b                ! CTI
+        add            %o1, 256, %o1           ! IEU0
+3:     andcc           %g1, 0xf0, %o2          ! 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)
+12:
+       andcc           %g1, 0xf, %o3           ! 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)
+       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)
+11:
+       sub             %g1, 256, %g1           ! IEU0  Group
+       add             %o0, 256, %o0           ! IEU1
+       andncc          %g1, 0xff, %g0          ! IEU1  Group   
+       bne,pt          %icc, ccdbl             ! CTI
+        add            %o1, 256, %o1           ! IEU0
+       b,pt            %xcc, ccmerge           ! CTI   Group
+        andcc          %g1, 0xf0, %o2          ! IEU1
 
 ccslow:        mov     0, %g5
        brlez,pn %g1, 4f
@@ -401,9 +627,9 @@ ccslow:     mov     0, %g5
        be,a,pt %icc, 1f
         srl    %g1, 1, %o3             
        sub     %g1, 1, %g1     
-       EX(lduba [%o0] %asi, %g5, add %g1, 1,#)
+       lduba [%o0] %asi, %g5
        add     %o0, 1, %o0     
-       EX2(stb %g5, [%o1],#)
+       stb     %g5, [%o1]
        srl     %g1, 1, %o3
        add     %o1, 1, %o1
 1:     brz,a,pn %o3, 3f
@@ -411,33 +637,33 @@ ccslow:   mov     0, %g5
        andcc   %o0, 2, %g0     
        be,a,pt %icc, 1f
         srl    %o3, 1, %o3
-       EX(lduha [%o0] %asi, %o4, add %g1, 0,#)
+       lduha [%o0] %asi, %o4
        sub     %g1, 2, %g1     
        srl     %o4, 8, %g2
        sub     %o3, 1, %o3     
-       EX2(stb %g2, [%o1],#)
+       stb     %g2, [%o1]
        add     %o4, %g5, %g5
-       EX2(stb %o4, [%o1 + 1],#)
+       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
-       EX3(lda [%o0] %asi, %o4,#)
+       lda     [%o0] %asi, %o4
 5:     srl     %o4, 24, %g2
        srl     %o4, 16, %g3
-       EX2(stb %g2, [%o1],#)
+       stb     %g2, [%o1]
        srl     %o4, 8, %g2
-       EX2(stb %g3, [%o1 + 1],#)
+       stb     %g3, [%o1 + 1]
        add     %o0, 4, %o0
-       EX2(stb %g2, [%o1 + 2],#)
+       stb     %g2, [%o1 + 2]
        addcc   %o4, %g5, %g5
-       EX2(stb %o4, [%o1 + 3],#)
+       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
        bne,a,pt %icc, 5b
-        EX3(lda [%o0] %asi, %o4,#)
+        lda [%o0] %asi, %o4
        sll     %g5, 16, %g2
        srl     %g5, 16, %g5
        srl     %g2, 16, %g2
@@ -445,19 +671,19 @@ ccslow:   mov     0, %g5
        add     %g2, %g5, %g5 
 2:     be,a,pt %icc, 3f                
         andcc  %g1, 1, %g0
-       EX(lduha [%o0] %asi, %o4, and %g1, 3,#)
+       lduha [%o0] %asi, %o4
        andcc   %g1, 1, %g0
        srl     %o4, 8, %g2
        add     %o0, 2, %o0     
-       EX2(stb %g2, [%o1],#)
+       stb     %g2, [%o1]
        add     %g5, %o4, %g5
-       EX2(stb %o4, [%o1 + 1],#)
+       stb     %o4, [%o1 + 1]
        add     %o1, 2, %o1
 3:     be,a,pt %icc, 1f                
         sll    %g5, 16, %o4
-       EX(lduba [%o0] %asi, %g2, add %g0, 1,#)
+       lduba [%o0] %asi, %g2
        sll     %g2, 8, %o4     
-       EX2(stb %g2, [%o1],#)
+       stb     %g2, [%o1]
        add     %g5, %o4, %g5
        sll     %g5, 16, %o4
 1:     addcc   %o4, %g5, %g5
@@ -474,103 +700,3 @@ ccslow:   mov     0, %g5
        retl    
         srl    %o0, 0, %o0
 __csum_partial_copy_end:
-
-        .section .fixup,#alloc,#execinstr
-        .align  4
-/* We do these strange calculations for the csum_*_from_user case only, ie.
- * we only bother with faults on loads... */
-
-/* o2 = ((g2%20)&3)*8
- * o3 = g1 - (g2/20)*32 - o2 */
-20:
-       cmp     %g2, 20
-       blu,a,pn %icc, 1f
-        and    %g2, 3, %o2
-       sub     %g1, 32, %g1
-       ba,pt   %xcc, 20b
-        sub    %g2, 20, %g2
-1:
-       sll     %o2, 3, %o2
-       ba,pt   %xcc, 31f
-        sub    %g1, %o2, %o3
-
-/* o2 = (!(g2 & 15) ? 0 : (((g2 & 15) + 1) & ~1)*8)
- * o3 = g1 - (g2/16)*32 - o2 */
-21:
-       andcc   %g2, 15, %o3
-       srl     %g2, 4, %g2
-       be,a,pn %icc, 1f
-        clr    %o2
-       add     %o3, 1, %o3
-       and     %o3, 14, %o3
-       sll     %o3, 3, %o2
-1:
-       sll     %g2, 5, %g2
-       sub     %g1, %g2, %o3
-       ba,pt   %xcc, 31f
-        sub    %o3, %o2, %o3
-
-/* o0 += (g2/10)*16 - 0x70
- * 01 += (g2/10)*16 - 0x70
- * o2 = (g2 % 10) ? 8 : 0
- * o3 += 0x70 - (g2/10)*16 - o2 */
-22:
-       cmp     %g2, 10
-       blu,a,pt %xcc, 1f
-        sub    %o0, 0x70, %o0
-       add     %o0, 16, %o0
-       add     %o1, 16, %o1
-       sub     %o3, 16, %o3
-       ba,pt   %xcc, 22b
-        sub    %g2, 10, %g2
-1:
-       sub     %o1, 0x70, %o1
-       add     %o3, 0x70, %o3
-       clr     %o2
-       movrnz  %g2, 8, %o2
-       ba,pt   %xcc, 31f
-        sub    %o3, %o2, %o3
-96:
-       and     %g1, 3, %g1
-       sll     %o3, 2, %o3
-       add     %g1, %o3, %o3
-30:
-/* %o1 is dst
- * %o3 is # bytes to zero out
- * %o4 is faulting address
- * %o5 is %pc where fault occured */
-       clr     %o2
-31:
-/* %o0 is src
- * %o1 is dst
- * %o2 is # of bytes to copy from src to dst
- * %o3 is # bytes to zero out
- * %o4 is faulting address
- * %o5 is %pc where fault occured */
-       save    %sp, -136, %sp
-        mov     %i5, %o0
-        mov     %i7, %o1
-        mov    %i4, %o2
-        call    lookup_fault
-        mov    %g7, %i4
-       cmp     %o0, 2
-       bne,pn  %icc, 1f
-        add    %g0, -EFAULT, %i5
-       brz,pn  %i2, 2f
-        mov    %i0, %o1
-       mov     %i1, %o0
-       call    __copy_from_user
-        mov    %i2, %o2
-       brnz,a,pn %o0, 2f
-        add    %i3, %i2, %i3
-       add     %i1, %i2, %i1
-2:
-       mov     %i1, %o0
-        wr     %g0, ASI_S, %asi
-        call   __bzero_noasi
-        mov    %i3, %o1
-1:
-       ldx     [%sp + STACK_BIAS + 264], %o2           ! struct_ptr of parent
-       st      %i5, [%o2]
-       ret
-        restore
diff --git a/arch/sparc64/lib/copy_from_user.S b/arch/sparc64/lib/copy_from_user.S
deleted file mode 100644 (file)
index 196435a..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/* copy_user.S: Sparc optimized copy_from_user code.
- *
- *  Copyright(C) 1995 Linus Torvalds
- *  Copyright(C) 1996 David S. Miller
- *  Copyright(C) 1996 Eddie C. Dost
- *  Copyright(C) 1996,1997 Jakub Jelinek
- *
- * derived from:
- *     e-mail between David and Eddie.
- *
- * Returns 0 if successful, otherwise count of bytes not copied yet
- *
- * FIXME: This code should be optimized for sparc64... -jj
- */
-
-#include <asm/ptrace.h>
-#include <asm/asi.h>
-#include <asm/head.h>
-
-#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
-
-#define EX(x,y,a,b,z)                          \
-98:    x,y;                                    \
-       .section .fixup,z##alloc,z##execinstr;  \
-       .align  4;                              \
-99:    PRE_RETL                                \
-       retl;                                   \
-        a, b, %o0;                             \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  98b, 99b;                       \
-       .text;                                  \
-       .align  4
-
-#define EX2(x,y,c,d,e,a,b,z)                   \
-98:    x,y;                                    \
-       .section .fixup,z##alloc,z##execinstr;  \
-       .align  4;                              \
-99:    c, d, e;                                \
-       PRE_RETL                                \
-       retl;                                   \
-        a, b, %o0;                             \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  98b, 99b;                       \
-       .text;                                  \
-       .align  4
-
-#define EXO2(x,y,z)                            \
-98:    x,##y;                                  \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  98b, 97f;                       \
-       .text;                                  \
-       .align  4
-
-#define EXT(start,end,handler,z)               \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  start, 0, end, handler;         \
-       .text;                                  \
-       .align  4
-
-/* Please do not change following macros unless you change logic used
- * in .fixup at the end of this file as well
- */
-
-/* Both these macros have to start with exactly the same insn */
-#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-       ldda    [%src + offset + 0x00] %asi, %t0; \
-       ldda    [%src + offset + 0x08] %asi, %t2; \
-       ldda    [%src + offset + 0x10] %asi, %t4; \
-       ldda    [%src + offset + 0x18] %asi, %t6; \
-       st      %t0, [%dst + offset + 0x00]; \
-       st      %t1, [%dst + offset + 0x04]; \
-       st      %t2, [%dst + offset + 0x08]; \
-       st      %t3, [%dst + offset + 0x0c]; \
-       st      %t4, [%dst + offset + 0x10]; \
-       st      %t5, [%dst + offset + 0x14]; \
-       st      %t6, [%dst + offset + 0x18]; \
-       st      %t7, [%dst + offset + 0x1c];
-
-#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-       ldda    [%src + offset + 0x00] %asi, %t0; \
-       ldda    [%src + offset + 0x08] %asi, %t2; \
-       ldda    [%src + offset + 0x10] %asi, %t4; \
-       ldda    [%src + offset + 0x18] %asi, %t6; \
-       std     %t0, [%dst + offset + 0x00]; \
-       std     %t2, [%dst + offset + 0x08]; \
-       std     %t4, [%dst + offset + 0x10]; \
-       std     %t6, [%dst + offset + 0x18];
-
-#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
-       ldda    [%src - offset - 0x10] %asi, %t0; \
-       ldda    [%src - offset - 0x08] %asi, %t2; \
-       st      %t0, [%dst - offset - 0x10]; \
-       st      %t1, [%dst - offset - 0x0c]; \
-       st      %t2, [%dst - offset - 0x08]; \
-       st      %t3, [%dst - offset - 0x04];
-
-#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
-       lduha   [%src + offset + 0x00] %asi, %t0; \
-       lduha   [%src + offset + 0x02] %asi, %t1; \
-       lduha   [%src + offset + 0x04] %asi, %t2; \
-       lduha   [%src + offset + 0x06] %asi, %t3; \
-       sth     %t0, [%dst + offset + 0x00]; \
-       sth     %t1, [%dst + offset + 0x02]; \
-       sth     %t2, [%dst + offset + 0x04]; \
-       sth     %t3, [%dst + offset + 0x06];
-
-#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
-       lduba   [%src - offset - 0x02] %asi, %t0; \
-       lduba   [%src - offset - 0x01] %asi, %t1; \
-       stb     %t0, [%dst - offset - 0x02]; \
-       stb     %t1, [%dst - offset - 0x01];
-
-       .text
-       .align  4
-
-       .globl  __copy_from_user
-dword_align:
-       andcc   %o1, 1, %g0
-       be      4f
-        andcc  %o1, 2, %g0
-
-       EXO2(lduba [%o1] %asi, %g2,#)
-       add     %o1, 1, %o1
-       stb     %g2, [%o0]
-       sub     %o2, 1, %o2
-       bne     3f
-        add    %o0, 1, %o0
-
-       EXO2(lduha [%o1] %asi, %g2,#)
-       add     %o1, 2, %o1
-       sth     %g2, [%o0]
-       sub     %o2, 2, %o2
-       ba,pt   %xcc, 3f
-        add    %o0, 2, %o0
-4:
-       EXO2(lduha [%o1] %asi, %g2,#)
-       add     %o1, 2, %o1
-       sth     %g2, [%o0]
-       sub     %o2, 2, %o2
-       ba,pt   %xcc, 3f
-        add    %o0, 2, %o0
-
-__copy_from_user:      /* %o0=dst %o1=src %o2=len */
-       wr      %g0, ASI_S, %asi
-       xor     %o0, %o1, %o4
-1:
-       andcc   %o4, 3, %o5
-2:
-       bne,pn  %icc, cannot_optimize
-        cmp    %o2, 15
-
-       bleu,pn %xcc, short_aligned_end
-        andcc  %o1, 3, %g0
-
-       bne,pn  %icc, dword_align
-3:
-        andcc  %o1, 4, %g0
-
-       be,pt   %icc, 2f
-        mov    %o2, %g1
-
-       EXO2(lda [%o1] %asi, %o4,#)
-       sub     %g1, 4, %g1
-       st      %o4, [%o0]
-       add     %o1, 4, %o1
-       add     %o0, 4, %o0
-2:
-       andcc   %g1, 0xffffffffffffff80, %g7
-       be,pn   %xcc, 3f
-        andcc  %o0, 4, %g0
-
-       be,pn   %icc, ldd_std + 4
-5:
-       MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-80:
-       EXT(5b, 80b, 50f,#)
-       subcc   %g7, 128, %g7
-       add     %o1, 128, %o1
-       bne,pt  %xcc, 5b
-        add    %o0, 128, %o0
-3:
-       andcc   %g1, 0x70, %g7
-       be,pn   %icc, copy_user_table_end
-        andcc  %g1, 8, %g0
-100:
-       rd      %pc, %o5
-       srl     %g7, 1, %o4
-       add     %g7, %o4, %o4
-       add     %o1, %g7, %o1
-       sub     %o5, %o4, %o5
-       jmpl    %o5 + (copy_user_table_end - 100b), %g0
-        add    %o0, %g7, %o0
-
-copy_user_table:
-       MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
-copy_user_table_end:
-       EXT(copy_user_table, copy_user_table_end, 51f,#)
-       be,pt   %icc, copy_user_last7
-        andcc  %g1, 4, %g0
-
-       EX(ldda [%o1] %asi, %g2, and %g1, 0xf,#)
-       add     %o0, 8, %o0
-       add     %o1, 8, %o1
-       st      %g2, [%o0 - 0x08]
-       st      %g3, [%o0 - 0x04]
-copy_user_last7:
-       be,pn   %icc, 1f
-        andcc  %g1, 2, %g0
-
-       EX(lda  [%o1] %asi, %g2, and %g1, 7,#)
-       add     %o1, 4, %o1
-       st      %g2, [%o0]
-       add     %o0, 4, %o0
-1:
-       be,pn   %icc, 1f
-        andcc  %g1, 1, %g0
-
-       EX(lduha [%o1] %asi, %g2, and %g1, 3,#)
-       add     %o1, 2, %o1
-       sth     %g2, [%o0]
-       add     %o0, 2, %o0
-1:
-       be,pn   %icc, 1f
-        nop
-
-       EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
-       stb     %g2, [%o0]
-1:
-       PRE_RETL
-       retl
-        clr    %o0
-
-ldd_std:
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-81:
-       EXT(ldd_std, 81b, 52f,#)
-       subcc   %g7, 128, %g7
-       add     %o1, 128, %o1
-       bne,pt  %xcc, ldd_std
-       add     %o0, 128, %o0
-
-       andcc   %g1, 0x70, %g7
-       be,pn   %icc, copy_user_table_end
-        andcc  %g1, 8, %g0
-101:
-       rd      %pc, %o5
-       srl     %g7, 1, %o4
-       add     %g7, %o4, %o4
-       add     %o1, %g7, %o1
-       sub     %o5, %o4, %o5
-       jmpl    %o5 + (copy_user_table_end - 101b), %g0
-        add    %o0, %g7, %o0
-
-cannot_optimize:
-       bleu    short_end
-        cmp    %o5, 2
-
-       bne     byte_chunk
-        and    %o2, 0xfffffffffffffff0, %o3
-        
-       andcc   %o1, 1, %g0
-       be      10f
-        nop
-
-       EXO2(lduba [%o1] %asi, %g2,#)
-       add     %o1, 1, %o1
-       stb     %g2, [%o0]
-       sub     %o2, 1, %o2
-       andcc   %o2, 0xfffffffffffffff0, %o3
-       be      short_end
-        add    %o0, 1, %o0
-10:
-       MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
-       MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
-82:
-       EXT(10b, 82b, 53f,#)
-       subcc   %o3, 0x10, %o3
-       add     %o1, 0x10, %o1
-       bne     10b
-        add    %o0, 0x10, %o0
-       ba,pt   %xcc, 2f
-        and    %o2, 0xe, %o3
-       
-byte_chunk:
-       MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
-83:
-       EXT(byte_chunk, 83b, 54f,#)
-       subcc   %o3, 0x10, %o3
-       add     %o1, 0x10, %o1
-       bne,pt  %xcc, byte_chunk
-        add    %o0, 0x10, %o0
-
-short_end:
-       and     %o2, 0xe, %o3
-2:
-       rd      %pc, %o5
-       sll     %o3, 3, %o4
-       add     %o0, %o3, %o0
-       sub     %o5, %o4, %o5
-       add     %o1, %o3, %o1
-       jmpl    %o5 + (short_table_end - 2b), %g0
-        andcc  %o2, 1, %g0
-84:
-       MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
-short_table_end:
-       EXT(84b, short_table_end, 55f,#)
-       be      1f
-        nop
-       EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
-       stb     %g2, [%o0]
-1:
-       PRE_RETL
-       retl
-        clr    %o0
-
-short_aligned_end:
-       bne     short_end
-        andcc  %o2, 8, %g0
-
-       be      1f
-        andcc  %o2, 4, %g0
-
-       EXO2(lda [%o1 + 0x00] %asi, %g2,#)
-       EX(lda  [%o1 + 0x04] %asi, %g3, sub %o2, 4,#)
-       add     %o1, 8, %o1
-       st      %g2, [%o0 + 0x00]
-       st      %g3, [%o0 + 0x04]
-       add     %o0, 8, %o0
-1:
-       ba,pt   %xcc, copy_user_last7
-        mov    %o2, %g1
-
-       .section .fixup,#alloc,#execinstr
-       .align  4
-97:
-       PRE_RETL
-       retl
-        mov    %o2, %o0
-/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
-50:
-/* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK
- * happens. This is derived from the amount ldd reads, st stores, etc.
- * x = g2 % 12;
- * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4)
- */
-       cmp     %g2, 12
-       bcs     1f
-        cmp    %g2, 24
-       bcs     2f
-        cmp    %g2, 36
-       bcs     3f
-        nop
-       sub     %g2, 12, %g2
-       sub     %g7, 32, %g7
-3:
-       sub     %g2, 12, %g2
-       sub     %g7, 32, %g7
-2:
-       sub     %g2, 12, %g2
-       sub     %g7, 32, %g7
-1:
-       cmp     %g2, 4
-       bcs,a   1f
-        sll    %g2, 3, %g2
-       sub     %g2, 4, %g2
-       sll     %g2, 2, %g2
-1:
-       and     %g1, 0x7f, %o0
-       add     %o0, %g7, %o0
-       PRE_RETL
-       retl
-        sub    %o0, %g2, %o0
-51:
-/* i = 41 - g2; j = i % 6;
- * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8;        
- */
-       neg     %g2
-       and     %g1, 0xf, %g1
-       add     %g2, 41, %g2
-1:
-       cmp     %g2, 6
-       bcs,a   2f
-        cmp    %g2, 4
-       add     %g1, 16, %g1
-       b       1b
-        sub    %g2, 6, %g2
-2:
-       bcs,a   3f
-        inc    %g2
-       sub     %g2, 3, %g2
-       b       2f
-        sll    %g2, 3, %g2
-3:
-       sll     %g2, 2, %g2
-2:
-       PRE_RETL
-       retl
-        add    %g1, %g2, %o0
-52:
-/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */
-       and     %g2, 0xfffffffffffffff8, %g4
-       and     %g2, 3, %g2
-       sll     %g4, 2, %g4
-       sll     %g2, 3, %g2
-       add     %g2, %g4, %g2
-       b,a     1b
-53:
-/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */
-       and     %g2, 3, %g4
-       and     %g2, 0xfffffffffffffff8, %g2
-       sll     %g4, 1, %g4
-       add     %g2, %g4, %g2
-       and     %o2, 0xf, %o0
-       add     %o0, %o3, %o0
-       PRE_RETL
-       retl
-        sub    %o0, %g2, %o0
-54:
-/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */
-       srl     %g2, 2, %o4
-       and     %g2, 1, %o1
-       sll     %o4, 1, %o4
-       and     %o2, 0xf, %o2
-       sub     %o3, %o1, %o3
-       sub     %o2, %o4, %o2
-       PRE_RETL
-       retl
-        add    %o2, %o3, %o0
-55:
-/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */
-       neg     %g2
-       and     %o2, 1, %o2
-       add     %g2, 27, %g2
-       srl     %g2, 2, %o1
-       and     %g2, 1, %g2
-       sll     %o1, 1, %o1
-       add     %o2, %g2, %o0
-       PRE_RETL
-       retl
-        add    %o0, %o1, %o0
diff --git a/arch/sparc64/lib/copy_to_user.S b/arch/sparc64/lib/copy_to_user.S
deleted file mode 100644 (file)
index cc6db14..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/* copy_user.S: Sparc optimized copy_to_user code.
- *
- *  Copyright(C) 1995 Linus Torvalds
- *  Copyright(C) 1996 David S. Miller
- *  Copyright(C) 1996 Eddie C. Dost
- *  Copyright(C) 1996,1997 Jakub Jelinek
- *
- * derived from:
- *     e-mail between David and Eddie.
- *
- * Returns 0 if successful, otherwise count of bytes not copied yet
- *
- * FIXME: This code should be optimized for sparc64... -jj
- */
-
-#include <asm/ptrace.h>
-#include <asm/head.h>
-#include <asm/asi.h>
-
-#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
-
-#define EX(x,y,a,b,z)                          \
-98:    x,y;                                    \
-       .section .fixup,z##alloc,z##execinstr;  \
-       .align  4;                              \
-99:    PRE_RETL                                \
-       retl;                                   \
-        a, b, %o0;                             \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  98b, 99b;                       \
-       .text;                                  \
-       .align  4
-
-#define EX2(x,y,c,d,e,a,b,z)                   \
-98:    x,y;                                    \
-       .section .fixup,z##alloc,z##execinstr;  \
-       .align  4;                              \
-99:    c, d, e;                                \
-       PRE_RETL                                \
-       retl;                                   \
-        a, b, %o0;                             \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  98b, 99b;                       \
-       .text;                                  \
-       .align  4
-
-#define EXO2(x,y,z)                            \
-98:    x,##y;                                  \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  98b, 97f;                       \
-       .text;                                  \
-       .align  4
-
-#define EXT(start,end,handler,z)               \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  start, 0, end, handler;         \
-       .text;                                  \
-       .align  4
-
-/* Please do not change following macros unless you change logic used
- * in .fixup at the end of this file as well
- */
-
-/* Both these macros have to start with exactly the same insn */
-#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-       ldd     [%src + offset + 0x00], %t0; \
-       ldd     [%src + offset + 0x08], %t2; \
-       ldd     [%src + offset + 0x10], %t4; \
-       ldd     [%src + offset + 0x18], %t6; \
-       sta     %t0, [%dst + offset + 0x00] %asi; \
-       sta     %t1, [%dst + offset + 0x04] %asi; \
-       sta     %t2, [%dst + offset + 0x08] %asi; \
-       sta     %t3, [%dst + offset + 0x0c] %asi; \
-       sta     %t4, [%dst + offset + 0x10] %asi; \
-       sta     %t5, [%dst + offset + 0x14] %asi; \
-       sta     %t6, [%dst + offset + 0x18] %asi; \
-       sta     %t7, [%dst + offset + 0x1c] %asi;
-
-#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-       ldd     [%src + offset + 0x00], %t0; \
-       ldd     [%src + offset + 0x08], %t2; \
-       ldd     [%src + offset + 0x10], %t4; \
-       ldd     [%src + offset + 0x18], %t6; \
-       stda    %t0, [%dst + offset + 0x00] %asi; \
-       stda    %t2, [%dst + offset + 0x08] %asi; \
-       stda    %t4, [%dst + offset + 0x10] %asi; \
-       stda    %t6, [%dst + offset + 0x18] %asi;
-
-#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
-       ldd     [%src - offset - 0x10], %t0; \
-       ldd     [%src - offset - 0x08], %t2; \
-       sta     %t0, [%dst - offset - 0x10] %asi; \
-       sta     %t1, [%dst - offset - 0x0c] %asi; \
-       sta     %t2, [%dst - offset - 0x08] %asi; \
-       sta     %t3, [%dst - offset - 0x04] %asi;
-
-#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
-       lduh    [%src + offset + 0x00], %t0; \
-       lduh    [%src + offset + 0x02], %t1; \
-       lduh    [%src + offset + 0x04], %t2; \
-       lduh    [%src + offset + 0x06], %t3; \
-       stha    %t0, [%dst + offset + 0x00] %asi; \
-       stha    %t1, [%dst + offset + 0x02] %asi; \
-       stha    %t2, [%dst + offset + 0x04] %asi; \
-       stha    %t3, [%dst + offset + 0x06] %asi;
-
-#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
-       ldub    [%src - offset - 0x02], %t0; \
-       ldub    [%src - offset - 0x01], %t1; \
-       stba    %t0, [%dst - offset - 0x02] %asi; \
-       stba    %t1, [%dst - offset - 0x01] %asi;
-
-       .text
-       .align  4
-
-       .globl  __copy_to_user
-dword_align:
-       andcc   %o1, 1, %g0
-       be      4f
-        andcc  %o1, 2, %g0
-
-       ldub    [%o1], %g2
-       add     %o1, 1, %o1
-       EXO2(stba %g2, [%o0] %asi,#)
-       sub     %o2, 1, %o2
-       bne     3f
-        add    %o0, 1, %o0
-
-       lduh    [%o1], %g2
-       add     %o1, 2, %o1
-       EXO2(stha %g2, [%o0] %asi,#)
-       sub     %o2, 2, %o2
-       ba,pt   %xcc, 3f
-        add    %o0, 2, %o0
-4:
-       lduh    [%o1], %g2
-       add     %o1, 2, %o1
-       EXO2(stha %g2, [%o0] %asi,#)
-       sub     %o2, 2, %o2
-       ba,pt   %xcc, 3f
-        add    %o0, 2, %o0
-
-__copy_to_user:        /* %o0=dst %o1=src %o2=len */
-       wr      %g0, ASI_S, %asi
-       xor     %o0, %o1, %o4
-1:
-       andcc   %o4, 3, %o5
-2:
-       bne,pn  %icc, cannot_optimize
-        cmp    %o2, 15
-
-       bleu,pn %xcc, short_aligned_end
-        andcc  %o1, 3, %g0
-
-       bne,pn  %icc, dword_align
-3:
-        andcc  %o1, 4, %g0
-
-       be,pt   %icc, 2f
-        mov    %o2, %g1
-
-       ld      [%o1], %o4
-       sub     %g1, 4, %g1
-       EXO2(sta %o4, [%o0] %asi,#)
-       add     %o1, 4, %o1
-       add     %o0, 4, %o0
-2:
-       andcc   %g1, 0xffffffffffffff80, %g7
-       be,pn   %xcc, 3f
-        andcc  %o0, 4, %g0
-
-       be,pn   %icc, ldd_std + 4
-5:
-       MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-80:
-       EXT(5b, 80b, 50f,#)
-       subcc   %g7, 128, %g7
-       add     %o1, 128, %o1
-       bne,pt  %xcc, 5b
-        add    %o0, 128, %o0
-3:
-       andcc   %g1, 0x70, %g7
-       be,pn   %icc, copy_user_table_end
-        andcc  %g1, 8, %g0
-100:
-       rd      %pc, %o5
-       srl     %g7, 1, %o4
-       add     %g7, %o4, %o4
-       add     %o1, %g7, %o1
-       sub     %o5, %o4, %o5
-       jmpl    %o5 + (copy_user_table_end - 100b), %g0
-        add    %o0, %g7, %o0
-
-copy_user_table:
-       MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
-copy_user_table_end:
-       EXT(copy_user_table, copy_user_table_end, 51f,#)
-       be,pt   %icc, copy_user_last7
-        andcc  %g1, 4, %g0
-
-       ldd     [%o1], %g2
-       add     %o0, 8, %o0
-       add     %o1, 8, %o1
-       EX(sta  %g2, [%o0 - 0x08] %asi, and %g1, 0xf,#)
-       EX2(sta %g3, [%o0 - 0x04] %asi, and %g1, 0xf, %g1, sub %g1, 4,#)
-copy_user_last7:
-       be,pn   %icc, 1f
-        andcc  %g1, 2, %g0
-
-       ld      [%o1], %g2
-       add     %o1, 4, %o1
-       EX(sta  %g2, [%o0] %asi, and %g1, 7,#)
-       add     %o0, 4, %o0
-1:
-       be,pn   %icc, 1f
-        andcc  %g1, 1, %g0
-
-       lduh    [%o1], %g2
-       add     %o1, 2, %o1
-       EX(stha %g2, [%o0] %asi, and %g1, 3,#)
-       add     %o0, 2, %o0
-1:
-       be,pn   %icc, 1f
-        nop
-
-       ldub    [%o1], %g2
-       EX(stba %g2, [%o0] %asi, add %g0, 1,#)
-1:
-       PRE_RETL
-       retl
-        clr    %o0
-
-ldd_std:
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-81:
-       EXT(ldd_std, 81b, 52f,#)
-       subcc   %g7, 128, %g7
-       add     %o1, 128, %o1
-       bne,pt  %xcc, ldd_std
-       add     %o0, 128, %o0
-
-       andcc   %g1, 0x70, %g7
-       be,pn   %icc, copy_user_table_end
-        andcc  %g1, 8, %g0
-101:
-       rd      %pc, %o5
-       srl     %g7, 1, %o4
-       add     %g7, %o4, %o4
-       add     %o1, %g7, %o1
-       sub     %o5, %o4, %o5
-       jmpl    %o5 + (copy_user_table_end - 101b), %g0
-        add    %o0, %g7, %o0
-
-cannot_optimize:
-       bleu    short_end
-        cmp    %o5, 2
-
-       bne     byte_chunk
-        and    %o2, 0xfffffffffffffff0, %o3
-        
-       andcc   %o1, 1, %g0
-       be      10f
-        nop
-
-       ldub [%o1], %g2
-       add     %o1, 1, %o1
-       EXO2(stba %g2, [%o0] %asi,#)
-       sub     %o2, 1, %o2
-       andcc   %o2, 0xfffffffffffffff0, %o3
-       be      short_end
-        add    %o0, 1, %o0
-10:
-       MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
-       MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
-82:
-       EXT(10b, 82b, 53f,#)
-       subcc   %o3, 0x10, %o3
-       add     %o1, 0x10, %o1
-       bne     10b
-        add    %o0, 0x10, %o0
-       ba,pt   %xcc, 2f
-        and    %o2, 0xe, %o3
-       
-byte_chunk:
-       MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
-83:
-       EXT(byte_chunk, 83b, 54f,#)
-       subcc   %o3, 0x10, %o3
-       add     %o1, 0x10, %o1
-       bne,pt  %xcc, byte_chunk
-        add    %o0, 0x10, %o0
-
-short_end:
-       and     %o2, 0xe, %o3
-2:
-       rd      %pc, %o5
-       sll     %o3, 3, %o4
-       add     %o0, %o3, %o0
-       sub     %o5, %o4, %o5
-       add     %o1, %o3, %o1
-       jmpl    %o5 + (short_table_end - 2b), %g0
-        andcc  %o2, 1, %g0
-84:
-       MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
-short_table_end:
-       EXT(84b, short_table_end, 55f,#)
-       be      1f
-        nop
-       ldub    [%o1], %g2
-       EX(stba %g2, [%o0] %asi, add %g0, 1,#)
-1:
-       PRE_RETL
-       retl
-        clr    %o0
-
-short_aligned_end:
-       bne     short_end
-        andcc  %o2, 8, %g0
-
-       be      1f
-        andcc  %o2, 4, %g0
-
-       ld      [%o1 + 0x00], %g2
-       ld      [%o1 + 0x04], %g3
-       add     %o1, 8, %o1
-       EXO2(sta %g2, [%o0 + 0x00] %asi,#)
-       EX(sta  %g3, [%o0 + 0x04] %asi, sub %o2, 4,#)
-       add     %o0, 8, %o0
-1:
-       ba,pt   %xcc, copy_user_last7
-        mov    %o2, %g1
-
-       .section .fixup,#alloc,#execinstr
-       .align  4
-97:
-       PRE_RETL
-       retl
-        mov    %o2, %o0
-/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
-50:
-/* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK
- * happens. This is derived from the amount ldd reads, st stores, etc.
- * x = g2 % 12;
- * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4)
- */
-       cmp     %g2, 12
-       bcs     1f
-        cmp    %g2, 24
-       bcs     2f
-        cmp    %g2, 36
-       bcs     3f
-        nop
-       sub     %g2, 12, %g2
-       sub     %g7, 32, %g7
-3:
-       sub     %g2, 12, %g2
-       sub     %g7, 32, %g7
-2:
-       sub     %g2, 12, %g2
-       sub     %g7, 32, %g7
-1:
-       cmp     %g2, 4
-       bcs,a   1f
-        sll    %g2, 3, %g2
-       sub     %g2, 4, %g2
-       sll     %g2, 2, %g2
-1:
-       and     %g1, 0x7f, %o0
-       add     %o0, %g7, %o0
-       PRE_RETL
-       retl
-        sub    %o0, %g2, %o0
-51:
-/* i = 41 - g2; j = i % 6;
- * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8;        
- */
-       neg     %g2
-       and     %g1, 0xf, %g1
-       add     %g2, 41, %g2
-1:
-       cmp     %g2, 6
-       bcs,a   2f
-        cmp    %g2, 4
-       add     %g1, 16, %g1
-       b       1b
-        sub    %g2, 6, %g2
-2:
-       bcs,a   3f
-        inc    %g2
-       sub     %g2, 3, %g2
-       b       2f
-        sll    %g2, 3, %g2
-3:
-       sll     %g2, 2, %g2
-2:
-       PRE_RETL
-       retl
-        add    %g1, %g2, %o0
-52:
-/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */
-       and     %g2, 0xfffffffffffffff8, %g4
-       and     %g2, 3, %g2
-       sll     %g4, 2, %g4
-       sll     %g2, 3, %g2
-       add     %g2, %g4, %g2
-       b,a     1b
-53:
-/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */
-       and     %g2, 3, %g4
-       and     %g2, 0xfffffffffffffff8, %g2
-       sll     %g4, 1, %g4
-       add     %g2, %g4, %g2
-       and     %o2, 0xf, %o0
-       add     %o0, %o3, %o0
-       PRE_RETL
-       retl
-        sub    %o0, %g2, %o0
-54:
-/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */
-       srl     %g2, 2, %o4
-       and     %g2, 1, %o1
-       sll     %o4, 1, %o4
-       and     %o2, 0xf, %o2
-       sub     %o3, %o1, %o3
-       sub     %o2, %o4, %o2
-       PRE_RETL
-       retl
-        add    %o2, %o3, %o0
-55:
-/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */
-       neg     %g2
-       and     %o2, 1, %o2
-       add     %g2, 27, %g2
-       srl     %g2, 2, %o1
-       and     %g2, 1, %g2
-       sll     %o1, 1, %o1
-       add     %o2, %g2, %o0
-       PRE_RETL
-       retl
-        add    %o0, %o1, %o0
diff --git a/arch/sparc64/lib/memcpy.S b/arch/sparc64/lib/memcpy.S
deleted file mode 100644 (file)
index 86adbc0..0000000
+++ /dev/null
@@ -1,526 +0,0 @@
-/* memcpy.S: Sparc optimized memcpy, bcopy and memmove code
- * Hand optimized from GNU libc's memcpy, bcopy and memmove
- * for UltraSparc
- * Copyright (C) 1991,1996 Free Software Foundation
- * Copyright (C) 1995 Linus Torvalds (Linus.Torvalds@helsinki.fi)
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <asm/asi.h>
-#include <asm/head.h>
-
-#ifdef __KERNEL__
-
-#define FUNC(x)                \
-       .globl  x;              \
-       .type   x,@function;    \
-       .align  4;              \
-x:
-
-#define FASTER_ALIGNED
-
-/* In kernel these functions don't return a value.
- * One should use macros in asm/string.h for that purpose.
- * We return 0, so that bugs are more apparent.
- */
-#define SETUP_RETL
-#define PRE_RETL       sethi   %uhi(KERNBASE), %g4; clr %o0
-#define RETL_INSN      sllx    %g4, 32, %g4
-
-#else
-
-/* libc */
-
-#define FASTER_ALIGNED
-
-#ifdef DEBUG
-#define FUNC(x)                        \
-       .globl  jj##x##1;               \
-       .type   jj##x##1,@function;     \
-       .align  4;                      \
-jj##x##1:
-#else
-#include "DEFS.h"
-#endif
-
-#define SETUP_RETL     mov     %o0, %g6
-#define PRE_RETL
-#define RETL_INSN      mov     %g6, %o0
-
-#endif
-
-#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7)        \
-       ldd     [%src + offset + 0x00], %t0;                                    \
-       ldd     [%src + offset + 0x08], %t2;                                    \
-       ldd     [%src + offset + 0x10], %t4;                                    \
-       ldd     [%src + offset + 0x18], %t6;                                    \
-       stw     %t0, [%dst + offset + 0x00];                                    \
-       stw     %t1, [%dst + offset + 0x04];                                    \
-       stw     %t2, [%dst + offset + 0x08];                                    \
-       stw     %t3, [%dst + offset + 0x0c];                                    \
-       stw     %t4, [%dst + offset + 0x10];                                    \
-       stw     %t5, [%dst + offset + 0x14];                                    \
-       stw     %t6, [%dst + offset + 0x18];                                    \
-       stw     %t7, [%dst + offset + 0x1c];
-
-#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7)   \
-       ldx     [%src + offset + 0x00], %t0;                                    \
-       ldx     [%src + offset + 0x08], %t1;                                    \
-       ldx     [%src + offset + 0x10], %t2;                                    \
-       ldx     [%src + offset + 0x18], %t3;                                    \
-       ldx     [%src + offset + 0x20], %t4;                                    \
-       ldx     [%src + offset + 0x28], %t5;                                    \
-       ldx     [%src + offset + 0x30], %t6;                                    \
-       ldx     [%src + offset + 0x38], %t7;                                    \
-       stx     %t0, [%dst + offset + 0x00];                                    \
-       stx     %t1, [%dst + offset + 0x08];                                    \
-       stx     %t2, [%dst + offset + 0x10];                                    \
-       stx     %t3, [%dst + offset + 0x18];                                    \
-       stx     %t4, [%dst + offset + 0x20];                                    \
-       stx     %t5, [%dst + offset + 0x28];                                    \
-       stx     %t6, [%dst + offset + 0x30];                                    \
-       stx     %t7, [%dst + offset + 0x38];
-
-#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3)       \
-       ldd     [%src - offset - 0x10], %t0;                    \
-       ldd     [%src - offset - 0x08], %t2;                    \
-       stw     %t0, [%dst - offset - 0x10];                    \
-       stw     %t1, [%dst - offset - 0x0c];                    \
-       stw     %t2, [%dst - offset - 0x08];                    \
-       stw     %t3, [%dst - offset - 0x04];
-
-#define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1)          \
-       ldx     [%src - offset - 0x10], %t0;                    \
-       ldx     [%src - offset - 0x08], %t1;                    \
-       stx     %t0, [%dst - offset - 0x10];                    \
-       stx     %t1, [%dst - offset - 0x08];
-
-#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1)              \
-       ldub    [%src - offset - 0x02], %t0;                    \
-       ldub    [%src - offset - 0x01], %t1;                    \
-       stb     %t0, [%dst - offset - 0x02];                    \
-       stb     %t1, [%dst - offset - 0x01];
-
-       .text
-       .align  4
-
-FUNC(bcopy)
-
-       mov             %o0, %o3
-       mov             %o1, %o0
-       mov             %o3, %o1
-       brgez,a,pt      %o2, 1f
-        cmp            %o0, %o1
-
-       retl
-        nop            ! Only bcopy returns here and it retuns void...
-
-#ifdef __KERNEL__
-FUNC(amemmove)
-FUNC(__memmove)
-#endif
-FUNC(memmove)
-
-       cmp             %o0, %o1
-1:
-       SETUP_RETL
-       bleu,pt         %xcc, 9f
-        sub            %o0, %o1, %o4
-
-       add             %o1, %o2, %o3
-       cmp             %o3, %o0
-       bleu,pt         %xcc, 0f
-        andcc          %o4, 3, %o5
-
-       add             %o1, %o2, %o1
-       add             %o0, %o2, %o0
-       sub             %o1, 1, %o1
-       sub             %o0, 1, %o0
-       
-1:
-       ldub            [%o1], %o4
-       subcc           %o2, 1, %o2
-       sub             %o1, 1, %o1
-       stb             %o4, [%o0]
-       bne,pt          %icc, 1b
-        sub            %o0, 1, %o0
-
-       PRE_RETL
-       retl
-        RETL_INSN
-
-#ifdef __KERNEL__
-FUNC(__memcpy)
-#endif
-FUNC(memcpy)   /* %o0=dst %o1=src %o2=len */
-
-       sub             %o0, %o1, %o4
-       SETUP_RETL
-9:
-       andcc           %o4, 3, %o5
-0:
-       bne,pn          %icc, 86f
-        cmp            %o2, 15
-
-       bleu,pn         %xcc, 90f
-        andcc          %o1, 3, %g0
-
-       be,a,pt         %icc, 3f                ! check if we need to align
-        andcc          %o1, 4, %g0
-
-       andcc           %o1, 1, %g0
-       be,pn           %icc, 4f
-        andcc          %o1, 2, %g0
-
-       ldub            [%o1], %g2
-       add             %o1, 1, %o1
-       sub             %o2, 1, %o2
-       stb             %g2, [%o0]
-       bne,pn          %icc, 5f
-        add            %o0, 1, %o0
-4:
-       lduh            [%o1], %g2
-       add             %o1, 2, %o1
-       sub             %o2, 2, %o2
-       sth             %g2, [%o0]
-       add             %o0, 2, %o0
-5:
-       andcc           %o1, 4, %g0
-3:
-       be,pn           %icc, 2f
-        mov            %o2, %g1
-
-       lduw            [%o1], %o4
-       sub             %g1, 4, %g1
-       stw             %o4, [%o0]
-       add             %o1, 4, %o1
-       add             %o0, 4, %o0
-2:
-       andcc           %g1, -128, %g7
-       be,pn           %xcc, 3f
-        andcc          %o0, 4, %g0
-
-       be,a,pn         %icc, 82f + 4
-        ldx            [%o1], %o2
-5:
-       MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-       subcc           %g7, 128, %g7
-       add             %o1, 128, %o1
-       bne,pt          %xcc, 5b
-        add            %o0, 128, %o0
-3:
-       andcc           %g1, 0x70, %g7
-       be,pn           %icc, 80f
-        andcc          %g1, 8, %g0
-79:
-       rd              %pc, %o5
-       srl             %g7, 1, %o4
-       add             %g7, %o4, %o4
-       add             %o1, %g7, %o1
-       sub             %o5, %o4, %o5
-       jmpl            %o5 + %lo(80f-79b), %g0
-        add            %o0, %g7, %o0
-
-       MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
-       MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
-
-80:    /* memcpy_table_end */
-       be,pt           %icc, 81f
-        andcc          %g1, 4, %g0
-
-       ldd             [%o1], %g2
-       add             %o0, 8, %o0
-       stw             %g2, [%o0 - 0x08]
-       add             %o1, 8, %o1
-       stw             %g3, [%o0 - 0x04]
-
-81:    /* memcpy_last7 */
-
-       be,pt           %icc, 1f
-        andcc          %g1, 2, %g0
-
-       lduw            [%o1], %g2
-       add             %o1, 4, %o1
-       stw             %g2, [%o0]
-       add             %o0, 4, %o0
-1:
-       be,pt           %icc, 1f
-        andcc          %g1, 1, %g0
-
-       lduh            [%o1], %g2
-       add             %o1, 2, %o1
-       sth             %g2, [%o0]
-       add             %o0, 2, %o0
-1:
-       be,pt           %icc, 1f
-        nop
-
-       ldub            [%o1], %g2
-       stb             %g2, [%o0]
-1:
-       PRE_RETL
-       retl
-        RETL_INSN
-
-82:    /* ldx_stx */
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
-       MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
-       subcc           %g7, 128, %g7
-       add             %o1, 128, %o1
-       bne,pt          %xcc, 82b
-        add            %o0, 128, %o0
-
-#ifndef FASTER_ALIGNED
-
-       andcc           %g1, 0x70, %g7
-       be,pn           %icc, 80b
-        andcc          %g1, 8, %g0
-83:
-       rd              %pc, %o5
-       srl             %g7, 1, %o4
-       add             %g7, %o4, %o4
-       add             %o1, %g7, %o1
-       sub             %o5, %o4, %o5
-       jmpl            %o5 + %lo(80b - 83b), %g0
-        add            %o0, %g7, %o0
-
-#else /* FASTER_ALIGNED */
-
-       andcc           %g1, 0x70, %g7
-       be,pn           %icc, 84f
-        andcc          %g1, 8, %g0
-83:
-       rd              %pc, %o5
-       add             %o1, %g7, %o1
-       sub             %o5, %g7, %o5
-       jmpl            %o5 + %lo(84f - 83b), %g0
-        add            %o0, %g7, %o0
-
-       MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3)
-       MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3)
-       MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3)
-       MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3)
-       MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3)
-       MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3)
-       MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3)
-
-84:    /* amemcpy_table_end */
-       be,pt           %icc, 85f
-        andcc          %g1, 4, %g0
-
-       ldx             [%o1], %g2
-       add             %o1, 8, %o1
-       stx             %g2, [%o0]
-       add             %o0, 8, %o0
-85:    /* amemcpy_last7 */
-       be,pt           %icc, 1f
-        andcc          %g1, 2, %g0
-
-       lduw            [%o1], %g2
-       add             %o1, 4, %o1
-       stw             %g2, [%o0]
-       add             %o0, 4, %o0
-1:
-       be,pt           %icc, 1f
-        andcc          %g1, 1, %g0
-
-       lduh            [%o1], %g2
-       add             %o1, 2, %o1
-       sth             %g2, [%o0]
-       add             %o0, 2, %o0
-1:
-       be,pt           %icc, 1f
-        nop
-
-       ldub            [%o1], %g2
-       stb             %g2, [%o0]
-1:
-       PRE_RETL
-       retl
-        RETL_INSN
-
-#endif /* FASTER_ALIGNED */
-
-86:    /* non_aligned */
-       cmp             %o2, 15
-       bleu,pn         %xcc, 88f
-
-        andcc          %o0, 3, %g0
-       be,pn           %icc, 61f
-        andcc          %o0, 1, %g0
-       be,pn           %icc, 60f
-        andcc          %o0, 2, %g0
-
-       ldub            [%o1], %g5
-       add             %o1, 1, %o1
-       stb             %g5, [%o0]
-       sub             %o2, 1, %o2
-       bne,pn          %icc, 61f
-        add            %o0, 1, %o0
-60:
-       ldub            [%o1], %g3
-       add             %o1, 2, %o1
-       stb             %g3, [%o0]
-       sub             %o2, 2, %o2
-       ldub            [%o1 - 1], %g3
-       add             %o0, 2, %o0
-       stb             %g3, [%o0 - 1]
-61:
-       and             %o1, 3, %g2
-       and             %o2, 0xc, %g3
-       and             %o1, -4, %o1
-       cmp             %g3, 4
-       sll             %g2, 3, %g4
-       mov             32, %g2
-       be,pn           %icc, 4f
-        sub            %g2, %g4, %g7
-       
-       blu,pn          %icc, 3f
-        cmp            %g3, 0x8
-
-       be,pn           %icc, 2f
-        srl            %o2, 2, %g3
-
-       lduw            [%o1], %o3
-       add             %o0, -8, %o0
-       lduw            [%o1 + 4], %o4
-       ba,pt           %xcc, 8f
-        add            %g3, 1, %g3
-2:
-       lduw            [%o1], %o4
-       add             %o0, -12, %o0
-       lduw            [%o1 + 4], %o5
-       add             %g3, 2, %g3
-       ba,pt           %xcc, 9f
-        add            %o1, -4, %o1
-3:
-       lduw            [%o1], %g1
-       add             %o0, -4, %o0
-       lduw            [%o1 + 4], %o3
-       srl             %o2, 2, %g3
-       ba,pt           %xcc, 7f
-        add            %o1, 4, %o1
-4:
-       lduw            [%o1], %o5
-       cmp             %o2, 7
-       lduw            [%o1 + 4], %g1
-       srl             %o2, 2, %g3
-       bleu,pn         %xcc, 10f
-        add            %o1, 8, %o1
-
-       lduw            [%o1], %o3
-       add             %g3, -1, %g3
-5:
-       sll             %o5, %g4, %g2
-       srl             %g1, %g7, %g5
-       or              %g2, %g5, %g2
-       stw             %g2, [%o0]
-7:
-       lduw            [%o1 + 4], %o4
-       sll             %g1, %g4, %g2
-       srl             %o3, %g7, %g5
-       or              %g2, %g5, %g2
-       stw             %g2, [%o0 + 4]
-8:
-       lduw            [%o1 + 8], %o5
-       sll             %o3, %g4, %g2
-       srl             %o4, %g7, %g5
-       or              %g2, %g5, %g2
-       stw             %g2, [%o0 + 8]
-9:
-       lduw            [%o1 + 12], %g1
-       sll             %o4, %g4, %g2
-       srl             %o5, %g7, %g5
-       addcc           %g3, -4, %g3
-       or              %g2, %g5, %g2
-       add             %o1, 16, %o1
-       stw             %g2, [%o0 + 12]
-       add             %o0, 16, %o0
-       bne,a,pt        %xcc, 5b
-        lduw           [%o1], %o3
-10:
-       sll             %o5, %g4, %g2
-       srl             %g1, %g7, %g5
-       srl             %g7, 3, %g3
-       or              %g2, %g5, %g2
-       sub             %o1, %g3, %o1
-       andcc           %o2, 2, %g0
-       stw             %g2, [%o0]
-       be,pt           %icc, 1f
-        andcc          %o2, 1, %g0
-
-       ldub            [%o1], %g2
-       add             %o1, 2, %o1
-       stb             %g2, [%o0 + 4]
-       add             %o0, 2, %o0
-       ldub            [%o1 - 1], %g2
-       stb             %g2, [%o0 + 3]
-1:
-       be,pt           %icc, 1f
-        nop
-
-       ldub            [%o1], %g2
-       stb             %g2, [%o0 + 4]
-1:
-       PRE_RETL
-       retl
-        RETL_INSN
-
-88:    /* short_end */
-
-       and             %o2, 0xe, %o3
-20:
-       rd              %pc, %o5
-       sll             %o3, 3, %o4
-       add             %o0, %o3, %o0
-       sub             %o5, %o4, %o5
-       add             %o1, %o3, %o1
-       jmpl            %o5 + %lo(89f - 20b), %g0
-        andcc          %o2, 1, %g0
-
-       MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
-
-89:    /* short_table_end */
-
-       be,pt           %icc, 1f
-        nop
-
-       ldub            [%o1], %g2
-       stb             %g2, [%o0]
-1:
-       PRE_RETL
-       retl
-        RETL_INSN
-
-90:    /* short_aligned_end */
-       bne,pn          %xcc, 88b
-        andcc          %o2, 8, %g0
-
-       be,pt           %icc, 1f
-        andcc          %o2, 4, %g0
-
-       lduw            [%o1 + 0x00], %g2
-       lduw            [%o1 + 0x04], %g3
-       add             %o1, 8, %o1
-       stw             %g2, [%o0 + 0x00]
-       stw             %g3, [%o0 + 0x04]
-       add             %o0, 8, %o0
-1:
-       ba,pt           %xcc, 81b
-        mov            %o2, %g1
diff --git a/arch/sparc64/lib/memset.S b/arch/sparc64/lib/memset.S
deleted file mode 100644 (file)
index a327316..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/* linux/arch/sparc64/lib/memset.S: Sparc optimized memset, bzero and clear_user code
- * Copyright (C) 1991,1996 Free Software Foundation
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *
- * Returns 0, if ok, and number of bytes not yet set if exception
- * occurs and we were called as clear_user.
- */
-
-#include <asm/asi.h>
-#include <asm/ptrace.h>
-
-#define EX(x,y,a,b,z)                          \
-98:    x,y;                                    \
-       .section .fixup,z##alloc,z##execinstr;  \
-       .align  4;                              \
-99:    ba,pt   %xcc, 30f;                      \
-        a, b, %o0;                             \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  98b, 99b;                       \
-       .text;                                  \
-       .align  4
-
-#define EXT(start,end,handler,z)               \
-       .section __ex_table,z##alloc;           \
-       .align  8;                              \
-       .xword  start, 0, end, handler;         \
-       .text;                                  \
-       .align  4
-
-/* Please don't change these macros, unless you change the logic
- * in the .fixup section below as well.
- * Store 64 bytes at (BASE + OFFSET) using value SOURCE.
- */
-#define ZERO_BIG_BLOCK(base, offset, source)    \
-       stxa    source, [base + offset + 0x00] %asi; \
-       stxa    source, [base + offset + 0x08] %asi; \
-       stxa    source, [base + offset + 0x10] %asi; \
-       stxa    source, [base + offset + 0x18] %asi; \
-       stxa    source, [base + offset + 0x20] %asi; \
-       stxa    source, [base + offset + 0x28] %asi; \
-       stxa    source, [base + offset + 0x30] %asi; \
-       stxa    source, [base + offset + 0x38] %asi;
-
-#define ZERO_LAST_BLOCKS(base, offset, source) \
-       stxa    source, [base - offset - 0x38] %asi; \
-       stxa    source, [base - offset - 0x30] %asi; \
-       stxa    source, [base - offset - 0x28] %asi; \
-       stxa    source, [base - offset - 0x20] %asi; \
-       stxa    source, [base - offset - 0x18] %asi; \
-       stxa    source, [base - offset - 0x10] %asi; \
-       stxa    source, [base - offset - 0x08] %asi; \
-       stxa    source, [base - offset - 0x00] %asi;
-
-       .text
-       .align 4
-
-       .globl  __bzero, __memset, __bzero_noasi
-       .globl  memset, __memset_start, __memset_end
-__memset_start:
-__memset:
-memset:
-       and     %o1, 0xff, %g3
-       sll     %g3, 8, %g2
-       or      %g3, %g2, %g3
-       sll     %g3, 16, %g2
-       or      %g3, %g2, %g3
-       mov     %o2, %o1
-       wr      %g0, ASI_P, %asi
-       sllx    %g3, 32, %g2
-       ba,pt   %xcc, 1f
-        or     %g3, %g2, %g3
-__bzero:
-       wr      %g0, ASI_P, %asi
-__bzero_noasi:
-       mov     %g0, %g3
-1:
-       cmp     %o1, 7
-       bleu,pn %xcc, 7f
-        andcc  %o0, 3, %o2
-
-       be,a,pt %icc, 4f
-        andcc  %o0, 4, %g0
-
-       cmp     %o2, 3
-       be,pn   %icc, 2f
-        EX(stba        %g3, [%o0] %asi, sub %o1, 0,#)
-
-       cmp     %o2, 2
-       be,pt   %icc, 2f
-        EX(stba        %g3, [%o0 + 0x01] %asi, sub %o1, 1,#)
-
-       EX(stba %g3, [%o0 + 0x02] %asi, sub %o1, 2,#)
-2:
-       sub     %o2, 4, %o2
-       sub     %o0, %o2, %o0
-       add     %o1, %o2, %o1
-       andcc   %o0, 4, %g0
-4:
-       be,a,pt %icc, 2f
-        andncc %o1, 0x7f, %o3
-
-       EX(sta  %g3, [%o0] %asi, sub %o1, 0,#)
-       sub     %o1, 4, %o1
-       add     %o0, 4, %o0
-       andncc  %o1, 0x7f, %o3          ! Now everything is 8 aligned and o1 is len to run
-2:
-       be,pn   %xcc, 9f
-        andcc  %o1, 0x78, %o2
-10:
-       ZERO_BIG_BLOCK(%o0, 0x00, %g3)
-       subcc   %o3, 128, %o3
-       ZERO_BIG_BLOCK(%o0, 0x40, %g3)
-11:
-       EXT(10b, 11b, 20f,#)
-       bne,pt  %xcc, 10b
-        add    %o0, 128, %o0
-
-       tst     %o2
-9:
-       be,pn   %xcc, 13f
-        andcc  %o1, 7, %o1
-14:
-       rd      %pc, %o4
-       srl     %o2, 1, %o3
-       sub     %o4, %o3, %o4
-       jmpl    %o4 + (13f - 14b), %g0
-        add    %o0, %o2, %o0
-12:
-       ZERO_LAST_BLOCKS(%o0, 0x48, %g3)
-       ZERO_LAST_BLOCKS(%o0, 0x08, %g3)
-13:
-       be,pn   %icc, 8f
-        andcc  %o1, 4, %g0
-
-       be,pn   %icc, 1f
-        andcc  %o1, 2, %g0
-
-       EX(sta  %g3, [%o0] %asi, and %o1, 7,#)
-       add     %o0, 4, %o0
-1:
-       be,pn   %icc, 1f
-        andcc  %o1, 1, %g0
-
-       EX(stha %g3, [%o0] %asi, and %o1, 3,#)
-       add     %o0, 2, %o0
-1:
-       bne,a,pn %icc, 8f
-        EX(stba        %g3, [%o0] %asi, and %o1, 1,#)
-8:
-       retl
-        clr    %o0
-7:
-       be,pn   %icc, 13b
-        orcc   %o1, 0, %g0
-
-       be,pn   %icc, 0f
-8:
-        add    %o0, 1, %o0
-       subcc   %o1, 1, %o1
-       bne,a,pt %icc, 8b
-        EX(stba        %g3, [%o0 - 1] %asi, add %o1, 1,#)
-0:
-       retl
-        clr    %o0
-__memset_end:
-
-       .section .fixup,#alloc,#execinstr
-       .align  4
-20:
-       cmp     %g2, 8
-       bleu,pn %xcc, 1f
-        and    %o1, 0x7f, %o1
-       sub     %g2, 9, %g2
-       add     %o3, 64, %o3
-1:
-       sll     %g2, 3, %g2
-       add     %o3, %o1, %o0
-       ba,pt   %xcc, 30f
-        sub    %o0, %g2, %o0
-21:
-       mov     8, %o0
-       and     %o1, 7, %o1
-       sub     %o0, %g2, %o0
-       sll     %o0, 3, %o0
-       ba,pt   %xcc, 30f
-        add    %o0, %o1, %o0
-30:
-/* %o4 is faulting address, %o5 is %pc where fault occured */
-       save    %sp, -160, %sp
-       mov     %i5, %o0
-       mov     %i7, %o1
-       call    lookup_fault
-        mov    %i4, %o2
-       ret
-        restore
index c41c7a938d8b31fa6947e66704d82ddb84737250..dddf3153bb2561e98cf0e4fa1c0d579593564698 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.1 1996/12/26 10:24:22 davem Exp $
+# $Id: Makefile,v 1.3 1997/06/27 14:53:38 jj Exp $
 # Makefile for the linux Sparc64-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -7,7 +7,13 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
+.S.s:
+       $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+
+.S.o:
+       $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+
 O_TARGET := mm.o
-O_OBJS   := fault.o init.o generic.o asyncd.o extable.o
+O_OBJS   := ultra.o fault.o init.o generic.o asyncd.o extable.o modutil.o
 
 include $(TOPDIR)/Rules.make
index b8da1997c68685679e92590d75df52786c297041..d7b48d5301816bc000c0b554f2265726cac64aad 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.12 1997/06/13 14:02:52 davem Exp $
+/* $Id: fault.c,v 1.17 1997/07/04 01:41:10 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)
@@ -134,61 +134,14 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
        return 0;
 }
 
-/* #define FAULT_TRACER */
-/* #define FAULT_TRACER_VERBOSE */
+/* #define DEBUG_EXCEPTIONS */
 
-#ifdef FAULT_TRACER
-/* Set and clear this elsewhere at critical moment, for oodles of debugging fun. */
-int fault_trace_enable = 0;
-#endif
-
-#include <asm/hardirq.h>
-
-asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write,
-                                unsigned long address, unsigned long tag,
-                                unsigned long sfsr)
+asmlinkage void do_sparc64_fault(struct pt_regs *regs, unsigned long address, int write)
 {
+       struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
-       unsigned long fixup;
-       unsigned long g2;
-       int from_user = !(regs->tstate & TSTATE_PRIV);
-#ifdef FAULT_TRACER
-       static unsigned long last_addr = 0;
-       static int rcnt = 0;
-
-       if(fault_trace_enable) {
-#ifdef FAULT_TRACER_VERBOSE
-               printk("FAULT(PC[%016lx],t[%d],w[%d],addr[%016lx])...",
-                      regs->tpc, text_fault, write, address);
-#else
-               printk("F[%016lx:%016lx:w(%d)", regs->tpc, address, write);
-#endif
-               if(address == last_addr) {
-                       if(rcnt++ > 15) {
-                               printk("Wheee lotsa bogus faults, something wrong, "
-                                      "spinning\n");
-                               printk("pctx[%016lx]sctx[%016lx]mmctx[%016lx]DS(%x)"
-                                      "tctx[%016lx] flgs[%016lx]\n",
-                                      spitfire_get_primary_context(),
-                                      spitfire_get_secondary_context(),
-                                      mm->context, (unsigned)current->tss.current_ds,
-                                      current->tss.ctx, current->tss.flags);
-                               __asm__ __volatile__("flushw");
-                               printk("o7[%016lx] i7[%016lx]\n",
-                                      regs->u_regs[UREG_I7],
-                     ((struct reg_window *)(regs->u_regs[UREG_FP]+STACK_BIAS))->ins[7]);
-                               sti();
-                               while(1)
-                                       barrier();
-                       }
-               } else rcnt = 0;
-               last_addr = address;
-       }
-#endif
 
-       lock_kernel ();
+       lock_kernel();
        down(&mm->mmap_sem);
        vma = find_vma(mm, address);
        if(!vma)
@@ -221,42 +174,99 @@ good_area:
         */
 bad_area:
        up(&mm->mmap_sem);
-       /* Is this in ex_table? */
+
+       {
+               unsigned long g2 = regs->u_regs[UREG_G2];
+
+               /* Is this in ex_table? */
+               if (regs->tstate & TSTATE_PRIV) {
+                       unsigned char asi = ASI_P;
+                       unsigned int insn;
+                       unsigned long fixup;
+               
+                       insn = *(unsigned int *)regs->tpc;
+                       if ((insn & 0xc0800000) == 0xc0800000) {
+                               if (insn & 0x2000)
+                                       asi = (regs->tstate >> 24);
+                               else
+                                       asi = (insn >> 5);
+                       }
        
-       g2 = regs->u_regs[UREG_G2];
-       if (!from_user && (fixup = search_exception_table (regs->tpc, &g2))) {
-               printk("Exception: PC<%016lx> faddr<%016lx>\n", regs->tpc, address);
-               printk("EX_TABLE: insn<%016lx> fixup<%016lx> g2<%016lx>\n",
-                       regs->tpc, fixup, g2);
-               regs->tpc = fixup;
-               regs->tnpc = regs->tpc + 4;
-               regs->u_regs[UREG_G2] = g2;
-               goto out;
-       }
-       if(from_user) {
-#if 1
-               unsigned long cpc;
-               __asm__ __volatile__("mov %%i7, %0" : "=r" (cpc));
-               printk("[%s:%d] SIGSEGV pc[%016lx] addr[%016lx] w[%d] sfsr[%016lx] "
-                      "caller[%016lx]\n", current->comm, current->pid, regs->tpc,
-                      address, write, sfsr, cpc);
+                       /* Look in asi.h: All _S asis have LS bit set */
+                       if ((asi & 0x1) &&
+                           (fixup = search_exception_table (regs->tpc, &g2))) {
+#ifdef DEBUG_EXCEPTIONS
+                               printk("Exception: PC<%016lx> faddr<%016lx>\n",
+                                      regs->tpc, address);
+                               printk("EX_TABLE: insn<%016lx> fixup<%016lx> "
+                                      "g2<%016lx>\n", regs->tpc, fixup, g2);
 #endif
-               tsk->tss.sig_address = address;
-               tsk->tss.sig_desc = SUBSIG_NOMAPPING;
-               send_sig(SIGSEGV, tsk, 1);
-               goto out;
+                               regs->tpc = fixup;
+                               regs->tnpc = regs->tpc + 4;
+                               regs->u_regs[UREG_G2] = g2;
+                               goto out;
+                       }
+               } else {
+                       current->tss.sig_address = address;
+                       current->tss.sig_desc = SUBSIG_NOMAPPING;
+                       send_sig(SIGSEGV, current, 1);
+                       goto out;
+               }
+               unhandled_fault (address, current, regs);
        }
-       unhandled_fault (address, tsk, regs);
 out:
        unlock_kernel();
-#ifdef FAULT_TRACER
-       if(fault_trace_enable) {
-#ifdef FAULT_TRACER_VERBOSE
-               printk(" done\n");
-#else
-               printk("]");
-#endif
-       }
-#endif
 }
 
+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_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);
+       }
+}
index 289ddd411c466eab994e795191df7d1498b14e5d..730e8cb323aa0b36c52fdccd645ff91f74d3e3cf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.1 1996/12/26 10:24:23 davem Exp $
+/* $Id: generic.c,v 1.2 1997/07/01 09:11:42 jj Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -66,13 +66,35 @@ static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsign
        if (end > PMD_SIZE)
                end = PMD_SIZE;
        do {
-               pte_t oldpage = *pte;
-               pte_clear(pte);
-               set_pte(pte, mk_pte_io(offset, prot, space));
-               forget_pte(oldpage);
-               address += PAGE_SIZE;
+               pte_t oldpage;
+               pte_t entry;
+               unsigned long curend = address + PAGE_SIZE;
+               
+               entry = mk_pte_io(offset, prot, space);
                offset += PAGE_SIZE;
-               pte++;
+               if (!(address & 0xffff)) {
+                       if (!(address & 0x3fffff) && !(offset & 0x3fffff) && end >= address + 0x400000) {
+                               entry = mk_pte_io(offset, __pgprot(pgprot_val (prot) | _PAGE_SZ4MB), space);
+                               curend = address + 0x400000;
+                               offset += 0x400000 - PAGE_SIZE;
+                       } else if (!(address & 0x7ffff) && !(offset & 0x7ffff) && end >= address + 0x80000) {
+                               entry = mk_pte_io(offset, __pgprot(pgprot_val (prot) | _PAGE_SZ512K), space);
+                               curend = address + 0x80000;
+                               offset += 0x80000 - PAGE_SIZE;
+                       } else if (!(offset & 0xffff) && end >= address + 0x10000) {
+                               entry = mk_pte_io(offset, __pgprot(pgprot_val (prot) | _PAGE_SZ64K), space);
+                               curend = address + 0x10000;
+                               offset += 0x10000 - PAGE_SIZE;
+                       }
+               }
+               do {
+                       oldpage = *pte;
+                       pte_clear(pte);
+                       set_pte(pte, entry);
+                       forget_pte(oldpage);
+                       address += PAGE_SIZE;
+                       pte++;
+               } while (address < curend);
        } while (address < end);
 }
 
index a43820257120708fa56fc3e4ba08c65bc528926c..a8d903b256558eff11f0a5ff7d9c0204620d3086 100644 (file)
@@ -1,15 +1,17 @@
-/*  $Id: init.c,v 1.30 1997/06/06 10:56:21 jj Exp $
+/*  $Id: init.c,v 1.39 1997/07/07 02:50:57 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
  *  Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
  
+#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/blk.h>
 #include <linux/swap.h>
 
+#include <asm/head.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -33,7 +35,7 @@ extern unsigned long empty_null_pte_table;
 unsigned long tlb_context_cache = CTX_FIRST_VERSION;
 
 /* References to section boundaries */
-extern char __init_begin, __init_end, etext, __p1275_loc, __bss_start;
+extern char __init_begin, __init_end, etext, __bss_start;
 
 /*
  * BAD_PAGE is the page that is used for page faults when linux
@@ -59,13 +61,15 @@ pmd_t *__bad_pmd(void)
 pte_t *__bad_pte(void)
 {
        memset((void *) &empty_bad_pte_table, 0, PAGE_SIZE);
-       return (pte_t *) (((unsigned long)&empty_bad_pte_table) + phys_base);
+       return (pte_t *) (((unsigned long)&empty_bad_pte_table) 
+               - ((unsigned long)&empty_zero_page) + phys_base + PAGE_OFFSET);
 }
 
 pte_t __bad_page(void)
 {
        memset((void *) &empty_bad_page, 0, PAGE_SIZE);
-       return pte_mkdirty(mk_pte((((unsigned long) &empty_bad_page)+phys_base),
+       return pte_mkdirty(mk_pte((((unsigned long) &empty_bad_page) 
+               - ((unsigned long)&empty_zero_page) + phys_base + PAGE_OFFSET),
                                  PAGE_SHARED));
 }
 
@@ -288,7 +292,7 @@ struct linux_prom_translation {
 };
 
 #define MAX_TRANSLATIONS 64
-static void inherit_prom_mappings(void)
+static inline void inherit_prom_mappings(void)
 {
        struct linux_prom_translation transl[MAX_TRANSLATIONS];
        pgd_t *pgdp;
@@ -332,7 +336,11 @@ static void inherit_prom_mappings(void)
        }
 }
 
-static void inherit_locked_prom_mappings(void)
+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)
 {
        int i;
        int dtlb_seen = 0;
@@ -359,6 +367,9 @@ static 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;
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
                                             : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
                        membar("#Sync");
@@ -379,6 +390,9 @@ static 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;
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
                                             : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
                        membar("#Sync");
@@ -399,6 +413,64 @@ static void inherit_locked_prom_mappings(void)
        }
 }
 
+/* Give PROM back his world, done during reboots... */
+void prom_reload_locked(void)
+{
+       __asm__ __volatile__("stxa %0, [%1] %2"
+                            : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS),
+                            "i" (ASI_DMMU));
+       membar("#Sync");
+       spitfire_put_dtlb_data(prom_dtlb_ent, prom_dtlb_data);
+       membar("#Sync");
+
+       __asm__ __volatile__("stxa %0, [%1] %2"
+                            : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS),
+                            "i" (ASI_IMMU));
+       membar("#Sync");
+       spitfire_put_itlb_data(prom_itlb_ent, prom_itlb_data);
+       membar("#Sync");
+}
+
+/* If not locked, zap it. */
+void flush_tlb_all(void)
+{
+       unsigned long flags;
+       int i;
+
+       save_flags(flags); cli();
+       for(i = 0; i < 64; i++) {
+               if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
+                       __asm__ __volatile__("stxa %%g0, [%0] %1"
+                                            : /* no outputs */
+                                            : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+                       membar("#Sync");
+                       spitfire_put_dtlb_data(i, 0x0UL);
+                       membar("#Sync");
+               }
+               if(!(spitfire_get_itlb_data(i) & _PAGE_L)) {
+                       __asm__ __volatile__("stxa %%g0, [%0] %1"
+                                            : /* no outputs */
+                                            : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
+                       membar("#Sync");
+                       spitfire_put_itlb_data(i, 0x0UL);
+                       membar("#Sync");
+               }
+       }
+       restore_flags(flags);
+}
+
+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;
+       }
+       tlb_context_cache = ctx + 1;
+       mm->context = ctx;
+}
+
 __initfunc(static void
 allocate_ptable_skeleton(unsigned long start, unsigned long end))
 {
@@ -500,51 +572,42 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
 {
        extern unsigned long phys_base;
        extern void setup_tba(unsigned long kpgdir);
-       extern void __bfill64(void *, unsigned long);
-       pgd_t *pgdp;
+       extern void __bfill64(void *, unsigned long *);
        pmd_t *pmdp;
-       pte_t *ptep, pte;
        int i;
-
-       /* Must create 2nd locked DTLB entry if physical ram starts at
-        * 4MB absolute or higher, kernel image has been placed in the
-        * right place at PAGE_OFFSET but references to start_mem and pages
-        * will be to the perfect alias mapping, so set it up now.
+       unsigned long alias_base = phys_base + PAGE_OFFSET;
+       unsigned long pt;
+       unsigned long flags;
+       unsigned long shift = alias_base - ((unsigned long)&empty_zero_page);
+       
+       /* We assume physical memory starts at some 4mb multiple,
+        * if this were not true we wouldn't boot up to this point
+        * anyways.
         */
-       if(phys_base >= (4 * 1024 * 1024)) {
-               unsigned long alias_base = phys_base + PAGE_OFFSET;
-               unsigned long pte;
-               unsigned long flags;
-
-               /* We assume physical memory starts at some 4mb multiple,
-                * if this were not true we wouldn't boot up to this point
-                * anyways.
-                */
-               pte  = phys_base | _PAGE_VALID | _PAGE_SZ4MB;
-               pte |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W;
-               save_flags(flags); cli();
-               __asm__ __volatile__("
-               stxa    %1, [%0] %3
-               stxa    %2, [%5] %4
-               membar  #Sync
-               flush   %%g4
-               nop
-               nop
-               nop"
-               : /* No outputs */
-               : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pte),
-                 "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
-               : "memory");
-               restore_flags(flags);
-
-               /* Now set kernel pgd to upper alias so physical page computations
-                * work.
-                */
-               init_mm.pgd += (phys_base / (sizeof(pgd_t *)));
-       }
+       pt  = phys_base | _PAGE_VALID | _PAGE_SZ4MB;
+       pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W;
+       save_flags(flags); cli();
+       __asm__ __volatile__("
+       stxa    %1, [%0] %3
+       stxa    %2, [%5] %4
+       membar  #Sync
+       flush   %%g6
+       nop
+       nop
+       nop"
+       : /* No outputs */
+       : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
+         "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
+       : "memory");
+       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) + phys_base);
-       null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + phys_base);
+       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++)
@@ -553,13 +616,13 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        memset((void *) &empty_null_pte_table, 0, PAGE_SIZE);
 
        /* Now can init the kernel/bad page tables. */
-       __bfill64((void *)swapper_pg_dir, null_pmd_table);
-       __bfill64((void *)&empty_bad_pmd_table, null_pte_table);
+       __bfill64((void *)swapper_pg_dir, &null_pmd_table);
+       __bfill64((void *)&empty_bad_pmd_table, &null_pte_table);
 
        /* We use mempool to create page tables, therefore adjust it up
         * such that __pa() macros etc. work.
         */
-       mempool = PAGE_ALIGN(start_mem) + phys_base;
+       mempool = PAGE_ALIGN(start_mem) + shift;
 
        /* FIXME: This should be done much nicer.
         * Just now we allocate 64M for each.
@@ -567,48 +630,29 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_VADDR + 0x4000000);
        allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000);
        inherit_prom_mappings();
-       allocate_ptable_skeleton(0, 0x8000 + PAGE_SIZE);
-
-       /* Map prom interface page. */
-       pgdp = pgd_offset(init_task.mm, 0x8000);
-       pmdp = pmd_offset(pgdp, 0x8000);
-       ptep = pte_offset(pmdp, 0x8000);
-       pte  = mk_pte(((unsigned long)&__p1275_loc)+phys_base, PAGE_KERNEL);
-       set_pte(ptep, pte);
-
+       
        /* Ok, we can use our TLB miss and window trap handlers safely. */
        setup_tba((unsigned long)init_mm.pgd);
 
-       /* Kill locked PROM interface page mapping, the mapping will
-        * re-enter on the next PROM interface call via our TLB miss
-        * handlers.
-        */
-       spitfire_flush_dtlb_primary_page(0x8000);
-       membar("#Sync");
-       spitfire_flush_itlb_primary_page(0x8000);
-       membar("#Sync");
-
        /* Really paranoid. */
-       flushi(PAGE_OFFSET);
+       flushi((long)&empty_zero_page);
        membar("#Sync");
 
        /* Cleanup the extra locked TLB entry we created since we have the
         * nice TLB miss handlers of ours installed now.
         */
-       if(phys_base >= (4 * 1024 * 1024)) {
-               /* We only created DTLB mapping of this stuff. */
-               spitfire_flush_dtlb_nucleus_page(phys_base + PAGE_OFFSET);
-               membar("#Sync");
-
-               /* Paranoid */
-               flushi(PAGE_OFFSET);
-               membar("#Sync");
-       }
+       /* We only created DTLB mapping of this stuff. */
+       spitfire_flush_dtlb_nucleus_page(alias_base);
+       membar("#Sync");
 
-       inherit_locked_prom_mappings();
+       /* Paranoid */
+       flushi((long)&empty_zero_page);
+       membar("#Sync");
 
+       inherit_locked_prom_mappings();
+       
        flush_tlb_all();
-
+       
        start_mem = free_area_init(PAGE_ALIGN(mempool), end_mem);
 
        return device_scan (PAGE_ALIGN (start_mem));
@@ -642,9 +686,8 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
        int codepages = 0;
        int datapages = 0;
        int initpages = 0;
-       int prompages = 0;
        unsigned long tmp2, addr;
-       unsigned long data_end;
+       unsigned long alias_base = phys_base + PAGE_OFFSET - (long)(&empty_zero_page);
 
        end_mem &= PAGE_MASK;
        max_mapnr = MAP_NR(end_mem);
@@ -665,16 +708,14 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
        }
 
        taint_real_pages(start_mem, end_mem);
-       data_end = start_mem - phys_base;
        for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
                if(PageReserved(mem_map + MAP_NR(addr))) {
-                       if ((addr < (unsigned long) &etext) && (addr >= PAGE_OFFSET))
+                       if ((addr < ((unsigned long) &etext) + alias_base) && (addr >= alias_base))
                                codepages++;
-                       else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+                       else if((addr >= ((unsigned long)&__init_begin) + alias_base)
+                               && (addr < ((unsigned long)&__init_end) + alias_base))
                                initpages++;
-                       else if((addr >= (unsigned long)&__p1275_loc && addr < (unsigned long)&__bss_start))
-                               prompages++;
-                       else if((addr < data_end) && (addr >= PAGE_OFFSET))
+                       else if((addr < start_mem) && (addr >= alias_base))
                                datapages++;
                        continue;
                }
@@ -689,12 +730,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 
        tmp2 = nr_free_pages << PAGE_SHIFT;
 
-       printk("Memory: %luk available (%dk kernel code, %dk data, %dk init, %dk prom) [%016lx,%016lx]\n",
+       printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%016lx,%016lx]\n",
               tmp2 >> 10,
               codepages << (PAGE_SHIFT-10),
               datapages << (PAGE_SHIFT-10), 
               initpages << (PAGE_SHIFT-10), 
-              prompages << (PAGE_SHIFT-10), 
               PAGE_OFFSET, end_mem);
 
        min_free_pages = nr_free_pages >> 7;
@@ -702,11 +742,6 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
                min_free_pages = 16;
        free_pages_low = min_free_pages + (min_free_pages >> 1);
        free_pages_high = min_free_pages + min_free_pages;
-
-#if 0
-       printk("Testing fault handling...\n");
-       *(char *)0x00000deadbef0000UL = 0;
-#endif
 }
 
 void free_initmem (void)
@@ -715,10 +750,8 @@ void free_initmem (void)
        
        addr = (unsigned long)(&__init_begin);
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-               unsigned long page = addr;
-
-               if(page < ((unsigned long)__va(phys_base)))
-                       page += phys_base;
+               unsigned long page = addr + (long)__va(phys_base)
+                                       - (long)(&empty_zero_page);
 
                mem_map[MAP_NR(page)].flags &= ~(1 << PG_reserved);
                atomic_set(&mem_map[MAP_NR(page)].count, 1);
diff --git a/arch/sparc64/mm/modutil.c b/arch/sparc64/mm/modutil.c
new file mode 100644 (file)
index 0000000..e6b4b22
--- /dev/null
@@ -0,0 +1,66 @@
+/*  $Id: modutil.c,v 1.1 1997/06/27 14:53:35 jj Exp $
+ *  arch/sparc64/mm/modutil.c
+ *
+ *  Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *  Based upon code written by Linus Torvalds and others.
+ */
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/vaddrs.h>
+
+static struct vm_struct * modvmlist = NULL;
+
+void module_unmap (void * addr)
+{
+       struct vm_struct **p, *tmp;
+
+       if (!addr)
+               return;
+       if ((PAGE_SIZE-1) & (unsigned long) addr) {
+               printk("Trying to vfree() bad address (%p)\n", addr);
+               return;
+       }
+       for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
+               if (tmp->addr == addr) {
+                       *p = tmp->next;
+                       vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
+                       kfree(tmp);
+                       return;
+               }
+       }
+       printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
+}
+
+void * module_map (unsigned long size)
+{
+       void * addr;
+       struct vm_struct **p, *tmp, *area;
+
+       size = PAGE_ALIGN(size);
+       if (!size || size > MODULES_LEN) return NULL;
+               
+       addr = (void *) MODULES_VADDR;
+       for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
+               if (size + (unsigned long) addr < (unsigned long) tmp->addr)
+                       break;
+               addr = (void *) (tmp->size + (unsigned long) tmp->addr);
+       }
+       if ((unsigned long) addr + size >= MODULES_END) return NULL;
+       
+       area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+       if (!area) return NULL;
+       area->size = size + PAGE_SIZE;
+       area->addr = addr;
+       area->next = *p;
+       *p = area;
+
+       if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size)) {
+               vfree(addr);
+               return NULL;
+       }
+       return addr;
+}
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
new file mode 100644 (file)
index 0000000..de9893e
--- /dev/null
@@ -0,0 +1,101 @@
+/* $Id: ultra.S,v 1.6 1997/06/30 10:31:43 jj Exp $
+ * ultra.S: Don't expand these all over the place...
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/asi.h>
+#include <asm/spitfire.h>
+
+       /* All callers check mm->context != NO_CONTEXT for us. */
+       .text
+       .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
+       cmp             %g2, %o0
+       be,pt           %icc, 1f
+        mov            0x50, %g3
+       stxa            %o0, [%g7] ASI_DMMU
+1:     stxa            %g0, [%g3] ASI_DMMU_DEMAP
+       be,pt           %icc, 1f
+        stxa           %g0, [%g3] ASI_IMMU_DEMAP
+
+       stxa            %g2, [%g7] ASI_DMMU
+1:     wrpr            %g1, 0x0, %pil
+       retl
+        flush          %g6
+__flush_tlb_range:     /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
+       sethi           %hi(8192 - 1), %g5
+       or              %g5, %lo(8192 - 1), %g5
+       andn            %o1, %g5, %o1
+       andn            %o2, %g5, %o2
+
+       sub             %o2, %o1, %o3
+       add             %g5, 1, %g5
+       orcc            %o1, 0x50, %o1
+       srlx            %o3, 13, %o4
+       rdpr            %otherwin, %g1
+       brz,pt          %g1, 1f
+        mov            %o7, %g3
+       call            __flushw_user
+
+        clr            %g2
+1:     cmp             %o4, 96
+       bgu,pn          %icc, 9b
+        rdpr           %pil, %g1
+       mov             SECONDARY_CONTEXT, %g7
+       wrpr            %g0, 15, %pil
+       ldxa            [%g7] ASI_DMMU, %g2
+       cmp             %g2, %o0
+
+       be,pt           %icc, 1f
+        sub            %o3, %g5, %o3
+       stxa            %o0, [%g7] ASI_DMMU
+1:     stxa            %g0, [%o1 + %o3] ASI_DMMU_DEMAP
+       stxa            %g0, [%o1 + %o3] ASI_IMMU_DEMAP
+       brnz,pt         %o3, 1b
+        sub            %o3, %g5, %o3
+       nop
+
+       be,pt           %icc, 1f
+        wrpr           %g1, 0x0, %pil
+       stxa            %g2, [%g7] ASI_DMMU
+1:     retl
+        flush          %g6
+
+       .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            %o0, [%g7] ASI_DMMU
+1:     stxa            %g0, [%g3] ASI_DMMU_DEMAP
+       be,pt           %icc, 1f
+        stxa           %g0, [%g3] ASI_IMMU_DEMAP
+       stxa            %g2, [%g7] ASI_DMMU
+1:     wrpr            %g1, 0x0, %pil
+       retl
+        flush          %g6
+
+
+       
index e226c6e9585f24a3136f5009e0e806620370e29e..7ef17159d3a9469b76e7ae132195696f97ab0442 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bootstr.c,v 1.3 1997/03/04 16:27:06 jj Exp $
+/* $Id: bootstr.c,v 1.4 1997/06/17 13:25:35 jj Exp $
  * bootstr.c:  Boot string/argument acquisition from the PROM.
  *
  * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -6,18 +6,20 @@
  */
 
 #include <linux/string.h>
+#include <linux/init.h>
 #include <asm/oplib.h>
 
 #define BARG_LEN  256
-static char barg_buf[BARG_LEN];
-static char fetched = 0;
+int bootstr_len __initdata = BARG_LEN;
+static int bootstr_valid __initdata = 0;
+static char bootstr_buf[BARG_LEN] __initdata = { 0 };
 
-char *
-prom_getbootargs(void)
+__initfunc(char *
+prom_getbootargs(void))
 {
        /* This check saves us from a panic when bootfd patches args. */
-       if (fetched) return barg_buf;
-       prom_getstring(prom_chosen_node, "bootargs", barg_buf, BARG_LEN);
-       fetched = 1;
-       return barg_buf;
+       if (bootstr_valid) return bootstr_buf;
+       prom_getstring(prom_chosen_node, "bootargs", bootstr_buf, BARG_LEN);
+       bootstr_valid = 1;
+       return bootstr_buf;
 }
index fe9bf9c6b057c8bbc5f5a9203b5dbc32c3cd0ddc..9c11d75b337886d79f34e0784ae36961e4dd3c95 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.6 1997/04/10 05:13:05 davem Exp $
+/* $Id: misc.c,v 1.7 1997/07/05 09:52:51 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -6,6 +6,7 @@
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -45,8 +46,8 @@ void
 prom_cmdline(void)
 {
        extern void kernel_enter_debugger(void);
-       extern void install_obp_ticker(void);
-       extern void install_linux_ticker(void);
+       /* extern void install_obp_ticker(void); */
+       /* extern void install_linux_ticker(void); */
        unsigned long flags;
     
        /* kernel_enter_debugger(); */
index 3eb0311dfcc8391c57d32472bf257c071a9fde6b..18de40debe77916978ff898fdde3e1492e4a3b5e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.8 1997/04/03 09:29:21 davem Exp $
+/* $Id: p1275.c,v 1.10 1997/06/27 04:18:30 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 #include <asm/spitfire.h>
 #include <asm/pstate.h>
 
-/* If you change layout of this structure, please change the prom_doit
-   function below as well. */
-typedef struct {
-       unsigned prom_doit_code [24];           /* 0x8000 */
-       long prom_sync_routine;                 /* 0x8060 */
-       void (*prom_cif_handler)(long *);       /* 0x8068 */
-       unsigned long prom_cif_stack;           /* 0x8070 */
-       unsigned long prom_args [23];           /* 0x8078 */
-       char prom_buffer [7888];
-} at0x8000;
+struct {
+       long prom_sync_routine;                 /* 0x00 */
+       void (*prom_cif_handler)(long *);       /* 0x08 */
+       unsigned long prom_cif_stack;           /* 0x10 */
+       unsigned long prom_args [23];           /* 0x18 */
+       char prom_buffer [3000];
+} p1275buf;
 
-static void (*prom_do_it)(void);
-
-void prom_cif_interface (void) __attribute__ ((__section__ (".p1275")));
-
-/* At most 14 insns */
 void prom_cif_interface (void)
 {
        __asm__ __volatile__ ("
-       sethi   %%hi(0x8000), %%o0
-       ldx     [%%o0 + 0x070], %%o1    ! prom_cif_stack
+       mov     %0, %%o0
+       ldx     [%%o0 + 0x010], %%o1    ! prom_cif_stack
        save    %%o1, -0xc0, %%sp
-       ldx     [%%i0 + 0x068], %%l2    ! prom_cif_handler
+       ldx     [%%i0 + 0x008], %%l2    ! prom_cif_handler
        rdpr    %%pstate, %%l4
        mov     %%g4, %%l0
        mov     %%g6, %%l1
-       wrpr    %%l4, %0, %%pstate      ! turn on address masking
+       wrpr    %%l4, %1, %%pstate      ! turn on address masking
        call    %%l2
-        or     %%i0, 0x078, %%o0       ! prom_args
+        add    %%i0, 0x018, %%o0       ! prom_args
        wrpr    %%l4, 0, %%pstate       ! put pstate back
        mov     %%l0, %%g4
        ret
         restore %%l1, 0, %%g6
        save    %%sp, -0xc0, %%sp       ! If you change the offset of the save 
        rdpr    %%pstate, %%l4          ! here, please change the 0x8038 
-       andn    %%l4, %0, %%l3          ! constant below as well
+       andn    %%l4, %1, %%l3          ! constant below as well
        wrpr    %%l3, %%pstate
-       ldx     [%%o0 + 0x060], %%l2
+       ldx     [%%o0 + 0x000], %%l2
        call    %%l2
         nop
        wrpr    %%l4, 0, %%pstate
        ret
         restore
-       " : : "i" (PSTATE_AM));
+       " : : "r" (&p1275buf), "i" (0 /* PSTATE_AM */));
 }
 
 long p1275_cmd (char *service, long fmt, ...)
@@ -68,61 +60,60 @@ long p1275_cmd (char *service, long fmt, ...)
        va_list list;
        long attrs, x;
        long ctx = 0;
-       at0x8000 *low = (at0x8000 *)(0x8000);
        
-       p = low->prom_buffer;
+       p = p1275buf.prom_buffer;
        save_and_cli(flags);
        ctx = spitfire_get_primary_context ();
        if (ctx) {
                flushw_user ();
                spitfire_set_primary_context (0);
        }
-       low->prom_args[0] = (unsigned long)p;                   /* service */
+       p1275buf.prom_args[0] = (unsigned long)p;                       /* service */
        strcpy (p, service);
        p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
-       low->prom_args[1] = nargs = (fmt & 0x0f);               /* nargs */
-       low->prom_args[2] = nrets = ((fmt & 0xf0) >> 4);        /* nrets */
+       p1275buf.prom_args[1] = nargs = (fmt & 0x0f);           /* nargs */
+       p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4);    /* nrets */
        attrs = fmt >> 8;
        va_start(list, fmt);
        for (i = 0; i < nargs; i++, attrs >>= 3) {
                switch (attrs & 0x7) {
                case P1275_ARG_NUMBER:
-                       low->prom_args[i + 3] = (unsigned)va_arg(list, long); break;
+                       p1275buf.prom_args[i + 3] = (unsigned)va_arg(list, long); break;
                case P1275_ARG_IN_STRING:
                        strcpy (p, va_arg(list, char *));
-                       low->prom_args[i + 3] = (unsigned long)p;
+                       p1275buf.prom_args[i + 3] = (unsigned long)p;
                        p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
                        break;
                case P1275_ARG_OUT_BUF:
                        (void) va_arg(list, char *);
-                       low->prom_args[i + 3] = (unsigned long)p;
+                       p1275buf.prom_args[i + 3] = (unsigned long)p;
                        x = va_arg(list, long);
                        i++; attrs >>= 3;
                        p = (char *)(((long)(p + (int)x + 7)) & ~7);
-                       low->prom_args[i + 3] = x;
+                       p1275buf.prom_args[i + 3] = x;
                        break;
                case P1275_ARG_IN_BUF:
                        q = va_arg(list, char *);
-                       low->prom_args[i + 3] = (unsigned long)p;
+                       p1275buf.prom_args[i + 3] = (unsigned long)p;
                        x = va_arg(list, long);
                        i++; attrs >>= 3;
                        memcpy (p, q, (int)x);
                        p = (char *)(((long)(p + (int)x + 7)) & ~7);
-                       low->prom_args[i + 3] = x;
+                       p1275buf.prom_args[i + 3] = x;
                        break;
                case P1275_ARG_OUT_32B:
                        (void) va_arg(list, char *);
-                       low->prom_args[i + 3] = (unsigned long)p;
+                       p1275buf.prom_args[i + 3] = (unsigned long)p;
                        p += 32;
                        break;
                case P1275_ARG_IN_FUNCTION:
-                       low->prom_args[i + 3] = 0x8038;
-                       low->prom_sync_routine = va_arg(list, long); break;
+                       p1275buf.prom_args[i + 3] = (unsigned long)prom_cif_interface + 0x38;
+                       p1275buf.prom_sync_routine = va_arg(list, long); break;
                }
        }
        va_end(list);
-       
-       (*prom_do_it)();
+
+       prom_cif_interface();
 
        attrs = fmt >> 8;
        va_start(list, fmt);
@@ -142,17 +133,17 @@ long p1275_cmd (char *service, long fmt, ...)
                case P1275_ARG_OUT_BUF:
                        p = va_arg(list, char *);
                        x = va_arg(list, long);
-                       memcpy (p, (char *)(low->prom_args[i + 3]), (int)x);
+                       memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x);
                        i++; attrs >>= 3;
                        break;
                case P1275_ARG_OUT_32B:
                        p = va_arg(list, char *);
-                       memcpy (p, (char *)(low->prom_args[i + 3]), 32);
+                       memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32);
                        break;
                }
        }
        va_end(list);
-       x = low->prom_args [nargs + 3];
+       x = p1275buf.prom_args [nargs + 3];
        
        if (ctx)
                spitfire_set_primary_context (ctx);
@@ -162,9 +153,6 @@ long p1275_cmd (char *service, long fmt, ...)
 
 void prom_cif_init(void *cif_handler, void *cif_stack)
 {
-       at0x8000 *low = (at0x8000 *)(0x8000);
-
-       low->prom_cif_handler = (void (*)(long *))cif_handler;
-       low->prom_cif_stack = (unsigned long)cif_stack;
-        prom_do_it = (void (*)(void))(0x8000);
+       p1275buf.prom_cif_handler = (void (*)(long *))cif_handler;
+       p1275buf.prom_cif_stack = (unsigned long)cif_stack;
 }
index d2d0cac34138125098c4c3429072824663666d66..eac8314cac4cbec9aebe36c505d408ca583a8732 100644 (file)
@@ -5,10 +5,10 @@ ENTRY(_start)
 
 SECTIONS
 {
-  empty_zero_page = 0xfffff80000000000;
-  swapper_pg_dir =  0xfffff80000002000;
+  empty_zero_page = 0x0000000000400000;
+  swapper_pg_dir =  0x0000000000402000;
   . = 0x4000;
-  .text 0xfffff80000004000 :
+  .text 0x0000000000404000 :
   {
     *(.text)
     *(.gnu.warning)
@@ -40,12 +40,6 @@ SECTIONS
   .data.init : { *(.data.init) }
   . = ALIGN(8192);
   __init_end = .;
-  __p1275_loc = .;
-  .p1275 :
-  {
-       *(.p1275)
-       . = ALIGN(8192);
-  }
   __bss_start = .;
   .sbss      : { *(.sbss) *(.scommon) }
   .bss       :
index fdc01f3d272f3523b1919e19bda51e4b19db35e5..a1fc2927de98e327688a27dfb91a03d9314f31f5 100644 (file)
@@ -2896,6 +2896,8 @@ static void raw_cmd_done(int flag)
                raw_cmd->flags |= FD_RAW_HARDFAILURE;
        } else {
                raw_cmd->reply_count = inr;
+               if(raw_cmd->reply_count > MAX_REPLIES)
+                       raw_cmd->reply_count=0;
                for (i=0; i< raw_cmd->reply_count; i++)
                        raw_cmd->reply[i] = reply_buffer[i];
 
index edf88356febb547cc95a063d25bf80aac3592ced..0be35e1ad7bd13748113715fab28bcba53bd89cd 100644 (file)
@@ -628,7 +628,10 @@ __initfunc(int psaux_init(void))
                poll_aux_status_nosleep();
 #endif /* INITIALIZE_DEVICE */
                outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
-               aux_write_dev_nosleep(AUX_INTS_OFF);        /* Disable controller interrupts */
+               poll_aux_status_nosleep();
+               outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
+               poll_aux_status_nosleep();
+               outb_p(AUX_INTS_OFF, KBD_DATA_REG);                
        }
        return 0;
 }
index 8f101539726ce5ec2a5638a7207ec4f74b064264..929bb2f857a2d245bffa3a1abae0714494e6e6bb 100644 (file)
@@ -26,20 +26,6 @@ struct pty_struct {
 
 #define PTY_MAGIC 0x5001
 
-#define PTY_BUF_SIZE PAGE_SIZE/2
-
-/*
- * tmp_buf is used as a temporary buffer by pty_write.  We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a pty write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the PTY's, since it significantly saves memory if
- * large numbers of PTY's are open.
- */
-static unsigned char *tmp_buf;
-static struct semaphore tmp_buf_sem = MUTEX;
-
 static struct tty_driver pty_driver, pty_slave_driver;
 static struct tty_driver old_pty_driver, old_pty_slave_driver;
 static int pty_refcount;
@@ -104,37 +90,51 @@ static void pty_unthrottle(struct tty_struct * tty)
        set_bit(TTY_THROTTLED, &tty->flags);
 }
 
+/*
+ * WSH 05/24/97: modified to 
+ *   (1) use space in tty->flip instead of a shared temp buffer
+ *      The flip buffers aren't being used for a pty, so there's lots
+ *      of space available.  The buffer is protected by a per-pty
+ *      semaphore that should almost never come under contention.
+ *   (2) avoid redundant copying for cases where count >> receive_room
+ * N.B. Calls from user space may now return an error code instead of
+ * a count.
+ */
 static int pty_write(struct tty_struct * tty, int from_user,
                       const unsigned char *buf, int count)
 {
        struct tty_struct *to = tty->link;
-       int     c=0, n, r;
+       int     c=0, n;
        char    *temp_buffer;
 
        if (!to || tty->stopped)
                return 0;
-       
+
        if (from_user) {
-               down(&tmp_buf_sem);
-               temp_buffer = tmp_buf +
-                       ((tty->driver.subtype-1) * PTY_BUF_SIZE);
+               down(&tty->flip.pty_sem);
+               temp_buffer = &tty->flip.char_buf[0];
                while (count > 0) {
-                       n = MIN(count, PTY_BUF_SIZE);
+                       /* check space so we don't copy needlessly */ 
+                       n = MIN(count, to->ldisc.receive_room(to));
+                       if (!n) break;
+
+                       n  = MIN(n, PTY_BUF_SIZE);
                        n -= copy_from_user(temp_buffer, buf, n);
                        if (!n) {
                                if (!c)
                                        c = -EFAULT;
                                break;
                        }
-                       r = to->ldisc.receive_room(to);
-                       if (r <= 0)
-                               break;
-                       n = MIN(n, r);
-                       to->ldisc.receive_buf(to, temp_buffer, 0, n);
-                       buf += n;  c+= n;
+
+                       /* check again in case the buffer filled up */
+                       n = MIN(n, to->ldisc.receive_room(to));
+                       if (!n) break;
+                       buf   += n; 
+                       c     += n;
                        count -= n;
+                       to->ldisc.receive_buf(to, temp_buffer, 0, n);
                }
-               up(&tmp_buf_sem);
+               up(&tty->flip.pty_sem);
        } else {
                c = MIN(count, to->ldisc.receive_room(to));
                to->ldisc.receive_buf(to, buf, 0, c);
@@ -153,14 +153,42 @@ static int pty_write_room(struct tty_struct *tty)
        return to->ldisc.receive_room(to);
 }
 
+/*
+ *     WSH 05/24/97:  Modified for asymmetric MASTER/SLAVE behavior
+ *     The chars_in_buffer() value is used by the ldisc select() function 
+ *     to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
+ *     The pty driver chars_in_buffer() Master/Slave must behave differently:
+ *
+ *      The Master side needs to allow typed-ahead commands to accumulate
+ *      while being canonicalized, so we report "our buffer" as empty until
+ *     some threshold is reached, and then report the count. (Any count >
+ *     WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock 
+ *     the count returned must be 0 if no canonical data is available to be 
+ *     read. (The N_TTY ldisc.chars_in_buffer now knows this.)
+ *  
+ *     The Slave side passes all characters in raw mode to the Master side's
+ *     buffer where they can be read immediately, so in this case we can
+ *     return the true count in the buffer.
+ */
 static int pty_chars_in_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
+       int count;
 
        if (!to || !to->ldisc.chars_in_buffer)
                return 0;
 
-       return to->ldisc.chars_in_buffer(to);
+       /* The ldisc must report 0 if no characters available to be read */
+       count = to->ldisc.chars_in_buffer(to);
+
+       if (tty->driver.subtype == PTY_TYPE_SLAVE) return count;
+
+       /* Master side driver ... if the other side's read buffer is less than 
+        * half full, return 0 to allow writers to proceed; otherwise return
+        * the count.  This leaves a comfortable margin to avoid overflow, 
+        * and still allows half a buffer's worth of typed-ahead commands.
+        */
+       return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
 }
 
 static void pty_flush_buffer(struct tty_struct *tty)
@@ -194,17 +222,6 @@ static int pty_open(struct tty_struct *tty, struct file * filp)
        pty = pty_state + line;
        tty->driver_data = pty;
 
-       if (!tmp_buf) {
-               unsigned long page = __get_free_page(GFP_KERNEL);
-               if (!tmp_buf) {
-                       retval = -ENOMEM;
-                       if (!page)
-                               goto out;
-                       tmp_buf = (unsigned char *) page;
-                       memset((void *) page, 0, PAGE_SIZE);
-               } else
-                       free_page(page);
-       }
        retval = -EIO;
        if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
                goto out;
@@ -288,8 +305,6 @@ __initfunc(int pty_init(void))
        old_pty_slave_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS;
        old_pty_slave_driver.other = &old_pty_driver;
 
-       tmp_buf = 0;
-
        if (tty_register_driver(&pty_driver))
                panic("Couldn't register pty driver");
        if (tty_register_driver(&pty_slave_driver))
index 2e905fadd66344761074d4c8a4aafb6004d2ad37..4cccb8faf7697eb6aa5f91c9a8f342596d4ec7d2 100644 (file)
  */
 
 #include <linux/utsname.h>
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/string.h>
index a4fb2cb175f22323f35000caec24e66367d3e8e2..d7c09833c3c792f6a8fee11e3cd25318d3d2562f 100644 (file)
@@ -152,7 +152,7 @@ static long rtc_read(struct inode *inode, struct file *file, char *buf,
                     unsigned long count)
 {
        struct wait_queue wait = { current, NULL };
-       int retval;
+       int retval = 0;
        
        if (count < sizeof(unsigned long))
                return -EINVAL;
index e2044c086590c1452f8966f17be07af14af3a073..cd44d36aaa5cda4b4be12ab7423e52f7a141ee51 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- linux-c -*-
  *
- *     $Id: sysrq.c,v 1.2 1997/05/31 18:33:11 mj Exp $
+ *     $Id: sysrq.c,v 1.3 1997/06/18 09:42:12 mj Exp $
  *
  *     Linux Magic System Request Key Hacks
  *
@@ -112,7 +112,7 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
                show_mem();
                break;
        case 2 ... 11:                                      /* 0-9 -- set console logging level */
-               key -= 2;
+               key--;
                if (key == 10)
                        key = 0;
                orig_log_level = key;
index 7678e75e9af502f1821fa6fa0aff9b255eda4944..be5e75fe8bedc1cc2876cae351b4a88c2355043d 100644 (file)
@@ -1654,6 +1654,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
        tty->flip.flag_buf_ptr = tty->flip.flag_buf;
        tty->flip.tqueue.routine = flush_to_ldisc;
        tty->flip.tqueue.data = tty;
+       tty->flip.pty_sem = MUTEX;
 }
 
 /*
index 603250b81ccf3bb6639adeff12fd38d3b2fc1ecc..c0d7440c3f0765803aca368dc959e2eac221f00f 100644 (file)
@@ -237,6 +237,11 @@ vcs_write(struct inode *inode, struct file *file, const char *buf, unsigned long
                        func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
                }
        }
+#ifdef CONFIG_FB_CONSOLE
+       if (currcons == fg_console)
+               /* Horribly inefficient if count < screen size.  */
+               update_screen(currcons);
+#endif
        written = buf - buf0;
        file->f_pos += written;
        RETURN( written );
index b3c25cd2af9fc333606ac1a0762947470f71dee3..9eb60afed999a94450d5d2cd471e9a42cfa2ef76 100644 (file)
@@ -26,6 +26,7 @@
  *
  */
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/stddef.h>
index 1cc7b5bae850bbc12029ff68dbcb822b797061df..7188ee0dab16b20c5978f9905500403638230700 100644 (file)
@@ -151,8 +151,12 @@ if [ "$CONFIG_NET_RADIO" != "n" ]; then
       bool 'Soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8
       bool 'Soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800
       bool 'Soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
-      #bool 'Soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666
-      #bool 'Soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800
+      if [ -f drivers/net/soundmodem/sm_afsk2666.c ]; then
+        bool 'Soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666
+      fi
+      if [ -f drivers/net/soundmodem/sm_psk4800.c ]; then
+        bool 'Soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800
+      fi
     fi
   fi
   tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
index a7e7c1303d0abcf460f200565360e1129d0a2500..fb353dc61887445d464d3a6bf525837ec202d7b1 100644 (file)
@@ -45,6 +45,7 @@ static const char *version =
 #include <linux/version.h>
 #endif
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
index 12a488cbc2697d1d9a3f73276fec98d63a2f187a..d3e337afc8d9821145fa604fca5d8c9a15dad797 100644 (file)
@@ -24,6 +24,7 @@
  *      - Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
  */
 
+#include <linux/config.h>
 
 #ifdef CONFIG_COPS_DAYNA
 
index 6ec334031e03e87cdc68a155724106d6f88db727..33f3d9a06932bdf2708eeea6dddad3b59ef89abb 100644 (file)
@@ -23,6 +23,7 @@
  *      - Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
  */
  
+#include <linux/config.h>
 
 #ifdef CONFIG_COPS_TANGENT
 
index 77574991b9ca486e42bb7f8eb7b0475f60cf584a..46ff5b5d9b12a6f41529a85de9f092e4bbdf9586 100644 (file)
@@ -13,7 +13,6 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
index 8c0764acb2390d68f5dbf20880902073f7b1d794..2ced975802257b08243409e8f20f1323b2981670 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cgsix.c,v 1.32 1997/06/14 15:26:08 davem Exp $
+/* $Id: cgsix.c,v 1.33 1997/07/01 09:12:05 jj Exp $
  * cgsix.c: cgsix frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -234,11 +234,32 @@ cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
 {
        uint size, page, r, map_size;
        unsigned long map_offset = 0;
-       
+
        size = vma->vm_end - vma->vm_start;
         if (vma->vm_offset & ~PAGE_MASK)
                 return -ENXIO;
 
+#ifdef __sparc_v9__
+       /* Try to align RAM */
+#define ALIGNMENT 0x80000
+       map_offset = vma->vm_offset + size;
+       if (vma->vm_offset <= CG6_RAM && map_offset >= CG6_RAM + fb->type.fb_size) {
+               struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start);
+               int alignment = ALIGNMENT - ((vma->vm_start + CG6_RAM - vma->vm_offset) & (ALIGNMENT - 1));
+               int sz = 0, fbsz; 
+
+               if (alignment == ALIGNMENT) alignment = 0;
+               fbsz = ((fb->type.fb_size + ALIGNMENT - 1) & ~(ALIGNMENT - 1));
+               if (map_offset < CG6_RAM + fbsz)
+                       sz = fbsz - map_offset + CG6_RAM;
+               if ((sz || alignment) && (!vmm || vmm->vm_start >= vma->vm_end + sz + alignment)) {
+                       vma->vm_start += alignment;
+                       vma->vm_end += alignment + sz;
+               }
+       }
+#undef ALIGNMENT
+#endif 
+
        /* To stop the swapper from even considering these pages */
        vma->vm_flags |= FB_MMAP_VM_FLAGS;
        
index 548abb60107938dddee829bd32915cff5e919bf3..75b9500715443a6fd69cc6570aa9d7325ed0014c 100644 (file)
@@ -137,6 +137,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
        struct openpromio *opp;
        unsigned long flags;
        int bufsize, len, error = 0;
+       extern char saved_command_line[];
 
        if (cmd == OPROMSETOPT)
                bufsize = getstrings((void *)arg, &opp);
@@ -172,7 +173,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
        case OPROMNXTOPT:
        case OPROMNXTPROP:
                save_and_cli(flags);
-               buf = prom_nextprop(node, opp->oprom_array);
+               buf = prom_nextprop(node, opp->oprom_array, buffer);
                restore_flags(flags);
 
                len = strlen(buf);
@@ -229,9 +230,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                break;
 
        case OPROMGETBOOTARGS:
-               save_and_cli(flags);
-               buf = prom_getbootargs();
-               restore_flags(flags);
+               buf = saved_command_line;
 
                len = strlen(buf);
 
@@ -315,6 +314,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
        unsigned long flags;
        int error, node, len;
        char *str, *tmp;
+       char buffer[64];
 
        switch (cmd) {
        case OPIOCGET:
@@ -378,7 +378,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                        return error;
 
                save_and_cli(flags);
-               tmp = prom_nextprop(op.op_nodeid,str);
+               tmp = prom_nextprop(op.op_nodeid,str,buffer);
                restore_flags(flags);
 
                if (tmp) {
index d0a5db4e5763f1a8d157201c40a23b0f75927196..227660457b05408e7a69e42d39c325a6a50f8b86 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunfb.c,v 1.24 1997/06/06 10:56:24 jj Exp $
+/* $Id: sunfb.c,v 1.25 1997/07/01 09:12:06 jj Exp $
  * sunfb.c: Sun generic frame buffer support.
  *
  * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -276,6 +276,7 @@ fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
                
                v = (*fb->mmap)(inode, file, vma, fb->base, fb);
                if (v) return v;
+               vma->vm_flags |= VM_IO;
                if (!fb->mmaped) {
                        fb->mmaped = 1;
                        if (!minor) {
index 1ddaaecd42aa18b1adf9f2285228b99a93133fc3..54b09cd7604dd713b37b8c5ecb4600f35f551aa2 100644 (file)
@@ -419,27 +419,27 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
 
        if(ch == SKBD_RESET) {
                kbd_reset_pending = 1;
-               return;
+               goto out;
        }
        if(ch == SKBD_LYOUT) {
                kbd_layout_pending = 1;
-               return;
+               goto out;
        }
        if(kbd_reset_pending) {
                sunkbd_type = ch;
                kbd_reset_pending = 0;
                if(ch == SUNKBD_TYPE4)
                        send_cmd(SKBDCMD_GLAYOUT);
-               return;
+               goto out;
        } else if(kbd_layout_pending) {
                sunkbd_layout = ch;
                kbd_layout_pending = 0;
-               return;
+               goto out;
        } else if(ch == SKBD_ALLUP) {
                del_timer (&auto_repeat_timer);
                memset(key_down, 0, sizeof(key_down));
                compute_shiftstate();
-               return;
+               goto out;
        }
 #ifdef SKBD_DEBUG
        if(ch == 0x7f)
@@ -456,11 +456,11 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
        } else {
                keycode = ch;
        }
-       add_keyboard_randomness(keycode);
        
-       mark_bh(KEYBOARD_BH);
        do_poke_blanked_console = 1;
        mark_bh(CONSOLE_BH);
+       add_keyboard_randomness(keycode);
+
        kbd = kbd_table + fg_console;
        tty = ttytab[fg_console];
        if((raw_mode = (kbd->kbdmode == VC_RAW))) {
@@ -491,11 +491,11 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
        }
 
        if(raw_mode)
-               return;
+               goto out;
 
        if(kbd->kbdmode == VC_MEDIUMRAW) {
                put_queue(keycode + up_flag);
-               return;
+               goto out;
        }
 
        /*
@@ -545,6 +545,8 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
                        compute_shiftstate();
                }
        }
+out:
+       mark_bh(KEYBOARD_BH);
 }
 
 static void put_queue(int ch)
index 371fb300404dedc591004b5703bdebee950068c5..789a332c03536fdf893bceb61484d891254cb777 100644 (file)
@@ -171,7 +171,7 @@ void mouse_baud_detection(unsigned char c)
                        ctr = 0;
                        wait_for_synchron = 1;
                        if(mouse_baud_changing == 1) {
-                               printk("sunmouse: Successfully adjusted to %d baud.\n",
+                               printk(KERN_DEBUG "sunmouse: Successfully adjusted to %d baud.\n",
                                       mouse_baud);
                                mouse_baud_changing = 0;
                        }
index e89384a3a97b54b8f4606514adca3b29a087822b..5331f1bdebb53807304145030cf55bc59bea3e12 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.42 1997/05/26 20:10:20 davem Exp $
+/* $Id: sunserial.c,v 1.43 1997/07/05 09:53:23 davem Exp $
  * serial.c: Serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -348,10 +348,12 @@ static void batten_down_hatches(void)
         */
        printk("\n");
        flush_user_windows();
+#ifndef __sparc_v9__
        if((((unsigned long)linux_dbvec)>=DEBUG_FIRSTVADDR) &&
           (((unsigned long)linux_dbvec)<=DEBUG_LASTVADDR))
                sp_enter_debugger();
        else
+#endif
                prom_cmdline();
 
        /* XXX We want to notify the keyboard driver that all
@@ -396,7 +398,9 @@ static _INLINE_ void rs_sched_event(struct sun_serial *info,
        mark_bh(SERIAL_BH);
 }
 
+#ifndef __sparc_v9__
 extern void breakpoint(void);  /* For the KGDB frame character */
+#endif
 
 static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs)
 {
@@ -453,6 +457,7 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs
                        /* It is a 'keyboard interrupt' ;-) */
                        wake_up(&keypress_wait);
                }
+#ifndef __sparc_v9__
                /* Look for kgdb 'stop' character, consult the gdb
                 * documentation for remote target debugging and
                 * arch/sparc/kernel/sparc-stub.c to see how all this works.
@@ -461,7 +466,7 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs
                        breakpoint();
                        return;
                }
-
+#endif
                if(!tty)
                        return;
 
@@ -1867,7 +1872,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
 
 static void show_serial_version(void)
 {
-       char *revision = "$Revision: 1.42 $";
+       char *revision = "$Revision: 1.43 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
index 7cd6ba4361baee63d4a0363bdeb8ee944e8594ef..10d78a3ae0ac298f4df6cb62469e84b7c3fa6b22 100644 (file)
@@ -27,6 +27,8 @@
 */
 
 
+#include <linux/config.h>
+
 /*
   Define types for some of the structures that interface with the rest
   of the Linux Kernel and SCSI Subsystem.
index 6edd01320855a88d3a8e915f518d7e4149d4ed01..f07d5e2cd839262a6e07874143ffd58455b945a6 100644 (file)
@@ -36,7 +36,7 @@ struct proc_dir_entry proc_scsi_amiga7xx = {
 int amiga7xx_detect(Scsi_Host_Template *tpnt)
 {
     static unsigned char called = 0;
-    int key;
+    int key, clock;
     int num = 0;
     unsigned long address;
     long long options;
@@ -59,8 +59,7 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt)
        clock = 50000000;       /* 50MHz SCSI Clock */
 
        ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000),
-                       0, IRQ_AMIGA_PORTS, DMA_NONE, 
-                       options, clock);
+                       0, IRQ_AMIGA_PORTS, DMA_NONE, options, clock);
 
        zorro_config_board(key, 0);
        num++;
@@ -74,16 +73,16 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt)
 
        clock = 50000000;       /* 50MHz SCSI Clock */
 
-       ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)ZTWO_VADDR(0xDD0040),
-                       0, IRQ_AMIGA_PORTS, DMA_NONE,
-                       options, clock);
+       ncr53c7xx_init(tpnt, 0, 710,
+                      (u32)(unsigned char *)ZTWO_VADDR(0xDD0040),
+                      0, IRQ_AMIGA_PORTS, DMA_NONE, options, clock);
        num++;
     }
 #endif
 
 #ifdef CONFIG_A4091_SCSI
     while ( (key = zorro_find(MANUF_COMMODORE, PROD_A4091, 0, 0)) ||
-        (key = zorro_find(MANUF_COMMODORE2, PROD_A4091_2, 0, 0)) )
+           (key = zorro_find(MANUF_COMMODORE2, PROD_A4091_2, 0, 0)) )
     {
        cd = zorro_get_board(key);
        address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
index 581f280e8fbeffc60c8e31fa3546adf231baef07..e9bdcee9b37dbd07069e4414b1b4237d6164a0b6 100644 (file)
  *                                              [Curtin-1-08-STABLE]
  */
 
+#include <linux/config.h>
+
 /* The following #define is to avoid a clash with hosts.c */
 #define PPA_CODE 1
 #include  "ppa.h"
index a10e9545d4ec0c6a4da57cebfbc305b2385bfac5..bc870dfea727e7fb70d97930a5cd84ea8c210ffe 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
index 7013c3c8df3d2f2548deb8deb1fe0572f42f01d3..a7e4026e85a09c32a81592e87891cedeabc93b68 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef _DEV_TABLE_H_
 #define _DEV_TABLE_H_
 
+#include <linux/config.h>
 
 /*
  * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h)
index 5ea64942536fbc73117ce08f3f34f3c5771d4d45..d9d48401d95d07f0bb5cb3acb409ba281b12d623 100644 (file)
@@ -566,12 +566,12 @@ start_up:
        old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
        if (!old_bh)
                goto end_rename;
-       old_inode = __iget(old_dir->i_sb,old_ino,0);
+       old_inode = __iget(old_dir->i_sb,old_ino);
        if (!old_inode)
                goto end_rename;
        new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
        if (new_bh) {
-               new_inode = __iget(new_dir->i_sb,new_ino,0);
+               new_inode = __iget(new_dir->i_sb,new_ino);
                if (!new_inode) {               /* What does this mean? */
                        affs_brelse(new_bh);
                        new_bh = NULL;
index cc38577aa8cd90e99f996c3ab0e8afcefbc7f6ec..f2bb6c3392ee3b8a24ff4f191c4cc75237b54691 100644 (file)
@@ -69,10 +69,8 @@ static inline int copy_from_user(void *dst, void *src, unsigned long len)
 
 #define AUTOFS_HASH_SIZE 67
 
-typedef u32 autofs_hash_t;     /* Type returned by autofs_hash() */
-
 struct autofs_dir_ent {
-       autofs_hash_t hash;
+       int hash;
        struct autofs_dir_ent *next;
        struct autofs_dir_ent **back;
        char *name;
@@ -94,7 +92,7 @@ struct autofs_wait_queue {
        struct wait_queue *queue;
        struct autofs_wait_queue *next;
        /* We use the following to see what we are waiting for */
-       autofs_hash_t hash;
+       int hash;
        int len;
        char *name;
        /* This is for status reporting upon return */
@@ -151,9 +149,8 @@ void autofs_check_waitlist_integrity(struct autofs_sb_info *,char *);
 
 /* Hash operations */
 
-autofs_hash_t autofs_hash(const char *,int);
 void autofs_initialize_hash(struct autofs_dirhash *);
-struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,autofs_hash_t,const char *,int);
+struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,struct qstr *);
 void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
 void autofs_hash_delete(struct autofs_dir_ent *);
 struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *);
@@ -176,7 +173,7 @@ struct super_block *autofs_read_super(struct super_block *, void *,int);
 
 /* Queue management functions */
 
-int autofs_wait(struct autofs_sb_info *,autofs_hash_t,const char *,int);
+int autofs_wait(struct autofs_sb_info *,struct qstr *);
 int autofs_wait_release(struct autofs_sb_info *,unsigned long,int);
 void autofs_catatonic_mode(struct autofs_sb_info *);
 
index 0f529c900d4da48006b28f3e9a6f22857a98639f..226b180e8d21f4b85f6975fa2ab670244395fe66 100644 (file)
@@ -34,24 +34,11 @@ static int autofs_dir_readdir(struct inode *inode, struct file *filp,
        return 1;
 }
 
-static int autofs_dir_lookup(struct inode *dir, const char *name, int len,
-                             struct inode **result)
+/*
+ * No entries except for "." and "..", both of which are handled by the VFS layer
+ */
+static int autofs_dir_lookup(struct inode *dir, struct qstr *str, struct inode **result)
 {
-       *result = dir;
-       if (!len)
-               return 0;
-       if (name[0] == '.') {
-               if (len == 1)
-                       return 0;
-               if (name[1] == '.' && len == 2) {
-                       /* Return the root directory */
-                       *result = iget(dir->i_sb,AUTOFS_ROOT_INO);
-                       iput(dir);
-                       return 0;
-               }
-       }
-       *result = NULL;
-       iput(dir);
        return -ENOENT;         /* No other entries */
 }
 
index 90c18695a094b5b9170d28cc2a79f8a865be94c2..60a3c6933b238821f1fb1a264441f3ade91caf18 100644 (file)
@@ -48,35 +48,23 @@ struct autofs_dir_ent *autofs_expire(struct autofs_dirhash *dh,
        return (jiffies - ent->last_usage >= timeout) ? ent : NULL;
 }
 
-/* Adapted from the Dragon Book, page 436 */
-/* This particular hashing algorithm requires autofs_hash_t == u32 */
-autofs_hash_t autofs_hash(const char *name, int len)
-{
-       autofs_hash_t h = 0;
-       while ( len-- ) {
-               h = (h << 4) + (unsigned char) (*name++);
-               h ^= ((h & 0xf0000000) >> 24);
-       }
-       return h;
-}
-
 void autofs_initialize_hash(struct autofs_dirhash *dh) {
        memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *));
        dh->expiry_head.exp_next = dh->expiry_head.exp_prev =
                &dh->expiry_head;
 }
 
-struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, autofs_hash_t hash, const char *name, int len)
+struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, struct qstr *name)
 {
        struct autofs_dir_ent *dhn;
 
-       DPRINTK(("autofs_hash_lookup: hash = 0x%08x, name = ", hash));
-       autofs_say(name,len);
+       DPRINTK(("autofs_hash_lookup: hash = 0x%08x, name = ", name->hash));
+       autofs_say(name->name,name->len);
 
-       for ( dhn = dh->h[hash % AUTOFS_HASH_SIZE] ; dhn ; dhn = dhn->next ) {
-               if ( hash == dhn->hash &&
-                    len == dhn->len &&
-                    !memcmp(name, dhn->name, len) )
+       for ( dhn = dh->h[(unsigned) name->hash % AUTOFS_HASH_SIZE] ; dhn ; dhn = dhn->next ) {
+               if ( name->hash == dhn->hash &&
+                    name->len == dhn->len &&
+                    !memcmp(name->name, dhn->name, name->len) )
                        break;
        }
 
@@ -92,7 +80,7 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
 
        autofs_init_usage(dh,ent);
 
-       dhnp = &dh->h[ent->hash % AUTOFS_HASH_SIZE];
+       dhnp = &dh->h[(unsigned) ent->hash % AUTOFS_HASH_SIZE];
        ent->next = *dhnp;
        ent->back = dhnp;
        *dhnp = ent;
index 20ca0907ad9cb0dd39c1efc0640d61d4e28b48b7..5560989a11b1befd01c7af128b45f1d2f09f0839 100644 (file)
@@ -163,7 +163,8 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
         s->s_magic = AUTOFS_SUPER_MAGIC;
         s->s_op = &autofs_sops;
         unlock_super(s);
-        if (!(s->s_mounted = iget(s, AUTOFS_ROOT_INO))) {
+        s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
+        if (!s->s_root) {
                 s->s_dev = 0;
                kfree(sbi);
                 printk("autofs: get root inode failed\n");
@@ -171,8 +172,8 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
                 return NULL;
         }
 
-        if ( parse_options(data,&pipefd,&s->s_mounted->i_uid,&s->s_mounted->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
-               iput(s->s_mounted);
+        if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+               d_delete(s->s_root);
                 s->s_dev = 0;
                kfree(sbi);
                 printk("autofs: called with bogus options\n");
@@ -181,7 +182,7 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
         }
 
        if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
-               iput(s->s_mounted);
+               d_delete(s->s_root);
                s->s_dev = 0;
                kfree(sbi);
                printk("autofs: kernel does not match daemon version\n");
@@ -198,7 +199,7 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
                } else {
                        printk("autofs: could not open pipe file descriptor\n");
                }
-               iput(s->s_mounted);
+               d_delete(s->s_root);
                s->s_dev = 0;
                kfree(sbi);
                MOD_DEC_USE_COUNT;
@@ -244,8 +245,8 @@ static void autofs_read_inode(struct inode *inode)
                 return;
         } 
        
-        inode->i_uid = inode->i_sb->s_mounted->i_uid;
-        inode->i_gid = inode->i_sb->s_mounted->i_gid;
+        inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
+        inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
         
        if ( ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO ) {
                /* Symlink inode - should be in symlink list */
index a615ede2903de0ac37db1ef48847421679e0e224..30c9e41b05ce011814abd9f93ed54e5d08aa96cb 100644 (file)
 #include "autofs_i.h"
 
 static int autofs_root_readdir(struct inode *,struct file *,void *,filldir_t);
-static int autofs_root_lookup(struct inode *,const char *,int,struct inode **);
-static int autofs_root_symlink(struct inode *,const char *,int,const char *);
-static int autofs_root_unlink(struct inode *,const char *,int);
-static int autofs_root_rmdir(struct inode *,const char *,int);
-static int autofs_root_mkdir(struct inode *,const char *,int,int);
+static int autofs_root_lookup(struct inode *,struct qstr *,struct inode **);
+static int autofs_root_symlink(struct inode *,struct dentry *,const char *);
+static int autofs_root_unlink(struct inode *,struct dentry *);
+static int autofs_root_rmdir(struct inode *,struct dentry *);
+static int autofs_root_mkdir(struct inode *,struct dentry *,int);
 static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
 
 static struct file_operations autofs_root_operations = {
@@ -48,6 +48,7 @@ struct inode_operations autofs_root_inode_operations = {
         NULL,                   /* mknod */
         NULL,                   /* rename */
         NULL,                   /* readlink */
+        NULL,                   /* follow_link */
         NULL,                   /* readpage */
         NULL,                   /* writepage */
         NULL,                   /* bmap */
@@ -92,95 +93,70 @@ static int autofs_root_readdir(struct inode *inode, struct file *filp,
        return 0;
 }
 
-static int autofs_root_lookup(struct inode *dir, const char *name, int len,
-                             struct inode **result)
+static int autofs_root_lookup(struct inode *dir, struct qstr *str, struct inode **result)
 {
        struct autofs_sb_info *sbi;
        struct autofs_dir_ent *ent;
        struct inode *res;
-       autofs_hash_t hash;
        int status, oz_mode;
 
        DPRINTK(("autofs_root_lookup: name = "));
-       autofs_say(name,len);
+       autofs_say(str->name,str->len);
 
        *result = NULL;
        if (!dir)
                return -ENOENT;
-       if (!S_ISDIR(dir->i_mode)) {
-               iput(dir);
+       if (!S_ISDIR(dir->i_mode))
                return -ENOTDIR;
-       }
-
-       /* Handle special cases: . and ..; since this is a root directory,
-          they both point to the inode itself */
-       *result = dir;
-       if (!len)
-               return 0;
-       if (name[0] == '.') {
-               if (len == 1)
-                       return 0;
-               if (name[1] == '.' && len == 2)
-                       return 0;
-       }
 
        *result = res = NULL;
        sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
 
-       hash = autofs_hash(name,len);
-
        oz_mode = autofs_oz_mode(sbi);
        DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n", current->pid, current->pgrp, sbi->catatonic, oz_mode));
 
        do {
-               while ( !(ent = autofs_hash_lookup(&sbi->dirhash,hash,name,len)) ) {
+               while ( !(ent = autofs_hash_lookup(&sbi->dirhash,str)) ) {
                        DPRINTK(("lookup failed, pid = %u, pgrp = %u\n", current->pid, current->pgrp));
                        
-                       if ( oz_mode ) {
-                               iput(dir);
+                       if ( oz_mode )
                                return -ENOENT;
-                       } else {
-                               status = autofs_wait(sbi,hash,name,len);
-                               DPRINTK(("autofs_wait returned %d\n", status));
-                               if ( status ) {
-                                       iput(dir);
-                                       return status;
-                               }
-                       }
+                       up(&dir->i_sem);
+                       status = autofs_wait(sbi,str);
+                       down(&dir->i_sem);
+                       DPRINTK(("autofs_wait returned %d\n", status));
+                       if ( status )
+                               return status;
                }
 
                DPRINTK(("lookup successful, inode = %08x\n", (unsigned int)ent->ino));
 
                if (!(res = iget(dir->i_sb,ent->ino))) {
                        printk("autofs: iget returned null!\n");
-                       iput(dir);
                        return -EACCES;
                }
                
                if ( !oz_mode && S_ISDIR(res->i_mode) && res->i_sb == dir->i_sb ) {
                        /* Not a mount point yet, call 1-800-DAEMON */
                        DPRINTK(("autofs: waiting on non-mountpoint dir, inode = %lu, pid = %u, pgrp = %u\n", res->i_ino, current->pid, current->pgrp));
-                       iput(res);
                        res = NULL;
-                       status = autofs_wait(sbi,hash,name,len);
-                       if ( status ) {
-                               iput(dir);
+                       up(&dir->i_sem);
+                       status = autofs_wait(sbi,str);
+                       down(&dir->i_sem);
+                       if ( status )
                                return status;
-                       }
                }
        } while(!res);
        autofs_update_usage(&sbi->dirhash,ent);
        
        *result = res;
-       iput(dir);
        return 0;
 }
 
-static int autofs_root_symlink(struct inode *dir, const char *name, int len, const char *symname)
+static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
        struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
        struct autofs_dirhash *dh = &sbi->dirhash;
-       autofs_hash_t hash = autofs_hash(name,len);
        struct autofs_dir_ent *ent;
        unsigned int n;
        int slsize;
@@ -189,70 +165,64 @@ static int autofs_root_symlink(struct inode *dir, const char *name, int len, con
        DPRINTK(("autofs_root_symlink: %s <- ", symname));
        autofs_say(name,len);
 
-       if ( !autofs_oz_mode(sbi) ) {
-               iput(dir);
+       if ( !autofs_oz_mode(sbi) )
                return -EPERM;
-       }
-       if ( autofs_hash_lookup(dh,hash,name,len) ) {
-               iput(dir);
+
+       if ( autofs_hash_lookup(dh, &dentry->d_name) )
                return -EEXIST;
-       }
+
        n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS);
-       if ( n >= AUTOFS_MAX_SYMLINKS ) {
-               iput(dir);
+       if ( n >= AUTOFS_MAX_SYMLINKS )
                return -ENOSPC;
-       }
+
        set_bit(n,sbi->symlink_bitmap);
        sl = &sbi->symlink[n];
        sl->len = strlen(symname);
        sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL);
        if ( !sl->data ) {
                clear_bit(n,sbi->symlink_bitmap);
-               iput(dir);
                return -ENOSPC;
        }
+
        ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
        if ( !ent ) {
                kfree(sl->data);
                clear_bit(n,sbi->symlink_bitmap);
-               iput(dir);
                return -ENOSPC;
        }
-       ent->name = kmalloc(len, GFP_KERNEL);
+
+       ent->name = kmalloc(dentry->d_name.len, GFP_KERNEL);
        if ( !ent->name ) {
                kfree(sl->data);
                kfree(ent);
                clear_bit(n,sbi->symlink_bitmap);
-               iput(dir);
                return -ENOSPC;
        }
+
        memcpy(sl->data,symname,slsize);
        sl->mtime = CURRENT_TIME;
 
        ent->ino = AUTOFS_FIRST_SYMLINK + n;
-       ent->hash = hash;
-       memcpy(ent->name,name,ent->len = len);
+       ent->hash = dentry->d_name.hash;
+       memcpy(ent->name, dentry->d_name.name,ent->len = dentry->d_name.len);
 
        autofs_hash_insert(dh,ent);
-       iput(dir);
+       d_instantiate(dentry, iget(dir->i_sb,ent->ino), 0);
 
        return 0;
 }
 
-static int autofs_root_unlink(struct inode *dir, const char *name, int len)
+static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
        struct autofs_dirhash *dh = &sbi->dirhash;
-       autofs_hash_t hash = autofs_hash(name,len);
        struct autofs_dir_ent *ent;
        unsigned int n;
 
-       iput(dir);              /* Nothing below can sleep */
-
        if ( !autofs_oz_mode(sbi) )
                return -EPERM;
 
-       ent = autofs_hash_lookup(dh,hash,name,len);
+       ent = autofs_hash_lookup(dh, &dentry->d_name);
        if ( !ent )
                return -ENOENT;
 
@@ -263,75 +233,68 @@ static int autofs_root_unlink(struct inode *dir, const char *name, int len)
        autofs_hash_delete(ent);
        clear_bit(n,sbi->symlink_bitmap);
        kfree(sbi->symlink[n].data);
+       d_delete(dentry);
        
        return 0;
 }
 
-static int autofs_root_rmdir(struct inode *dir, const char *name, int len)
+static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry)
 {
        struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
        struct autofs_dirhash *dh = &sbi->dirhash;
-       autofs_hash_t hash = autofs_hash(name,len);
        struct autofs_dir_ent *ent;
 
-       if ( !autofs_oz_mode(sbi) ) {
-               iput(dir);
+       if ( !autofs_oz_mode(sbi) )
                return -EPERM;
-       }
-       ent = autofs_hash_lookup(dh,hash,name,len);
-       if ( !ent ) {
-               iput(dir);
+
+       ent = autofs_hash_lookup(dh, &dentry->d_name);
+       if ( !ent )
                return -ENOENT;
-       }
-       if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO ) {
-               iput(dir);
+
+       if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO )
                return -ENOTDIR; /* Not a directory */
-       }
+
        autofs_hash_delete(ent);
        dir->i_nlink--;
-       iput(dir);
+       d_delete(dentry);
 
        return 0;
 }
 
-static int autofs_root_mkdir(struct inode *dir, const char *name, int len, int mode)
+static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
        struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
        struct autofs_dirhash *dh = &sbi->dirhash;
-       autofs_hash_t hash = autofs_hash(name,len);
        struct autofs_dir_ent *ent;
 
-       if ( !autofs_oz_mode(sbi) ) {
-               iput(dir);
+       if ( !autofs_oz_mode(sbi) )
                return -EPERM;
-       }
-       ent = autofs_hash_lookup(dh,hash,name,len);
-       if ( ent ) {
-               iput(dir);
+
+       ent = autofs_hash_lookup(dh, &dentry->d_name);
+       if ( ent )
                return -EEXIST;
-       }
+
        if ( sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO ) {
                printk("autofs: Out of inode numbers -- what the heck did you do??\n");
-               iput(dir);
                return -ENOSPC;
        }
+
        ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
-       if ( !ent ) {
-               iput(dir);
+       if ( !ent )
                return -ENOSPC;
-       }
-       ent->name = kmalloc(len, GFP_KERNEL);
+
+       ent->name = kmalloc(dentry->d_name.len, GFP_KERNEL);
        if ( !ent->name ) {
                kfree(ent);
-               iput(dir);
                return -ENOSPC;
        }
-       ent->hash = hash;
-       memcpy(ent->name, name, ent->len = len);
+
+       ent->hash = dentry->d_name.hash;
+       memcpy(ent->name, dentry->d_name.name, ent->len = dentry->d_name.len);
        ent->ino = sbi->next_dir_ino++;
        autofs_hash_insert(dh,ent);
        dir->i_nlink++;
-       iput(dir);
+       d_instantiate(dentry, iget(dir->i_sb,ent->ino), D_DIR);
 
        return 0;
 }
index d6ac82ed40ace94ef6e712f200b94a53beede039..e3ff3d31bec00dc00732af7a1a70deae78a6a828 100644 (file)
@@ -19,18 +19,21 @@ static int autofs_readlink(struct inode *inode, char *buffer, int buflen)
        struct autofs_symlink *sl;
        int len;
 
-       if (!S_ISLNK(inode->i_mode)) {
-               iput(inode);
-               return -EINVAL;
-       }
        sl = (struct autofs_symlink *)inode->u.generic_ip;
        len = sl->len;
        if (len > buflen) len = buflen;
        copy_to_user(buffer,sl->data,len);
-       iput(inode);
        return len;
 }
 
+static struct dentry * autofs_follow_link(struct inode *inode, struct dentry *base)
+{
+       struct autofs_symlink *sl;
+
+       sl = (struct autofs_symlink *)inode->u.generic_ip;
+       return lookup_dentry(sl->data, base, 1);
+}
+
 struct inode_operations autofs_symlink_inode_operations = {
        NULL,                   /* file operations */
        NULL,                   /* create */
@@ -43,6 +46,7 @@ struct inode_operations autofs_symlink_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        autofs_readlink,        /* readlink */
+       autofs_follow_link,     /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
index cbe270a5338eb7ddea1b5d3f16ccbd6ebb4e4cad..ec222d61cd2a04617c8150d9b617a2a3db2b7ebe 100644 (file)
@@ -90,15 +90,15 @@ static void autofs_notify_daemon(struct autofs_sb_info *sbi, struct autofs_wait_
                autofs_catatonic_mode(sbi);
 }
 
-int autofs_wait(struct autofs_sb_info *sbi, autofs_hash_t hash, const char *name, int len)
+int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name)
 {
        struct autofs_wait_queue *wq;
        int status;
 
        for ( wq = sbi->queues ; wq ; wq = wq->next ) {
-               if ( wq->hash == hash &&
-                    wq->len == len &&
-                    wq->name && !memcmp(wq->name,name,len) )
+               if ( wq->hash == name->hash &&
+                    wq->len == name->len &&
+                    wq->name && !memcmp(wq->name,name->name,name->len) )
                        break;
        }
        
@@ -108,17 +108,17 @@ int autofs_wait(struct autofs_sb_info *sbi, autofs_hash_t hash, const char *name
                if ( !wq )
                        return -ENOMEM;
 
-               wq->name = kmalloc(len,GFP_KERNEL);
+               wq->name = kmalloc(name->len,GFP_KERNEL);
                if ( !wq->name ) {
                        kfree(wq);
                        return -ENOMEM;
                }
                wq->wait_queue_token = autofs_next_wait_queue++;
                init_waitqueue(&wq->queue);
-               wq->hash = hash;
-               wq->len = len;
+               wq->hash = name->hash;
+               wq->len = name->len;
                wq->status = -EINTR; /* Status return if interrupted */
-               memcpy(wq->name, namelen);
+               memcpy(wq->name, name->name, name->len);
                wq->next = sbi->queues;
                sbi->queues = wq;
 
index a097e804ffba185b353c1e30f95478f2a76cf68c..f62a001916cd71359e959bc49b01c4df632056eb 100644 (file)
@@ -111,23 +111,20 @@ create_elf_tables(char *p, int argc, int envc,
 {
        elf_caddr_t *argv;
        elf_caddr_t *envp;
-       elf_addr_t *sp;
+       elf_addr_t *sp, *csp;
 
        /*
-        * Force 16 byte alignment here for generality.
+        * Force 16 byte _final_ alignment here for generality.
         */
        sp = (elf_addr_t *) (~15UL & (unsigned long) p);
-#ifdef __sparc__
-{
-       elf_addr_t *csp;
        csp = sp;
        csp -= exec ? DLINFO_ITEMS*2 : 2;
        csp -= envc+1;
        csp -= argc+1;
-       if (!(((unsigned long) csp) & 4))
-               sp--;
-}
-#endif
+       csp -= (!ibcs ? 3 : 1); /* argc itself */
+       if ((unsigned long)csp & 15UL) {
+               sp -= (16UL - ((unsigned long)csp & 15UL)) / sizeof(*sp);
+       }
 
        /*
         * Put the ELF interpreter info on the stack
@@ -142,17 +139,17 @@ create_elf_tables(char *p, int argc, int envc,
        if (exec) {
                sp -= 11*2;
 
-         NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
-         NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
-         NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
-         NEW_AUX_ENT (3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
-         NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
-         NEW_AUX_ENT (5, AT_FLAGS, 0);
-         NEW_AUX_ENT (6, AT_ENTRY, (elf_addr_t) exec->e_entry);
-         NEW_AUX_ENT (7, AT_UID, (elf_addr_t) current->uid);
-         NEW_AUX_ENT (8, AT_EUID, (elf_addr_t) current->euid);
-         NEW_AUX_ENT (9, AT_GID, (elf_addr_t) current->gid);
-         NEW_AUX_ENT (10, AT_EGID, (elf_addr_t) current->egid);
+               NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
+               NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
+               NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
+               NEW_AUX_ENT (3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
+               NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
+               NEW_AUX_ENT (5, AT_FLAGS, 0);
+               NEW_AUX_ENT (6, AT_ENTRY, (elf_addr_t) exec->e_entry);
+               NEW_AUX_ENT (7, AT_UID, (elf_addr_t) current->uid);
+               NEW_AUX_ENT (8, AT_EUID, (elf_addr_t) current->euid);
+               NEW_AUX_ENT (9, AT_GID, (elf_addr_t) current->gid);
+               NEW_AUX_ENT (10, AT_EGID, (elf_addr_t) current->egid);
        }
 #undef NEW_AUX_ENT
 
index 28dced39472303f0f6c83950041fcd194598fe7e..5ef090761bb5032f3a7c3fd75f4426b1452cab4b 100644 (file)
@@ -7,9 +7,11 @@
  *  a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
  *  binfmt_mz.
  *
- *  25.4.97 first version
- *    [...]
- *  19.5.97 cleanup
+ *  1997-04-25 first version
+ *  [...]
+ *  1997-05-19 cleanup
+ *  1997-06-26 hpa: pass the real filename rather than argv[0]
+ *  1997-06-30 minor cleanup
  */
 
 #include <linux/module.h>
@@ -85,7 +87,6 @@ static void clear_entry(int id)
                *ep = e->next;
                entry_proc_cleanup(e);
                kfree(e);
-               MOD_DEC_USE_COUNT;
        }
        write_unlock(&entries_lock);
 }
@@ -102,7 +103,6 @@ static void clear_entries(void)
                entries = entries->next;
                entry_proc_cleanup(e);
                kfree(e);
-               MOD_DEC_USE_COUNT;
        }
        write_unlock(&entries_lock);
 }
@@ -161,7 +161,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        char *iname_addr = iname, *p;
        int retval, fmt_flags = 0;
 
-       MOD_INC_USE_COUNT;
        if (!enabled) {
                retval = -ENOEXEC;
                goto _ret;
@@ -185,12 +184,11 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 
        /* Build args for interpreter */
        if ((fmt_flags & ENTRY_STRIP_EXT) &&
-           (p = strrchr(bprm->filename, '.'))) {
+           (p = strrchr(bprm->filename, '.')))
                *p = '\0';
-               remove_arg_zero(bprm);
-               bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
-               bprm->argc++;
-       }
+       remove_arg_zero(bprm);
+       bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
+       bprm->argc++;
        bprm->p = copy_strings(1, &iname_addr, bprm->page, bprm->p, 2);
        bprm->argc++;
        if (!bprm->p) {
@@ -206,7 +204,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        if ((retval = prepare_binprm(bprm)) >= 0)
                retval = search_binary_handler(bprm, regs);
 _ret:
-       MOD_DEC_USE_COUNT;
        return retval;
 }
 
@@ -265,18 +262,13 @@ static int proc_write_register(struct file *file, const char *buffer,
        struct binfmt_entry *e;
        int memsize, cnt = count - 1, err = 0;
 
-       MOD_INC_USE_COUNT;
        /* some sanity checks */
-       if ((count < 11) || (count > 256)) {
-               err = -EINVAL;
-               goto _err;
-       }
+       if ((count < 11) || (count > 256))
+               return -EINVAL;
 
        memsize = sizeof(struct binfmt_entry) + count;
-       if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
-               err = -ENOMEM;
-               goto _err;
-       }
+       if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
+               return -ENOMEM;
 
        sp = buffer + 1;
        del = buffer[0];
@@ -313,8 +305,7 @@ static int proc_write_register(struct file *file, const char *buffer,
            !(e->proc_name) || !(e->interpreter) ||
            entry_proc_setup(e)) {
                kfree(e);
-               err = -EINVAL;
-               goto _err;
+               return -EINVAL;
        }
 
        write_lock(&entries_lock);
@@ -323,9 +314,6 @@ static int proc_write_register(struct file *file, const char *buffer,
        write_unlock(&entries_lock);
 
        return count;
-_err:
-       MOD_DEC_USE_COUNT;
-       return err;
 }
 
 /*
@@ -340,7 +328,6 @@ static int proc_read_status(char *page, char **start, off_t off,
        char *dp;
        int elen, i;
 
-       MOD_INC_USE_COUNT;
 #ifndef VERBOSE_STATUS
        if (data) {
                read_lock(&entries_lock);
@@ -400,7 +387,6 @@ _out:
        *eof = (elen <= count) ? 1 : 0;
        *start = page + off;
 
-       MOD_DEC_USE_COUNT;
        return elen;
 }
 
@@ -414,7 +400,6 @@ static int proc_write_status(struct file *file, const char *buffer,
        struct binfmt_entry *e;
        int res = count;
 
-       MOD_INC_USE_COUNT;
        if (((buffer[0] == '1') || (buffer[0] == '0')) &&
            ((count == 1) || ((count == 2) && (buffer[1] == '\n')))) {
                if (data) {
@@ -434,7 +419,6 @@ static int proc_write_status(struct file *file, const char *buffer,
        } else {
                res = -EINVAL;
        }
-       MOD_DEC_USE_COUNT;
        return res;
 }
 
@@ -499,6 +483,7 @@ void cleanup_module(void)
        unregister_binfmt(&misc_format);
        remove_proc_entry("register", bm_dir);
        remove_proc_entry("status", bm_dir);
+       clear_entries();
        remove_proc_entry("sys/fs/binfmt_misc", NULL);
 }
 #endif
index 87b6470273d9dd86401b6ca8d2f8b5eff2706354..96f47d2630584ab3662ea275fd369bdadca9aad6 100644 (file)
@@ -1612,6 +1612,7 @@ asmlinkage int sync_old_buffers(void)
                                 next->b_count--;
                         }
        }
+       run_task_queue(&tq_disk);
 #ifdef DEBUG
        if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
        printk("Wrote %d/%d buffers\n", nwritten, ndirty);
index dcf4c46a6ec35628003004845e9718179abb73b3..3b9697c29534f72ea0a117cb332d9f72916b8844 100644 (file)
@@ -5,67 +5,14 @@
  * (C) 1997 Thomas Schoebel-Theuer
  */
 
-/* The new dcache is exclusively called from the VFS, not from
- * the specific fs'es any more. Despite having the same name as in the
- * old code, it has less to do with it.
- *
- * It serves many purposes:
- *
- *  1) Any inode that has been retrieved with lookup() and is in use
- *     (i_count>0), has access to its full absolute path name, by going
- *     to inode->i_dentry and then recursively following the entry->d_parent
- *     chain. Use d_path() as predefined method for that.
- *     You may find out the corresponding inode belonging to
- *     a dentry by calling d_inode(). This can be used as an easy way for
- *     determining .. and its absolute pathname, an old UNIX problem that
- *     deserved a solution for a long time.
- *     Note that hardlinked inodes may have multiple dentries assigned to
- *     (via the d_next chain), reflecting multiple alias pathnames.
- *
- *  2) If not disabled by filesystem types specifying FS_NO_DCACHE,
- *     the dentries of unused (aged) inodes are retained for speeding up
- *     lookup()s, by allowing hashed inquiry starting from the dentry of
- *     the parent directory.
- *
- *  3) It can remeber so-called "negative entries", that is dentries for
- *     pathnames that are known to *not* exist, so unneccessary repeated
- *     lookup()s for non-existant names can be saved.
- *
- *  4) It provides a means for keeping deleted files (inode->i_nlink==0)
- *     accessible in the so-called *basket*. Inodes in the basket have been
- *     removed with unlink() while being in use (i_count>0), so they would
- *     normally use up space on the disk and be accessile through their
- *     filedescriptor, but would not be accessible for lookup() any more.
- *     The basket simply keeps such files in the dcache (for potential
- *     dcache lookup) until they are either eventually removed completely,
- *     or transferred to the second-level basket, the so-called *ibasket*.
- *     The ibasket is implemented in the new inode code, on request of
- *     filesystem types that have the flag FS_IBASKET set, and proliferates
- *     the unlinked files when i_count has gone to zero, at least as long
- *     as there is space on the disk and enough inodes remain available
- *     and no umount() has started.
- *
- *  5) Preliminary dentries can be added by readdir(). While normal dentries
- *     directly point to the inode via u.d_inode only the inode number is
- *     known from readdir(), but not more. They can be converted to
- *     normal dentries by using d_inode().
- */
-
 /*
  * Notes on the allocation strategy:
  *
- * The dcache is a full slave cache of the inodes. Whenever an inode
- * is cleared, all the dentries associated with it will recursively
- * disappear. dentries have no own reference counting; this has to
- * be obeyed for SMP.
- * If directories could go out of inode cache while
- * successors are alive, this would interrupt the d_parent chain of
- * the live successors. To prevent this without using zombies, all
- * directories are thus prevented from __iput() as long as successors
- * are alive.
+ * The dcache is a master of the icache - whenever a dcache entry
+ * exists, the inode will always exist. "iput()" is done either when
+ * the dcache entry is deleted or garbage collected.
  */
 
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/malloc.h>
 
 /* this should be removed after the beta phase */
-/* #define DEBUG */
+/*#define DEBUG*/
 /*#undef DEBUG*/
-/* #define DEBUG_DDIR_COUNT */
-
-#define D_HASHSIZE   64
+/*#define DEBUG_DDIR_COUNT*/
 
-/* local flags for d_flag */
-#define D_DIR          32
-#define D_HASHED       64
-#define D_ZOMBIE      128
-#define D_PRELIMINARY 256
-#define D_INC_DDIR    512
-
-/* local flags for d_del() */
-#define D_RECURSIVE 4
-#define D_NO_FREE   8
-
-/* This is only used for directory dentries. Think of it as an extension
- * of the dentry.
- * It is defined as separate struct, so it uses up space only
- * where necessary.
- */
-struct ddir {
-       struct dentry * dd_hashtable[D_HASHSIZE];
-       struct dentry * dd_neglist;
-       struct dentry * dd_basketlist;
-       struct dentry * dd_zombielist;
-       unsigned short dd_alloced; /* # d_alloc()ed, but not yet d_add()ed */
-       unsigned short dd_hashed;  /* # of entries in hashtable */
-       unsigned short dd_true_hashed; /* # non-preliminaries in hashtable */
-       unsigned short dd_negs; /* # of negative entries */
-};
+void printpath(struct dentry * entry);
 
 DEF_INSERT(alias,struct dentry,d_next,d_prev)
 DEF_REMOVE(alias,struct dentry,d_next,d_prev)
@@ -113,11 +33,28 @@ DEF_REMOVE(alias,struct dentry,d_next,d_prev)
 DEF_INSERT(hash,struct dentry,d_hash_next,d_hash_prev)
 DEF_REMOVE(hash,struct dentry,d_hash_next,d_hash_prev)
 
-DEF_INSERT(basket,struct dentry,d_basket_next,d_basket_prev)
-DEF_REMOVE(basket,struct dentry,d_basket_next,d_basket_prev)
-
 struct dentry * the_root = NULL;
 
+/*
+ * This is the single most critical data structure when it comes
+ * to the dcache: the hashtable for lookups. Somebody should try
+ * to make this good - I've just made it work.
+ *
+ * This hash-function tries to avoid losing too many bits of hash
+ * information, yet avoid using a prime hash-size or similar.
+ */
+#define D_HASHBITS     10
+#define D_HASHSIZE     (1UL << D_HASHBITS)
+#define D_HASHMASK     (D_HASHSIZE-1)
+struct dentry * dentry_hashtable[D_HASHSIZE];
+
+static inline unsigned long dentry_hash(struct dentry *dir, int name_hash)
+{
+       unsigned long hash = name_hash + (unsigned long) dir;
+       hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
+       return hash & D_HASHMASK;
+}
+
 unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end)
 {
        return mem_start;
@@ -142,7 +79,7 @@ static void ins(void* ptr)
         if(cnt % 1000 == 0)
                printk("------%d allocated: %d: %d %d %d\n", inodes_stat, cnt,
                       x_alloc, x_freed, x_free);
-       if(cnt>=20000) panic("stop");
+       if (cnt>=20000) panic("stop");
 }
 
 #if 0
@@ -150,7 +87,7 @@ static inline int search(void* ptr)
 {
        int i;
        for(i = cnt-1; i>=0; i--)
-               if(tst[i] == ptr)
+               if (tst[i] == ptr)
                        return i;
        return -1;
 }
@@ -163,55 +100,18 @@ static inline int search(void* ptr)
 void LOG(char * txt, struct dentry * entry)
 {
        static int count = 0;
-       if(entry) {
+       if (entry) {
                TST(txt,entry);
        }
-       if(count) {
+       if (count) {
                count--;
                printk("%s: entry=%p\n", txt, entry);
        }
 }
 
 #ifdef DEBUG_DDIR_COUNT
-static struct ddir * d_dir(struct dentry * entry);
 void recursive_test(struct dentry * entry)
 {
-       int i;
-       struct ddir * ddir = d_dir(entry);
-       int sons = 0;
-
-       if(ddir->dd_zombielist)
-               sons++;
-       for(i=0; i < D_HASHSIZE; i++) {
-               struct dentry ** base = &ddir->dd_hashtable[i];
-               struct dentry * tmp = *base;
-               if(tmp) do {
-                       TST("__clear",tmp);
-                       if(!(tmp->d_flag & D_HASHED)) {
-                               printk("VFS: dcache entry not hashed!\n");
-                               printpath(*base); printk("\n");
-                               printpath(tmp);
-                       }
-                       if(!(tmp->d_flag & D_PRELIMINARY))
-                               sons++;
-                       if(tmp->d_flag & D_DIR)
-                               recursive_test(tmp);
-                       tmp = tmp->d_hash_next;
-               } while(tmp && tmp != *base);
-       }
-       if(!sons && !(entry->d_flag & D_PRELIMINARY) && entry->u.d_inode) {
-               struct inode * inode = entry->u.d_inode;
-               if(!atomic_read(&inode->i_count)) {
-                       if(!(inode->i_status & 1/*ST_AGED*/)) {
-                               printpath(entry);
-                               printk(" is not aged!\n");
-                       }
-                       if(inode->i_ddir_count) {
-                               printpath(entry);
-                               printk(" has ddir_count blockage!\n");
-                       }
-               }
-       }
 }
 #else
 #define recursive_test(e) /*nothing*/
@@ -226,604 +126,280 @@ void recursive_test(struct dentry * entry)
 
 void printpath(struct dentry * entry)
 {
-       if(!IS_ROOT(entry))
+       if (!IS_ROOT(entry))
                printpath(entry->d_parent);
        printk("/%s", entry->d_name.name);
 }
 
-static inline long has_sons(struct ddir * ddir)
-{
-       return ((ddir->dd_alloced | ddir->dd_hashed)    ||
-               ddir->dd_neglist                        ||
-               ddir->dd_basketlist                     ||
-               ddir->dd_zombielist);
-}
-
-static inline int has_true_sons(struct ddir * ddir)
-{
-       return (ddir->dd_alloced | ddir->dd_true_hashed);
-}
-
-/* Only hold the i_ddir_count pseudo refcount when neccessary (i.e. when
- * they have true_sons), to prevent keeping too much dir inodes in use.
- */
-static inline void inc_ddir(struct dentry * entry, struct inode * inode)
-{
-       if(!(entry->d_flag & D_INC_DDIR)) {
-               entry->d_flag |= D_INC_DDIR;
-#ifdef DEBUG
-               if(inode->i_ddir_count) {
-                       printpath(entry);
-                       printk(" ddir_count=%d\n", inode->i_ddir_count);
-               }
-#endif
-               inode->i_ddir_count++;
-               _get_inode(inode);
-       }
-}
-
-static inline blocking void dec_ddir(struct dentry * entry, struct inode * inode)
+void d_free(struct dentry *dentry)
 {
-       if(entry->d_flag & D_INC_DDIR) {
-               entry->d_flag &= ~D_INC_DDIR;
-               inode->i_ddir_count--;
-               if(!inode->i_ddir_count)
-                       __iput(inode);
+       if (dentry) {
+               kfree(dentry->d_name.name);
+               kfree(dentry);
        }
 }
 
-/* Do not inline this many times. */
-static void d_panic(void)
-{
-       panic("VFS: dcache directory corruption");
-}
-
-/*
- * IF this is a directory, the ddir has been allocated right
- * after the dentry.
- */
-static inline struct ddir * d_dir(struct dentry * entry)
-{
-       if(!(entry->d_flag & D_DIR))
-               d_panic();
-       return (struct ddir *) (entry+1);
-}
-
 #define NAME_ALLOC_LEN(len)    ((len+16) & ~15)
 
-struct dentry * d_alloc(struct dentry * parent, int len, int isdir)
+struct dentry * d_alloc(struct dentry * parent, struct qstr *name, int isdir)
 {
+       char *str;
        struct dentry *res;
-       int size = sizeof(struct dentry);
-       int flag = 0;
 
-       if (isdir) {
-               size += sizeof(struct ddir);
-               flag = D_DIR;
-       }
-       res = kmalloc(size, GFP_KERNEL);
+       res = kmalloc(sizeof(struct dentry), GFP_KERNEL);
        if (!res)
                return NULL;
-       memset(res, 0, size);
-       res->d_flag = flag;
 
-       res->d_name.name = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL);
-       if (!res->d_name.name) {
+       str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);
+       if (!str) {
                kfree(res);
                return NULL;
        }
        
-       res->d_name.len = len;
+       memcpy(str, name->name, name->len);
+       str[name->len] = 0;
+
+       memset(res, 0, sizeof(struct dentry));
+
        res->d_parent = parent;
-       if(parent) {
-               struct ddir * pdir = d_dir(parent);
-#ifdef DEBUG
-               if(pdir->dd_alloced > 1 && !IS_ROOT(parent)) {
-                       printpath(parent);
-                       printk(" dd_alloced=%d\n", pdir->dd_alloced);
-               }
-#endif
-               pdir->dd_alloced++;
-       }
+       res->d_mounts = res;
+       res->d_covers = res;
+       res->d_flag = isdir ? D_DIR : 0;
+
+       res->d_name.name = str;
+       res->d_name.len = name->len;
+       res->d_name.hash = name->hash;
+
 #ifdef DEBUG
        x_alloc++;
 #endif
        return res;
 }
 
-extern blocking struct dentry * d_alloc_root(struct inode * root_inode)
+extern blocking struct dentry * d_alloc_root(struct inode * root_inode, struct dentry *old_root)
 {
-       struct dentry * res = the_root;
+       struct dentry *res;
+       struct qstr name = { "/", 1, 0 };       /* dummy qstr */
 
-       if(res) {
-               d_del(res, D_NO_CLEAR_INODE); /* invalidate everything beyond */
-       } else {
-               struct ddir * ddir;
-
-               the_root = res = d_alloc(NULL, 0, 1);
-               LOG("d_alloc_root", res);
-               res->d_parent = res;
-               res->d_name.name[0]='\0';
-               ddir = d_dir(res);
-               ddir->dd_alloced = 999; /* protect from deletion */
-       }
-       insert_alias(&root_inode->i_dentry, res);
-       root_inode->i_dent_count++;
-       root_inode->i_ddir_count++;
-       res->u.d_inode = root_inode;
+       if (!root_inode)
+               return NULL;
+       res = d_alloc(NULL, &name, 1);
+       LOG("d_alloc_root", res);
+       res->d_parent = res;
+       d_instantiate(res, root_inode, D_DIR);
        return res;
 }
 
-static inline unsigned long d_hash(char first, char last)
-{
-       return ((unsigned long)first ^ ((unsigned long)last << 4)) & (D_HASHSIZE-1);
-}
-
-static inline struct dentry ** d_base_entry(struct ddir * pdir, struct dentry * entry)
+static inline struct dentry ** d_base_qstr(struct dentry * parent, struct qstr * s)
 {
-       return &pdir->dd_hashtable[d_hash(entry->d_name.name[0],
-                                         entry->d_name.name[entry->d_name.len-1])];
+       return dentry_hashtable + dentry_hash(parent, s->hash);
 }
 
-static inline struct dentry ** d_base_qstr(struct ddir * pdir,
-                                          struct qstr * s1,
-                                          struct qstr * s2)
+static inline struct dentry ** d_base_entry(struct dentry * pdir, struct dentry * entry)
 {
-       unsigned long hash;
-
-       if(s2 && s2->len) {
-               hash = d_hash(s1->name[0], s2->name[s2->len-1]);
-       } else {
-               hash = d_hash(s1->name[0], s1->name[s1->len-1]);
-       }
-       return &pdir->dd_hashtable[hash];
+       return d_base_qstr(pdir, &entry->d_name);
 }
 
 
 static /*inline*/ blocking void _d_remove_from_parent(struct dentry * entry,
-                                                     struct ddir * pdir,
-                                                     struct inode * inode,
-                                                     int flags)
+                                                     struct dentry * parent)
 {
-       if(entry->d_flag & D_HASHED) {
-               struct dentry ** base = d_base_entry(pdir, entry);
+       if (entry->d_flag & D_HASHED) {
+               struct dentry ** base = d_base_entry(parent, entry);
 
                remove_hash(base, entry);
                entry->d_flag &= ~D_HASHED;
-               pdir->dd_hashed--;
-               if(!(entry->d_flag & D_PRELIMINARY)) {
-                       pdir->dd_true_hashed--;
-                       if(!inode) {
-#ifdef DEBUG
-                               if(!entry->d_next || !entry->d_prev) {
-                                       printpath(entry);
-                                       printk(" flags=%x d_flag=%x negs=%d "
-                                              "hashed=%d\n", flags, entry->d_flag,
-                                              pdir->dd_negs, pdir->dd_hashed);
-                               }
-#endif
-                               remove_alias(&pdir->dd_neglist, entry);
-                               pdir->dd_negs--;
-                       }
-               }
-       } else if(!(entry->d_flag & D_ZOMBIE)) {
-#ifdef DEBUG
-               if(!pdir->dd_alloced) printk("dd_alloced is 0!\n");
-#endif
-               pdir->dd_alloced--;
-       }
-       if(entry->d_flag & D_BASKET) {
-               remove_basket(&pdir->dd_basketlist, entry);
-               entry->d_flag &= ~D_BASKET;
-       }
-}
-
-/* Theoretically, zombies should never or extremely seldom appear,
- * so this code is nearly superfluous.
- * A way to get zombies is while using inodes (i_count>0), unlink()
- * them as well as rmdir() the parent dir => the parent dir becomes a zombie.
- * Zombies are *not* in the hashtable, because somebody could re-creat()
- * that filename in it's parent dir again.
- * Besides coding errors during beta phase, when forcing an umount()
- * (e.g. at shutdown time), inodes could be in use such that the parent
- * dir is cleared, resulting also in zombies.
- */
-static /*inline*/ void _d_handle_zombie(struct dentry * entry,
-                                       struct ddir * ddir,
-                                       struct ddir * pdir)
-{
-       if(entry->d_flag & D_DIR) {
-               if(entry->d_flag & D_ZOMBIE) {
-                       if(!has_sons(ddir)) {
-                               entry->d_flag &= ~D_ZOMBIE;
-                               remove_hash(&pdir->dd_zombielist, entry);
-                               if(!pdir->dd_zombielist &&
-                                  (entry->d_parent->d_flag & D_ZOMBIE)) {
-                                       d_del(entry->d_parent, D_NORMAL);
-                               }
-                       }
-               } else if(has_sons(ddir)) {
-                       entry->d_flag |= D_ZOMBIE;
-                       insert_hash(&pdir->dd_zombielist, entry);
-
-                       /* This condition is no longer a bug, with the removal
-                        * of recursive_clear() this happens naturally during
-                        * an unmount attempt of a filesystem which is busy.
-                        */
-#if 0
-                       /* Not sure when this message should show up... */
-                       if(!IS_ROOT(entry)) {
-                               printk("VFS: clearing dcache directory "
-                                      "with successors\n");
-#ifdef DEBUG
-                               printpath(entry);
-                               printk(" d_flag=%x alloced=%d negs=%d hashed=%d "
-                                      "basket=%p zombies=%p\n",
-                                      entry->d_flag, ddir->dd_alloced,
-                                      ddir->dd_negs, ddir->dd_hashed,
-                                      ddir->dd_basketlist, ddir->dd_zombielist);
-#endif
-                       }
-#endif
-               }
-       }
-}
-
-static /*inline*/ blocking void _d_del(struct dentry * entry,
-                                      int flags)
-{
-       struct ddir * ddir = NULL;
-       struct ddir * pdir;
-       struct inode * inode = entry->d_flag & D_PRELIMINARY ? NULL : entry->u.d_inode;
-
-#ifdef DEBUG
-       if(inode)
-               xcheck("_d_del", inode);
-#endif
-       if(!entry->d_parent) {
-               printk("VFS: dcache parent is NULL\n");
-               return;
-       }
-       pdir = d_dir(entry->d_parent);
-       if(!IS_ROOT(entry))
-               _d_remove_from_parent(entry, pdir, inode, flags);
-
-       /* This may block, be careful! _d_remove_from_parent() is
-        * thus called before.
-        */
-       if(entry->d_flag & D_DIR)
-               ddir = d_dir(entry);
-       if(IS_ROOT(entry))
-               return;
-
-       if(flags & D_NO_FREE) {
-               /* Make it re-d_add()able */
-               pdir->dd_alloced++;
-               entry->d_flag &= D_DIR;
-       } else
-               _d_handle_zombie(entry, ddir, pdir);
-
-       /* This dec_ddir() must occur after zombie handling. */
-       if(!has_true_sons(pdir))
-               dec_ddir(entry->d_parent, entry->d_parent->u.d_inode);
-
-       entry->u.d_inode = NULL;
-       if(inode) {
-               remove_alias(&inode->i_dentry, entry);
-               inode->i_dent_count--;
-               if (entry->d_flag & D_DIR)
-                       dec_ddir(entry, inode);
-
-               if(!(flags & D_NO_CLEAR_INODE) &&
-                  !(atomic_read(&inode->i_count) +
-                    inode->i_ddir_count +
-                    inode->i_dent_count)) {
-#ifdef DEBUG
-                       printk("#");
-#endif
-                       /* This may block also. */
-                       _clear_inode(inode, 0, 0);
-               }
-       }
-       if(!(flags & D_NO_FREE) && !(entry->d_flag & D_ZOMBIE)) {
-               kfree(entry->d_name.name);
-               kfree(entry);
-#ifdef DEBUG
-               x_freed++;
-#endif
        }
-#ifdef DEBUG
-       x_free++;
-#endif
-}
-
-blocking void d_del(struct dentry * entry, int flags)
-{
-       if(!entry)
-               return;
-       LOG("d_clear", entry);
-       _d_del(entry, flags);
 }
 
-static inline struct dentry * __dlookup(struct dentry ** base,
-                                       struct qstr * name,
-                                       struct qstr * appendix)
+static inline struct dentry * __dlookup(struct dentry * base, struct dentry * parent, struct qstr * name)
 {
-       struct dentry * tmp = *base;
-
-       if(tmp && name->len) {
-               int totallen = name->len;
+       if (base) {
+               struct dentry * tmp = base;
+               int len = name->len;
+               int hash = name->hash;
+               const unsigned char *str = name->name;
 
-               if(appendix)
-                       totallen += appendix->len;
                do {
-                       if(tmp->d_name.len == totallen                  &&
-                          !(tmp->d_flag & D_DUPLICATE)                 &&
-                          !strncmp(tmp->d_name.name, name->name, name->len)    &&
-                          (!appendix || !strncmp(tmp->d_name.name+name->len,
-                                                 appendix->name, appendix->len)))
+                       if (tmp->d_name.hash == hash            &&
+                           tmp->d_name.len == len              &&
+                           tmp->d_parent == parent             &&
+                          !(tmp->d_flag & D_DUPLICATE)         &&
+                          !memcmp(tmp->d_name.name, str, len))
                                return tmp;
                        tmp = tmp->d_hash_next;
-               } while(tmp != *base);
+               } while(tmp != base);
        }
        return NULL;
 }
 
-struct dentry * d_lookup(struct inode * dir,
-                        struct qstr * name,
-                        struct qstr * appendix)
+struct dentry * d_lookup(struct dentry * dir, struct qstr * name)
 {
-       if(dir->i_dentry) {
-               struct ddir * ddir = d_dir(dir->i_dentry);
-               struct dentry ** base = d_base_qstr(ddir, name, appendix);
+       struct dentry ** base = d_base_qstr(dir, name);
 
-               return __dlookup(base, name, appendix);
-       }
-       return NULL;
+       return __dlookup(*base, dir, name);
 }
 
 static /*inline*/ blocking void _d_insert_to_parent(struct dentry * entry,
-                                                   struct ddir * pdir,
+                                                   struct dentry * parent,
                                                    struct inode * inode,
-                                                   struct qstr * ininame,
                                                    int flags)
 {
        struct dentry ** base;
-       struct dentry * parent = entry->d_parent;
 
-#ifdef DEBUG
-       if(!pdir->dd_alloced)
-               printk("dd_alloced is 0!\n");
-#endif
-       base = d_base_qstr(pdir, ininame, NULL);
-       if(!(flags & (D_NOCHECKDUP|D_DUPLICATE)) &&
-          __dlookup(base, ininame, NULL)) {
-               d_del(entry, D_NO_CLEAR_INODE);
-               return;
-       }
-       if(entry->d_flag & D_HASHED) {
+       base = d_base_qstr(parent, &entry->d_name);
+       if (entry->d_flag & D_HASHED) {
                printk("VFS: dcache entry is already hashed\n");
                return;
        }
-       if(!(flags & D_PRELIMINARY))
-               pdir->dd_true_hashed++;
-       pdir->dd_hashed++;
        insert_hash(base, entry);
        entry->d_flag |= D_HASHED;
-       pdir->dd_alloced--;
-       if(flags & D_BASKET)
-               insert_basket(&pdir->dd_basketlist, entry);
+}
 
-#ifdef DEBUG
-       if(inode && inode->i_dentry && (entry->d_flag & D_DIR)) {
-               struct dentry * tmp = inode->i_dentry;
-               printk("Auweia inode=%p entry=%p (%p %p %s)\n",
-                      inode, entry, parent->u.d_inode, parent, parent->d_name.name);
-               printk("entry path="); printpath(entry); printk("\n");
-               do {
-                       TST("auweia",tmp);
-                       printk("alias path="); printpath(tmp); printk("\n");
-                       tmp = tmp->d_next;
-               } while(tmp != inode->i_dentry);
-               printk("\n");
+/*
+ * Fill in inode information in the entry.
+ *
+ * This turns negative dentries into productive full members
+ * of society.
+ *
+ * NOTE! This assumes that the inode count has been incremented
+ * (or otherwise set) by the caller to indicate that it is now
+ * in use by the dcache..
+ */
+void d_instantiate(struct dentry *entry, struct inode * inode, int flags)
+{
+       entry->d_flag = (entry->d_flag & ~D_NEGATIVE) | flags;
+
+       if (inode && !(flags & D_NEGATIVE)) {
+               if (entry->d_flag & D_DIR) {
+                       if (inode->i_dentry) {
+                               printk("VFS: creating dcache directory alias\n");
+                               return;
+                       }
+               }
+               insert_alias(&inode->i_dentry, entry);
        }
-#endif
-       if(has_true_sons(pdir))
-               inc_ddir(parent, parent->u.d_inode);
-       if(!inode && !(flags & D_PRELIMINARY)) {
-               insert_alias(&pdir->dd_neglist, entry);
-               pdir->dd_negs++;
-
-               /* Don't allow the negative list to grow too much ... */
-               while(pdir->dd_negs > (pdir->dd_true_hashed >> 1) + 5)
-                       d_del(pdir->dd_neglist->d_prev, D_REMOVE);
+
+       entry->d_inode = inode;
+}
+
+/*
+ * Remove the inode from the dentry.. This removes
+ * it from the parent hashes but otherwise leaves it
+ * around - it may be a "zombie", part of a path
+ * that is still in use...
+ *
+ * "The Night of the Living Dead IV - the Dentry"
+ */
+void d_delete(struct dentry * dentry)
+{
+       struct inode * inode = dentry->d_inode;
+
+       _d_remove_from_parent(dentry, dentry->d_parent);
+       if (inode) {
+               remove_alias(&inode->i_dentry, dentry);
+               dentry->d_inode = NULL;
+               iput(inode);
        }
 }
 
-blocking void d_add(struct dentry * entry, struct inode * inode,
-                   struct qstr * ininame, int flags)
+blocking void d_add(struct dentry * entry, struct inode * inode, int flags)
 {
        struct dentry * parent = entry->d_parent;
-       struct qstr dummy;
-       struct ddir * pdir;
 
 #ifdef DEBUG
-       if(inode)
+       if (inode)
                xcheck("d_add", inode);
-       if(IS_ROOT(entry)) {
+       if (IS_ROOT(entry)) {
                printk("VFS: d_add for root dentry ");
                printpath(entry);
                printk(" -> ");
-               if(ininame)
-                       printk("%s", ininame->name);
                printk("\n");
                return;
        }
-       if(!parent)
+       if (!parent)
                panic("d_add with parent==NULL");
        LOG("d_add", entry);
 #endif
-       if(ininame) {
-               if(ininame->len != entry->d_name.len) {
-                       printk("VFS: d_add with wrong string length");
-                       entry->d_name.len = ininame->len; /* kludge */
-               }
-               memcpy(entry->d_name.name, ininame->name, ininame->len);
-               entry->d_name.name[ininame->len] = '\0';
-       } else {
-               dummy.name = entry->d_name.name;
-               dummy.len = entry->d_name.len;
-               ininame = &dummy;
-       }
         if(entry->d_flag & D_HASHED)
                printk("VFS: d_add of already added dcache entry\n");
 
-       pdir = d_dir(parent);
-       _d_insert_to_parent(entry, pdir, inode, ininame, flags);
-       entry->d_flag |= flags;
-       if(inode && !(flags & D_PRELIMINARY)) {
-               if(entry->d_flag & D_DIR) {
-                       if(inode->i_dentry) {
-                               printk("VFS: creating dcache directory alias\n");
-                               return;
-                       }
-               }
-               insert_alias(&inode->i_dentry, entry);
-               inode->i_dent_count++;
-       }
-       entry->u.d_inode = inode;
+       _d_insert_to_parent(entry, parent, inode, flags);
+       d_instantiate(entry, inode, flags);
 }
 
-blocking struct dentry * d_entry(struct dentry * parent,
-                                struct qstr * name,
-                                struct inode * inode)
+static inline void alloc_new_name(struct dentry * entry, struct qstr *newname)
 {
-       struct ddir * pdir = d_dir(parent);
-       struct dentry ** base = d_base_qstr(pdir, name, NULL);
-       struct dentry * found = __dlookup(base, name, NULL);
-
-       if(!found) {
-               int isdir = (inode && S_ISDIR(inode->i_mode));
-
-               found = d_alloc(parent, name->len, isdir);
-               if(found) {
-                       d_add(found, inode, name,
-                             isdir ? (D_DIR|D_NOCHECKDUP) : D_NOCHECKDUP);
-               } else
-                       printk("VFS: problem with d_alloc\n");
-       }
-       return found;
-}
+       int len = newname->len;
+       int hash = newname->hash;
+       char *name = (char *) entry->d_name.name;
 
-blocking void d_entry_preliminary(struct dentry * parent,
-                                 struct qstr * name,
-                                 unsigned long ino)
-{
-       struct ddir * pdir = d_dir(parent);
-       struct dentry ** base = d_base_qstr(pdir, name, NULL);
-       struct dentry * found = __dlookup(base, name, NULL);
-
-       if(!found && ino) {
-               struct dentry * new = d_alloc(parent, name->len, 0);
-
-               if(new) {
-                       d_add(new, NULL, name, D_PRELIMINARY|D_NOCHECKDUP);
-                       new->u.d_ino = ino;
-               } else
-                       printk("VFS: problem with d_alloc\n");
+       if (NAME_ALLOC_LEN(len) != NAME_ALLOC_LEN(entry->d_name.len)) {
+               name = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL);
+               if (!name)
+                       printk("out of memory for dcache\n");
+               kfree(entry->d_name.name);
+               entry->d_name.name = name;
        }
-}
-
-static inline void alloc_new_name(struct dentry * entry, int len)
-{
-       int alloc_len = NAME_ALLOC_LEN(len);
-       char *name;
-
-       if (alloc_len == NAME_ALLOC_LEN(entry->d_name.len))
-               return;
-       name = kmalloc(alloc_len, GFP_KERNEL);
-       if (!name)
-               printk("out of memory for dcache\n");
-       kfree(entry->d_name.name);
-       entry->d_name.name = name;
+       memcpy(name, newname->name, len);
+       name[len] = 0;
+       entry->d_name.len = len;
+       entry->d_name.hash = hash;
 }
 
 static inline void d_remove_old_parent(struct dentry * entry)
 {
-       struct ddir * pdir;
+       struct dentry * parent;
        struct inode * inode;
 
-       pdir = d_dir(entry->d_parent);
-       inode = entry->u.d_inode;
-       _d_remove_from_parent(entry, pdir, inode, D_NO_CLEAR_INODE);
+       parent = entry->d_parent;
+       inode = entry->d_inode;
+       _d_remove_from_parent(entry, parent);
 }
 
-static inline void d_add_new_parent(struct dentry * entry, struct inode * new_parent)
+static inline void d_add_new_parent(struct dentry * entry, struct dentry * parent)
 {
-       struct ddir * pdir;
        struct inode * inode;
 
-       pdir = d_dir(entry->d_parent = new_parent->i_dentry);
-       inode = entry->u.d_inode;
+       entry->d_parent = parent;
+       inode = entry->d_inode;
 
-       _d_insert_to_parent(entry, pdir, inode, &entry->d_name, entry->d_flag);
+       _d_insert_to_parent(entry, parent, inode, entry->d_flag);
 }
 
 
-blocking void d_move(struct dentry * entry, struct inode * newdir, 
-                    struct qstr * newname, struct qstr * newapp)
+blocking void d_move(struct dentry * entry, struct dentry * newdir, struct qstr * newname)
 {
        struct inode * inode;
-       int len;
        int flags;
 
-       if(!entry)
+       if (!entry)
                return;
-       inode = entry->u.d_inode;
+       inode = entry->d_inode;
        flags = entry->d_flag;
-       if((flags & D_PRELIMINARY) || !inode) {
-               if(!(flags & D_PRELIMINARY))
-                       printk("VFS: trying to move negative dcache entry\n");
-               d_del(entry, D_NO_CLEAR_INODE);
-               return;
+       if (!inode) {
+               printk("VFS: moving negative dcache entry\n");
        }
-#if 0
-printk("d_move %p '%s' -> '%s%s' dent_count=%d\n", inode, entry->d_name.name,
-       newname->name, newapp ? newapp->name : "", inode->i_dent_count);
-#endif
-       if(flags & D_ZOMBIE) {
+
+       if (flags & D_ZOMBIE) {
                printk("VFS: moving zombie entry\n");
        }
 
        d_remove_old_parent(entry);
-
-       len = newname->len;
-       if(newapp) {
-               len += newapp->len;
-               flags |= D_BASKET;
-       } else
-               flags &= ~D_BASKET;
-       alloc_new_name(entry, len);
-       memcpy(entry->d_name.name, newname->name, newname->len);
-       if(newapp)
-               memcpy(entry->d_name.name+newname->len, newapp->name, newapp->len);
-       entry->d_name.name[len] = '\0';
-       entry->d_name.len = len;
-
+       alloc_new_name(entry, newname);
        d_add_new_parent(entry, newdir);
 }
 
-int d_path(struct dentry * entry, struct inode * chroot, char * buf)
+int d_path(struct dentry * entry, struct dentry * chroot, char * buf)
 {
-       if(IS_ROOT(entry) || (chroot && entry->u.d_inode == chroot &&
-                             !(entry->d_flag & D_PRELIMINARY))) {
+       if (IS_ROOT(entry) || (chroot && entry == chroot)) {
                *buf = '/';
                return 1;
        } else {
                int len = d_path(entry->d_parent, chroot, buf);
 
                buf += len;
-               if(len > 1) {
+               if (len > 1) {
                        *buf++ = '/';
                        len++;
                }
@@ -831,97 +407,3 @@ int d_path(struct dentry * entry, struct inode * chroot, char * buf)
                return len + entry->d_name.len;
        }
 }
-
-struct dentry * d_basket(struct dentry * dir_entry)
-{
-       if(dir_entry && (dir_entry->d_flag & D_DIR)) {
-               struct ddir * ddir = d_dir(dir_entry);
-
-               return ddir->dd_basketlist;
-       } else
-               return NULL;
-}
-
-int d_isbasket(struct dentry * entry)
-{
-       return entry->d_flag & D_BASKET;
-}
-
-blocking struct inode * d_inode(struct dentry ** changing_entry)
-{
-       struct dentry * entry = *changing_entry;
-       struct inode * inode;
-
-#ifdef CONFIG_DCACHE_PRELOAD
-       if(entry->d_flag & D_PRELIMINARY) {
-               struct qstr name = { entry->d_name.name, entry->d_name.len };
-               struct ddir * pdir = d_dir(entry->d_parent);
-               struct dentry ** base = d_base_qstr(pdir, &name, NULL);
-               struct dentry * found;
-               unsigned long ino;
-               struct inode * dir = entry->d_parent->u.d_inode;
-               TST("d_inode",entry);
-               ino = entry->u.d_ino;
-               if(!dir)
-                       d_panic();
-
-               /* Prevent concurrent d_lookup()s or d_inode()s before
-                * giving up vfs_lock. This just removes from the parent,
-                * but does not deallocate it.
-                */
-
-               /* !!!!!!! Aiee, here is an unresolved race if somebody
-                * unlink()s the inode during the iget(). The problem is
-                * that we need to synchronize externally. Proposed solution:
-                * put a rw_lock (read-mode) on the parent dir for each
-                * iget(), lookup() and so on, and a write-mode lock for
-                * everything that changes the dir (e.g. unlink()), and do
-                * this consistently everywhere in the generic VFS (not in
-                * the concrete filesystems). This should kill similar
-                * races everywhere, with a single clean concept.
-                * Later, the synchronization stuff can be cleaned out
-                * of the concrete fs'es.
-                */
-               d_del(entry, D_NO_CLEAR_INODE|D_NO_FREE);
-               vfs_unlock();
-
-               /* This circumvents the normal lookup() of pathnames.
-                * Therefore,  preliminary entries must not be used
-                * (see FS_NO_DCACHE and FS_NO_PRELIM) if the fs does not
-                * permit fetching *valid* inodes with plain iget().
-                */
-               inode = __iget(dir->i_sb, ino, 0);
-               vfs_lock();
-               if(!inode) {
-                       printk("VFS: preliminary dcache entry was invalid\n");
-                       *changing_entry = NULL;
-                       return NULL;
-               }
-               xcheck("d_inode iget()", inode);
-               if((found = __dlookup(base, &name, NULL))) {
-                       d_del(entry, D_NO_CLEAR_INODE);
-                       *changing_entry = found;
-               } else if(S_ISDIR(inode->i_mode)) {
-                       struct dentry * new = d_alloc(entry->d_parent, entry->d_name.len, 1);
-                       if(new)
-                               d_add(new, inode, &name, D_DIR);
-                       *changing_entry = new;
-
-                       /* Finally deallocate old entry. */
-                       d_del(entry, D_NO_CLEAR_INODE);
-               } else {
-                       /* Re-insert to the parent, but now as normal dentry. */
-                       d_add(entry, inode, NULL, 0);
-               }
-               return inode;
-       }
-#endif
-       inode = entry->u.d_inode;
-       if(inode) {
-#ifdef DEBUG
-               xcheck("d_inode", inode);
-#endif
-               iinc_zero(inode);
-       }
-       return inode;
-}
index 59d2112d946285249dc60627710e4a80c2528566..b830193d0e99c27576c7812506337dc95a0a7246 100644 (file)
@@ -1038,7 +1038,7 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
        if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS))
                dev = 0;
        else {
-               int error = namei(NAM_FOLLOW_LINK, special, &ino);
+               int error = namei(special, &ino);
                if(error)
                        goto out;
                dev = ino->i_rdev;
index 4d2b561ee62b3d5e79b2a482db14a9b61d33ee51..7e159e7d286d80ff68cc4b3f60023368e6fc39ec 100644 (file)
@@ -291,7 +291,7 @@ int ext2_new_block (const struct inode * inode, unsigned long goal,
                printk ("ext2_new_block: nonexistent device");
                return 0;
        }
-retry:
+
        lock_super (sb);
        es = sb->u.ext2_sb.s_es;
        if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) &&
@@ -299,8 +299,6 @@ retry:
             (sb->u.ext2_sb.s_resgid == 0 ||
              !in_group_p (sb->u.ext2_sb.s_resgid)))) {
                unlock_super (sb);
-               if(sb->s_ibasket && free_ibasket(sb))
-                       goto retry;
                return 0;
        }
 
@@ -392,8 +390,6 @@ repeat:
        }
        if (k >= sb->u.ext2_sb.s_groups_count) {
                unlock_super (sb);
-               if(sb->s_ibasket && free_ibasket(sb))
-                       goto retry;
                return 0;
        }
        bitmap_nr = load_block_bitmap (sb, i);
index d9b1957e317286ca1be746b89683402d6b37fb7a..bf64a2a1aead82671ed2e9c6bc07e2c65f71b87c 100644 (file)
@@ -65,6 +65,7 @@ struct inode_operations ext2_dir_inode_operations = {
        ext2_mknod,             /* mknod */
        ext2_rename,            /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
index dbb8c3619b9e07de8cbac0a01acb9eeb1d94e866..61d552d8c7c0543de51977b794e5fd55b03466fc 100644 (file)
@@ -72,6 +72,7 @@ struct inode_operations ext2_file_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        generic_readpage,       /* readpage */
        NULL,                   /* writepage */
        ext2_bmap,              /* bmap */
index 7c578ae6f1b5529cdd079960d25538733155e794..85981a7982ea204cef890eeaa7a7b3c4620be5dd 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/string.h>
 #include <linux/locks.h>
 
+
 /*
  * define how far ahead to read directories while searching them.
  */
@@ -154,8 +155,7 @@ failure:
        return NULL;
 }
 
-int ext2_lookup (struct inode * dir, const char * name, int len,
-                struct inode ** result)
+int ext2_lookup(struct inode * dir, struct qstr *name, struct inode ** result)
 {
        unsigned long ino;
        struct ext2_dir_entry * de;
@@ -164,26 +164,22 @@ int ext2_lookup (struct inode * dir, const char * name, int len,
        *result = NULL;
        if (!dir)
                return -ENOENT;
-       if (!S_ISDIR(dir->i_mode)) {
-               iput (dir);
+
+       if (!S_ISDIR(dir->i_mode))
                return -ENOTDIR;
-       }
-       if (len > EXT2_NAME_LEN) {
-               iput (dir);
+
+       if (name->len > EXT2_NAME_LEN)
                return -ENAMETOOLONG;
-       }
+
        ino = dir->i_version;
-       if (!(bh = ext2_find_entry (dir, name, len, &de))) {
-               iput (dir);
+       if (!(bh = ext2_find_entry (dir, name->name, name->len, &de)))
                return -ENOENT;
-       }
+
        ino = le32_to_cpu(de->inode);
        brelse (bh);
-       if (!(*result = iget (dir->i_sb, ino))) {
-               iput (dir);
+       if (!(*result = iget (dir->i_sb, ino)))
                return -EACCES;
-       }
-       iput (dir);
+
        return 0;
 }
 
@@ -347,31 +343,35 @@ static int ext2_delete_entry (struct ext2_dir_entry * dir,
        return -ENOENT;
 }
 
-int ext2_create (struct inode * dir,const char * name, int len, int mode,
-                struct inode ** result)
+/*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+ * is so far marked "D_NEGATIVE".
+ *
+ * If the create succeeds, remove the D_NEGATIVE flag,
+ * and fill in the inode information with d_instantiate().
+ */
+int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
 {
        struct inode * inode;
        struct buffer_head * bh;
        struct ext2_dir_entry * de;
        int err;
 
-       *result = NULL;
        if (!dir)
                return -ENOENT;
        inode = ext2_new_inode (dir, mode, &err);
-       if (!inode) {
-               iput (dir);
+       if (!inode)
                return err;
-       }
+
        inode->i_op = &ext2_file_inode_operations;
        inode->i_mode = mode;
        inode->i_dirt = 1;
-       bh = ext2_add_entry (dir, name, len, &de, &err);
+       bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
        if (!bh) {
                inode->i_nlink--;
                inode->i_dirt = 1;
                iput (inode);
-               iput (dir);
                return err;
        }
        de->inode = cpu_to_le32(inode->i_ino);
@@ -382,13 +382,11 @@ int ext2_create (struct inode * dir,const char * name, int len, int mode,
                wait_on_buffer (bh);
        }
        brelse (bh);
-       iput (dir);
-       *result = inode;
+       d_instantiate(dentry, inode, 0);
        return 0;
 }
 
-int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
-               int rdev)
+int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
 {
        struct inode * inode;
        struct buffer_head * bh;
@@ -398,21 +396,13 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
        if (!dir)
                return -ENOENT;
 
-       if (len > EXT2_NAME_LEN) {
-               iput (dir);
+       if (dentry->d_name.len > EXT2_NAME_LEN)
                return -ENAMETOOLONG;
-       }
-       bh = ext2_find_entry (dir, name, len, &de);
-       if (bh) {
-               brelse (bh);
-               iput (dir);
-               return -EEXIST;
-       }
+
        inode = ext2_new_inode (dir, mode, &err);
-       if (!inode) {
-               iput (dir);
+       if (!inode)
                return err;
-       }
+
        inode->i_uid = current->fsuid;
        inode->i_mode = mode;
        inode->i_op = NULL;
@@ -434,12 +424,11 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
        if (S_ISBLK(mode) || S_ISCHR(mode))
                inode->i_rdev = to_kdev_t(rdev);
        inode->i_dirt = 1;
-       bh = ext2_add_entry (dir, name, len, &de, &err);
+       bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
        if (!bh) {
                inode->i_nlink--;
                inode->i_dirt = 1;
-               iput (inode);
-               iput (dir);
+               iput(inode);
                return err;
        }
        de->inode = cpu_to_le32(inode->i_ino);
@@ -449,45 +438,32 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
                ll_rw_block (WRITE, 1, &bh);
                wait_on_buffer (bh);
        }
-       brelse (bh);
-       iput (dir);
-       iput (inode);
+       brelse(bh);
+       d_instantiate(dentry, inode, 0);
        return 0;
 }
 
-int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
+int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 {
        struct inode * inode;
        struct buffer_head * bh, * dir_block;
        struct ext2_dir_entry * de;
        int err;
 
-       if (!dir)
-               return -ENOENT;
-       if (len > EXT2_NAME_LEN) {
-               iput (dir);
+       if (dentry->d_name.len > EXT2_NAME_LEN)
                return -ENAMETOOLONG;
-       }
-       bh = ext2_find_entry (dir, name, len, &de);
-       if (bh) {
-               brelse (bh);
-               iput (dir);
-               return -EEXIST;
-       }
-       if (dir->i_nlink >= EXT2_LINK_MAX) {
-               iput (dir);
+
+       if (dir->i_nlink >= EXT2_LINK_MAX)
                return -EMLINK;
-       }
+
        inode = ext2_new_inode (dir, S_IFDIR, &err);
-       if (!inode) {
-               iput (dir);
+       if (!inode)
                return err;
-       }
+
        inode->i_op = &ext2_dir_inode_operations;
        inode->i_size = inode->i_sb->s_blocksize;
        dir_block = ext2_bread (inode, 0, 1, &err);
        if (!dir_block) {
-               iput (dir);
                inode->i_nlink--;
                inode->i_dirt = 1;
                iput (inode);
@@ -511,9 +487,8 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
        if (dir->i_mode & S_ISGID)
                inode->i_mode |= S_ISGID;
        inode->i_dirt = 1;
-       bh = ext2_add_entry (dir, name, len, &de, &err);
+       bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
        if (!bh) {
-               iput (dir);
                inode->i_nlink = 0;
                inode->i_dirt = 1;
                iput (inode);
@@ -528,8 +503,7 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
        }
        dir->i_nlink++;
        dir->i_dirt = 1;
-       iput (dir);
-       iput (inode);
+       d_instantiate(dentry, inode, D_DIR);
        brelse (bh);
        return 0;
 }
@@ -593,51 +567,46 @@ static int empty_dir (struct inode * inode)
        return 1;
 }
 
-int ext2_rmdir (struct inode * dir, const char * name, int len)
+int ext2_rmdir (struct inode * dir, struct dentry *dentry)
 {
        int retval;
        struct inode * inode;
        struct buffer_head * bh;
        struct ext2_dir_entry * de;
 
-repeat:
        if (!dir)
                return -ENOENT;
        inode = NULL;
-       if (len > EXT2_NAME_LEN) {
-               iput (dir);
+       if (dentry->d_name.len > EXT2_NAME_LEN)
                return -ENAMETOOLONG;
-       }
-       bh = ext2_find_entry (dir, name, len, &de);
+
+       bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
        retval = -ENOENT;
        if (!bh)
                goto end_rmdir;
        retval = -EPERM;
-       if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode))))
-               goto end_rmdir;
+       inode = dentry->d_inode;
+
        if (inode->i_sb->dq_op)
                inode->i_sb->dq_op->initialize (inode, -1);
-       if (inode->i_dev != dir->i_dev) {
-               retval = -EBUSY;
-               goto end_rmdir;
-       }
-       if (le32_to_cpu(de->inode) != inode->i_ino) {
-               iput(inode);
-               brelse(bh);
-               current->counter = 0;
-               schedule();
-               goto repeat;
-       }
+
         if ((dir->i_mode & S_ISVTX) && !fsuser() &&
             current->fsuid != inode->i_uid &&
             current->fsuid != dir->i_uid)
                goto end_rmdir;
        if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
                goto end_rmdir;
-       if (!S_ISDIR(inode->i_mode)) {
-               retval = -ENOTDIR;
+
+       retval = -ENOTDIR;
+       if (!S_ISDIR(inode->i_mode))
                goto end_rmdir;
-       }
+
+       retval = -EIO;
+       if (inode->i_dev != dir->i_dev)
+               goto end_rmdir;
+       if (le32_to_cpu(de->inode) != inode->i_ino)
+               goto end_rmdir;
+
        down(&inode->i_sem);
        if (!empty_dir (inode))
                retval = -ENOTEMPTY;
@@ -675,52 +644,47 @@ repeat:
        dir->i_nlink--;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        dir->i_dirt = 1;
+       d_delete(dentry);
+
 end_rmdir:
-       iput (dir);
-       iput (inode);
        brelse (bh);
        return retval;
 }
 
-int ext2_unlink (struct inode * dir, const char * name, int len)
+int ext2_unlink(struct inode * dir, struct dentry *dentry)
 {
        int retval;
        struct inode * inode;
        struct buffer_head * bh;
        struct ext2_dir_entry * de;
 
-repeat:
-       if (!dir)
-               return -ENOENT;
        retval = -ENOENT;
        inode = NULL;
-       if (len > EXT2_NAME_LEN) {
-               iput (dir);
+       if (dentry->d_name.len > EXT2_NAME_LEN)
                return -ENAMETOOLONG;
-       }
-       bh = ext2_find_entry (dir, name, len, &de);
+
+       bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
        if (!bh)
                goto end_unlink;
-       if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode))))
-               goto end_unlink;
+
+       inode = dentry->d_inode;
        if (inode->i_sb->dq_op)
                inode->i_sb->dq_op->initialize (inode, -1);
+
        retval = -EPERM;
        if (S_ISDIR(inode->i_mode))
                goto end_unlink;
        if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
                goto end_unlink;
-       if (le32_to_cpu(de->inode) != inode->i_ino) {
-               iput(inode);
-               brelse(bh);
-               current->counter = 0;
-               schedule();
-               goto repeat;
-       }
        if ((dir->i_mode & S_ISVTX) && !fsuser() &&
            current->fsuid != inode->i_uid &&
            current->fsuid != dir->i_uid)
                goto end_unlink;
+
+       retval = -EIO;
+       if (le32_to_cpu(de->inode) != inode->i_ino)
+               goto end_unlink;
+       
        if (!inode->i_nlink) {
                ext2_warning (inode->i_sb, "ext2_unlink",
                              "Deleting nonexistent file (%lu), %d",
@@ -742,15 +706,14 @@ repeat:
        inode->i_dirt = 1;
        inode->i_ctime = dir->i_ctime;
        retval = 0;
+       d_delete(dentry);       /* This also frees the inode */
+
 end_unlink:
        brelse (bh);
-       iput (inode);
-       iput (dir);
        return retval;
 }
 
-int ext2_symlink (struct inode * dir, const char * name, int len,
-                 const char * symname)
+int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
 {
        struct ext2_dir_entry * de;
        struct inode * inode = NULL;
@@ -761,7 +724,6 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
        char c;
 
        if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) {
-               iput (dir);
                return err;
        }
        inode->i_mode = S_IFLNK | S_IRWXUGO;
@@ -775,7 +737,6 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
 
                name_block = ext2_bread (inode, 0, 1, &err);
                if (!name_block) {
-                       iput (dir);
                        inode->i_nlink--;
                        inode->i_dirt = 1;
                        iput (inode);
@@ -799,21 +760,11 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
        inode->i_size = i;
        inode->i_dirt = 1;
 
-       bh = ext2_find_entry (dir, name, len, &de);
-       if (bh) {
-               inode->i_nlink--;
-               inode->i_dirt = 1;
-               iput (inode);
-               brelse (bh);
-               iput (dir);
-               return -EEXIST;
-       }
-       bh = ext2_add_entry (dir, name, len, &de, &err);
+       bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
        if (!bh) {
                inode->i_nlink--;
                inode->i_dirt = 1;
                iput (inode);
-               iput (dir);
                return err;
        }
        de->inode = cpu_to_le32(inode->i_ino);
@@ -824,47 +775,30 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
                wait_on_buffer (bh);
        }
        brelse (bh);
-       iput (dir);
-       iput (inode);
+       d_instantiate(dentry, inode, 0);
        return 0;
 }
 
-int ext2_link (struct inode * oldinode, struct inode * dir,
-              const char * name, int len)
+int ext2_link (struct inode * inode, struct inode * dir, struct dentry *dentry)
 {
        struct ext2_dir_entry * de;
        struct buffer_head * bh;
        int err;
 
-       if (S_ISDIR(oldinode->i_mode)) {
-               iput (oldinode);
-               iput (dir);
+       if (S_ISDIR(inode->i_mode))
                return -EPERM;
-       }
-       if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
-               iput (oldinode);
-               iput (dir);
+
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
                return -EPERM;
-       }
-       if (oldinode->i_nlink >= EXT2_LINK_MAX) {
-               iput (oldinode);
-               iput (dir);
+
+       if (inode->i_nlink >= EXT2_LINK_MAX)
                return -EMLINK;
-       }
-       bh = ext2_find_entry (dir, name, len, &de);
-       if (bh) {
-               brelse (bh);
-               iput (dir);
-               iput (oldinode);
-               return -EEXIST;
-       }
-       bh = ext2_add_entry (dir, name, len, &de, &err);
-       if (!bh) {
-               iput (dir);
-               iput (oldinode);
+
+       bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+       if (!bh)
                return err;
-       }
-       de->inode = cpu_to_le32(oldinode->i_ino);
+
+       de->inode = cpu_to_le32(inode->i_ino);
        dir->i_version = ++event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
@@ -872,11 +806,11 @@ int ext2_link (struct inode * oldinode, struct inode * dir,
                wait_on_buffer (bh);
        }
        brelse (bh);
-       iput (dir);
-       oldinode->i_nlink++;
-       oldinode->i_ctime = CURRENT_TIME;
-       oldinode->i_dirt = 1;
-       iput (oldinode);
+       inode->i_nlink++;
+       inode->i_ctime = CURRENT_TIME;
+       inode->i_dirt = 1;
+       atomic_inc(&inode->i_count);
+       d_instantiate(dentry, inode, 0);
        return 0;
 }
 
@@ -895,7 +829,7 @@ static int subdir (struct inode * new_inode, struct inode * old_inode)
                if (new_inode->i_dev != old_inode->i_dev)
                        break;
                ino = new_inode->i_ino;
-               if (ext2_lookup (new_inode, "..", 2, &new_inode))
+               if (ext2_lookup (new_inode, &(struct qstr) { "..", 2, 0 }, &new_inode))
                        break;
                if (new_inode->i_ino == ino)
                        break;
@@ -923,43 +857,27 @@ static int subdir (struct inode * new_inode, struct inode * old_inode)
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int do_ext2_rename (struct inode * old_dir, const char * old_name,
-                          int old_len, struct inode * new_dir,
-                          const char * new_name, int new_len)
+static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
+                          struct inode * new_dir,struct dentry *new_dentry)
 {
        struct inode * old_inode, * new_inode;
        struct buffer_head * old_bh, * new_bh, * dir_bh;
        struct ext2_dir_entry * old_de, * new_de;
        int retval;
 
-       goto start_up;
-try_again:
-       if (new_bh && new_de) {
-               ext2_delete_entry(new_de, new_bh);
-               new_dir->i_version = ++event;
-       }
-       brelse (old_bh);
-       brelse (new_bh);
-       brelse (dir_bh);
-       iput (old_inode);
-       iput (new_inode);
-       current->counter = 0;
-       schedule ();
-start_up:
        old_inode = new_inode = NULL;
        old_bh = new_bh = dir_bh = NULL;
        new_de = NULL;
        retval = -ENAMETOOLONG;
-       if (old_len > EXT2_NAME_LEN)
+       if (old_dentry->d_name.len > EXT2_NAME_LEN)
                goto end_rename;
 
-       old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de);
+       old_bh = ext2_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
        retval = -ENOENT;
        if (!old_bh)
                goto end_rename;
-       old_inode = __iget (old_dir->i_sb, le32_to_cpu(old_de->inode), 0); /* don't cross mnt-points */
-       if (!old_inode)
-               goto end_rename;
+       old_inode = old_dentry->d_inode;
+
        retval = -EPERM;
        if ((old_dir->i_mode & S_ISVTX) && 
            current->fsuid != old_inode->i_uid &&
@@ -967,9 +885,10 @@ start_up:
                goto end_rename;
        if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode))
                goto end_rename;
-       new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de);
+
+       new_inode = new_dentry->d_inode;
+       new_bh = ext2_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de);
        if (new_bh) {
-               new_inode = __iget (new_dir->i_sb, le32_to_cpu(new_de->inode), 0); /* no mntp cross */
                if (!new_inode) {
                        brelse (new_bh);
                        new_bh = NULL;
@@ -1018,29 +937,18 @@ start_up:
                        goto end_rename;
        }
        if (!new_bh)
-               new_bh = ext2_add_entry (new_dir, new_name, new_len, &new_de,
+               new_bh = ext2_add_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de,
                                         &retval);
        if (!new_bh)
                goto end_rename;
        new_dir->i_version = ++event;
-       /*
-        * sanity checking before doing the rename - avoid races
-        */
-       if (new_inode && (le32_to_cpu(new_de->inode) != new_inode->i_ino))
-               goto try_again;
-       if (le32_to_cpu(new_de->inode) && !new_inode)
-               goto try_again;
-       if (le32_to_cpu(old_de->inode) != old_inode->i_ino)
-               goto try_again;
+
        /*
         * ok, that's it
         */
        new_de->inode = le32_to_cpu(old_inode->i_ino);
-       retval = ext2_delete_entry (old_de, old_bh);
-       if (retval == -ENOENT)
-               goto try_again;
-       if (retval)
-               goto end_rename;
+       ext2_delete_entry (old_de, old_bh);
+
        old_dir->i_version = ++event;
        if (new_inode) {
                new_inode->i_nlink--;
@@ -1072,15 +980,15 @@ start_up:
                ll_rw_block (WRITE, 1, &new_bh);
                wait_on_buffer (new_bh);
        }
+
+       /* Update the dcache */
+       d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
+       d_delete(new_dentry);
        retval = 0;
 end_rename:
        brelse (dir_bh);
        brelse (old_bh);
        brelse (new_bh);
-       iput (old_inode);
-       iput (new_inode);
-       iput (old_dir);
-       iput (new_dir);
        return retval;
 }
 
@@ -1097,16 +1005,15 @@ end_rename:
  * super-block.  This way, we really lock other renames only if they occur
  * on the same file system
  */
-int ext2_rename (struct inode * old_dir, const char * old_name, int old_len,
-                struct inode * new_dir, const char * new_name, int new_len)
+int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
+                struct inode * new_dir, struct dentry *new_dentry)
 {
        int result;
 
        while (old_dir->i_sb->u.ext2_sb.s_rename_lock)
                sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
        old_dir->i_sb->u.ext2_sb.s_rename_lock = 1;
-       result = do_ext2_rename (old_dir, old_name, old_len, new_dir,
-                                new_name, new_len);
+       result = do_ext2_rename (old_dir, old_dentry, new_dir, new_dentry);
        old_dir->i_sb->u.ext2_sb.s_rename_lock = 0;
        wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
        return result;
index 635a45692c04926d299440fdf6d4c54873c934a3..5a654f686b71ee578c9ce9cc2757f1a1309ca089 100644 (file)
@@ -632,7 +632,8 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
         */
        sb->s_dev = dev;
        sb->s_op = &ext2_sops;
-       if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO))) {
+       sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO), NULL);
+       if (!sb->s_root) {
                sb->s_dev = 0;
                for (i = 0; i < db_count; i++)
                        if (sb->u.ext2_sb.s_group_desc[i])
index 4d5a5cadab5f3d94cf07b9b35a054a03f149365e..654736c0df019c514f43a019ffc10f343e18bb21 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/stat.h>
 
 static int ext2_readlink (struct inode *, char *, int);
+static struct dentry *ext2_follow_link(struct inode *, struct dentry *);
 
 /*
  * symlinks can't do much...
@@ -41,6 +42,7 @@ struct inode_operations ext2_symlink_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        ext2_readlink,          /* readlink */
+       ext2_follow_link,       /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -49,26 +51,50 @@ struct inode_operations ext2_symlink_inode_operations = {
        NULL                    /* smap */
 };
 
+static struct dentry * ext2_follow_link(struct inode * inode, struct dentry *base)
+{
+       int error;
+       struct buffer_head * bh = NULL;
+       char * link;
+
+       link = (char *) inode->u.ext2_i.i_data;
+       if (inode->i_blocks) {
+               if (!(bh = ext2_bread (inode, 0, 0, &error))) {
+                       dput(base);
+                       return ERR_PTR(-EIO);
+               }
+               link = bh->b_data;
+       }
+       if (!IS_RDONLY(inode)) {
+               inode->i_atime = CURRENT_TIME;
+               inode->i_dirt = 1;
+       }
+       base = lookup_dentry(link, base, 1);
+       if (bh)
+               brelse(bh);
+       return base;
+}
+
 static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
 {
        struct buffer_head * bh = NULL;
        char * link;
-       int i, err;
+       int i;
 
        if (buflen > inode->i_sb->s_blocksize - 1)
                buflen = inode->i_sb->s_blocksize - 1;
+
+       link = (char *) inode->u.ext2_i.i_data;
        if (inode->i_blocks) {
+               int err;
                bh = ext2_bread (inode, 0, 0, &err);
                if (!bh) {
-                       iput (inode);
                        if(err < 0) /* indicate type of error */
                                return err;
                        return 0;
                }
                link = bh->b_data;
        }
-       else
-               link = (char *) inode->u.ext2_i.i_data;
 
        i = 0;
        while (i < buflen && link[i])
@@ -79,7 +105,6 @@ static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
                inode->i_atime = CURRENT_TIME;
                inode->i_dirt = 1;
        }
-       iput (inode);
        if (bh)
                brelse (bh);
        return i;
index 3fdc0be0aef8d3153ef15d2b834b670de67c28e6..dfd06929d2871b8535e00330afec5d9ad3bb286c 100644 (file)
@@ -23,8 +23,8 @@ static char ascii_extensions[] =
   "TXT" "ME " "HTM" "1ST" "LOG" "   "  /* text files */
   "C  " "H  " "CPP" "LIS" "PAS" "FOR"  /* programming languages */
   "F  " "MAK" "INC" "BAS"              /* programming languages */
-  "BAT" "SH                          /* program code :) */
-  "INI "                               /* config files */
+  "BAT" "SH "                          /* program code :) */
+  "INI"                                        /* config files */
   "PBM" "PGM" "DXF"                    /* graphics */
   "TEX";                               /* TeX */
 
index 7215e12049fbf26f6fa977b79f8062caeaf8b26a..0f11cde829dd38fc4433512f13054c837cd27563 100644 (file)
@@ -110,7 +110,7 @@ void xcheck(char * txt, struct inode * p)
 {
        int i;
        for(i=xcnt-1; i>=0; i--)
-               if(xtst[i] == p)
+               if (xtst[i] == p)
                        return;
        printk("Bogus inode %p in %s\n", p, txt);
 }
@@ -123,7 +123,7 @@ static inline struct inode * grow_inodes(void)
        struct inode * res;
        struct inode * inode = res = (struct inode*)__get_free_page(GFP_KERNEL);
        int size = PAGE_SIZE;
-       if(!inode)
+       if (!inode)
                return NULL;
        
        size -= sizeof(struct inode);
@@ -178,7 +178,7 @@ static inline blocking int release_io(struct inode * inode, unsigned short flags
        int res = 0; 
        vfs_lock();
        inode->i_status &= ~flags;
-       if(inode->i_status & ST_WAITING) {
+       if (inode->i_status & ST_WAITING) {
                inode->i_status &= ~ST_WAITING;
                vfs_unlock();
                wake_up(&inode->i_wait);
@@ -191,10 +191,10 @@ static inline blocking void _io(void (*op)(struct inode*), struct inode * inode,
                                unsigned short waitflags, unsigned short setflags)
 {
        /* Do nothing if the same op is already in progress. */
-       if(op && !(inode->i_status & setflags)) {
+       if (op && !(inode->i_status & setflags)) {
                set_io(inode, waitflags, setflags);
                op(inode);
-               if(release_io(inode, setflags)) {
+               if (release_io(inode, setflags)) {
                        /* Somebody grabbed my inode from under me. */
 #ifdef DEBUG
                        printk("_io grab!\n");
@@ -204,36 +204,10 @@ static inline blocking void _io(void (*op)(struct inode*), struct inode * inode,
        }
 }
 
-blocking int _free_ibasket(struct super_block * sb)
-{
-       if(sb->s_ibasket) {
-               struct inode * delinquish = sb->s_ibasket->i_basket_prev;
-#if 0
-printpath(delinquish->i_dentry);
-printk(" delinquish\n");
-#endif
-               _clear_inode(delinquish, 0, 1);
-               return 1;
-       }
-       return 0;
-}
-
-static /*inline*/ void _put_ibasket(struct inode * inode)
-{
-       struct super_block * sb = inode->i_sb;
-       if(!(inode->i_status & ST_IBASKET)) {
-               inode->i_status |= ST_IBASKET;
-               insert_ibasket(&sb->s_ibasket, inode);
-               sb->s_ibasket_count++;
-               if(sb->s_ibasket_count > sb->s_ibasket_max)
-                       (void)_free_ibasket(sb);
-       }
-}
-
 blocking void _clear_inode(struct inode * inode, int external, int verbose)
 {
 xcheck("_clear_inode",inode);
-       if(inode->i_status & ST_IBASKET) {
+       if (inode->i_status & ST_IBASKET) {
                struct super_block * sb = inode->i_sb;
                remove_ibasket(&sb->s_ibasket, inode);
                sb->s_ibasket_count--;
@@ -243,32 +217,29 @@ printpath(inode->i_dentry);
 printk(" put_inode\n");
 #endif
                _io(sb->s_op->put_inode, inode, ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
-               if(inode->i_status & ST_EMPTY)
+               if (inode->i_status & ST_EMPTY)
                        return;
        }
-       if(inode->i_status & ST_HASHED)
+       if (inode->i_status & ST_HASHED)
                remove_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
-       if(inode->i_status & ST_AGED) {
+       if (inode->i_status & ST_AGED) {
                /* "cannot happen" when called from an fs because at least
                 * the caller must use it. Can happen when called from
                 * invalidate_inodes(). */
-               if(verbose)
+               if (verbose)
                        printk("VFS: clearing aged inode\n");
-               if(atomic_read(&inode->i_count))
+               if (atomic_read(&inode->i_count))
                        printk("VFS: aged inode is in use\n");
                remove_lru(&aged_i[inode->i_level], inode);
                inodes_stat.aged_count[inode->i_level]--;
        }
-       if(!external && inode->i_status & ST_IO) {
+       if (!external && inode->i_status & ST_IO) {
                printk("VFS: clearing inode during IO operation\n");
        }
-       if(!(inode->i_status & ST_EMPTY)) {
+       if (!(inode->i_status & ST_EMPTY)) {
                remove_all(&all_i, inode);
                inode->i_status = ST_EMPTY;
-               while(inode->i_dentry) {
-                       d_del(inode->i_dentry, D_NO_CLEAR_INODE);
-               }
-               if(inode->i_pages) {
+               if (inode->i_pages) {
                        vfs_unlock(); /* may block, can that be revised? */
                        truncate_inode_pages(inode, 0);
                        vfs_lock();
@@ -291,7 +262,7 @@ void insert_inode_hash(struct inode * inode)
 {
 xcheck("insert_inode_hash",inode);
        vfs_lock();
-       if(!(inode->i_status & ST_HASHED)) {
+       if (!(inode->i_status & ST_HASHED)) {
                insert_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
                inode->i_status |= ST_HASHED;
        } else
@@ -306,42 +277,42 @@ blocking struct inode * _get_empty_inode(void)
 
 retry:
        inode = empty_i;
-       if(inode) {
+       if (inode) {
                remove_all(&empty_i, inode);
                inodes_stat.nr_free_inodes--;
        } else if(inodes_stat.nr_inodes < max_inodes || retry > 2) {
                inode = grow_inodes();
        }
-       if(!inode) {
+       if (!inode) {
                int level;
                int usable = 0;
                for(level = 0; level <= NR_LEVELS; level++)
-                       if(aged_i[level]) {
+                       if (aged_i[level]) {
                                inode = aged_i[level]->i_lru_prev;
                                /* Here is the picking strategy, tune this */
-                               if(aged_reused[level] < (usable++ ?
+                               if (aged_reused[level] < (usable++ ?
                                                         inodes_stat.aged_count[level] :
                                                         2))
                                        break;
                                aged_reused[level] = 0;
                        }
-               if(inode) {
-                       if(!(inode->i_status & ST_AGED))
+               if (inode) {
+                       if (!(inode->i_status & ST_AGED))
                                printk("VFS: inode aging inconsistency\n");
-                       if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+                       if (atomic_read(&inode->i_count))
                                printk("VFS: i_count of aged inode is not zero\n");
-                       if(inode->i_dirt)
+                       if (inode->i_dirt)
                                printk("VFS: Hey, somebody made my aged inode dirty\n");
                        _clear_inode(inode, 0, 0);
                        goto retry;
                }
        }
-       if(!inode) {
+       if (!inode) {
                vfs_unlock();
                schedule();
-               if(retry > 10)
+               if (retry > 10)
                        panic("VFS: cannot repair inode shortage");
-               if(retry > 2)
+               if (retry > 2)
                        printk("VFS: no free inodes\n");
                retry++;
                vfs_lock();
@@ -363,8 +334,8 @@ static inline blocking struct inode * _get_empty_inode_hashed(dev_t i_dev,
 {
        struct inode ** base = &hashtable[hash(i_dev, i_ino)];
        struct inode * inode = *base;
-       if(inode) do {
-               if(inode->i_ino == i_ino && inode->i_dev == i_dev) {
+       if (inode) do {
+               if (inode->i_ino == i_ino && inode->i_dev == i_dev) {
                        atomic_inc(&inode->i_count);
                        printk("VFS: inode %lx is already in use\n", i_ino);
                        return inode;
@@ -391,17 +362,17 @@ blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino)
 
 void _get_inode(struct inode * inode)
 {
-       if(inode->i_status & ST_IBASKET) {
+       if (inode->i_status & ST_IBASKET) {
                inode->i_status &= ~ST_IBASKET;
                remove_ibasket(&inode->i_sb->s_ibasket, inode);
                inode->i_sb->s_ibasket_count--;
        }
-       if(inode->i_status & ST_AGED) {
+       if (inode->i_status & ST_AGED) {
                inode->i_status &= ~ST_AGED;
                remove_lru(&aged_i[inode->i_level], inode);
                inodes_stat.aged_count[inode->i_level]--;
                aged_reused[inode->i_level]++;
-               if(S_ISDIR(inode->i_mode))
+               if (S_ISDIR(inode->i_mode))
                        /* make dirs less thrashable */
                        inode->i_level = NR_LEVELS-1;
                else if(inode->i_nlink > 1)
@@ -410,30 +381,28 @@ void _get_inode(struct inode * inode)
                else if(++inode->i_reuse_count >= age_table[inode->i_level]
                        && inode->i_level < NR_LEVELS-1)
                        inode->i_level++;
-               if(atomic_read(&inode->i_count) != 1)
-                       printk("VFS: inode count was not zero\n");
+               if (atomic_read(&inode->i_count) != 1)
+                       printk("VFS: inode count was not zero (%d after ++)\n", atomic_read(&inode->i_count));
        } else if(inode->i_status & ST_EMPTY)
                printk("VFS: invalid reuse of empty inode\n");
 }
 
-blocking struct inode * __iget(struct super_block * sb,
-                              unsigned long i_ino,
-                              int crossmntp)
+blocking struct inode * iget(struct super_block * sb, unsigned long i_ino)
 {
        struct inode ** base;
        struct inode * inode;
        dev_t i_dev;
        
-       if(!sb)
+       if (!sb)
                panic("VFS: iget with sb == NULL");
        i_dev = sb->s_dev;
-       if(!i_dev)
+       if (!i_dev)
                panic("VFS: sb->s_dev is NULL\n");
        base = &hashtable[hash(i_dev, i_ino)];
        vfs_lock();
        inode = *base;
-       if(inode) do {
-               if(inode->i_ino == i_ino && inode->i_dev == i_dev) {
+       if (inode) do {
+               if (inode->i_ino == i_ino && inode->i_dev == i_dev) {
                        atomic_inc(&inode->i_count);
                        _get_inode(inode);
 
@@ -455,21 +424,14 @@ blocking struct inode * __iget(struct super_block * sb,
        inode = _get_empty_inode_hashed(i_dev, i_ino);
        inode->i_sb = sb;
        inode->i_flags = sb->s_flags;
-       if(sb->s_op && sb->s_op->read_inode) {
+       if (sb->s_op && sb->s_op->read_inode) {
                set_io(inode, 0, ST_TO_READ); /* do not wait at all */
                sb->s_op->read_inode(inode);
-               if(release_io(inode, ST_TO_READ))
+               if (release_io(inode, ST_TO_READ))
                        goto done;
        }
        vfs_unlock();
 done:
-       while(crossmntp && inode->i_mount) {
-               struct inode * tmp = inode->i_mount;
-               iinc(tmp);
-               iput(inode);
-               inode = tmp;
-       }
-xcheck("_iget",inode);
        return inode;
 }
 
@@ -477,68 +439,43 @@ blocking void __iput(struct inode * inode)
 {
        struct super_block * sb;
 xcheck("_iput",inode);
-       if(atomic_read(&inode->i_count) + inode->i_ddir_count < 0)
+
+       if (atomic_read(&inode->i_count) < 0)
                printk("VFS: i_count is negative\n");
-       if((atomic_read(&inode->i_count) + inode->i_ddir_count) ||
-          (inode->i_status & ST_FREEING)) {
+
+       if (atomic_read(&inode->i_count) || (inode->i_status & ST_FREEING))
                return;
-       }
+
        inode->i_status |= ST_FREEING;
-#ifdef CONFIG_OMIRR
-       if(inode->i_status & ST_MODIFIED) {
-               inode->i_status &= ~ST_MODIFIED;
-               omirr_printall(inode, " W %ld ", CURRENT_TIME);
-       }
-#endif
-       if(inode->i_pipe) {
+       if (inode->i_pipe) {
                free_page((unsigned long)PIPE_BASE(*inode));
                PIPE_BASE(*inode)= NULL;
        }
-       if((sb = inode->i_sb)) {
-               if(sb->s_type && (sb->s_type->fs_flags & FS_NO_DCACHE)) {
-                       while(inode->i_dentry)
-                               d_del(inode->i_dentry, D_NO_CLEAR_INODE);
-                       if(atomic_read(&inode->i_count) + inode->i_ddir_count)
-                               goto done;
-               }
-               if(sb->s_op) {
-                       if(inode->i_nlink <= 0 && inode->i_dent_count &&
-                          !(inode->i_status & (ST_EMPTY|ST_IBASKET)) &&
-                          (sb->s_type->fs_flags & FS_IBASKET)) {
-                               _put_ibasket(inode);
+       if ((sb = inode->i_sb)) {
+               if (sb->s_op) {
+                       if (inode->i_nlink <= 0 &&
+                           !(inode->i_status & (ST_EMPTY|ST_IBASKET))) {
+                               _clear_inode(inode, 0, 1);
                                goto done;
                        }
-                       if(!inode->i_dent_count ||
-                          (sb->s_type->fs_flags & FS_NO_DCACHE)) {
-                               _io(sb->s_op->put_inode, inode, 
-                                   ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
-                               if(atomic_read(&inode->i_count) + inode->i_ddir_count)
-                                       goto done;
-                               if(inode->i_nlink <= 0) {
-                                       if(!(inode->i_status & ST_EMPTY)) {
-                                               _clear_inode(inode, 0, 1);
-                                       }
-                                       goto done;
-                               }
-                       }
-                       if(inode->i_dirt) {
+                       if (inode->i_dirt) {
                                inode->i_dirt = 0;
                                _io(sb->s_op->write_inode, inode,
                                    ST_TO_PUT|ST_TO_WRITE, ST_TO_WRITE);
-                               if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+                               if (atomic_read(&inode->i_count))
                                        goto done;
                        }
                }
-               if(IS_WRITABLE(inode) && sb->dq_op) {
+               if (IS_WRITABLE(inode) && sb->dq_op) {
                        /* can operate in parallel to other ops ? */
                        _io(sb->dq_op->drop, inode, 0, ST_TO_DROP);
-                       if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+                       if (atomic_read(&inode->i_count))
                                goto done;
                }
        }
-       if(inode->i_mmap)
+       if (inode->i_mmap)
                printk("VFS: inode has mappings\n");
-       if(inode->i_status & ST_AGED) {
+       if (inode->i_status & ST_AGED) {
                printk("VFS: reaging inode\n");
 #if defined(DEBUG)
 printpath(inode->i_dentry);
@@ -546,11 +483,11 @@ printk("\n");
 #endif
                goto done;
        }
-       if(!(inode->i_status & (ST_HASHED|ST_EMPTY))) {
+       if (!(inode->i_status & (ST_HASHED|ST_EMPTY))) {
                _clear_inode(inode, 0, 1);
                goto done;
        }
-       if(inode->i_status & ST_EMPTY) {
+       if (inode->i_status & ST_EMPTY) {
                printk("VFS: aging an empty inode\n");
                goto done;
        }
@@ -573,10 +510,10 @@ blocking void sync_inodes(kdev_t dev)
        struct inode * inode;
        vfs_lock();
        inode = all_i;
-       if(inode) do {
+       if (inode) do {
 xcheck("sync_inodes",inode);
-               if(inode->i_dirt && (inode->i_dev == dev || !dev)) {
-                       if(inode->i_sb && inode->i_sb->s_op &&
+               if (inode->i_dirt && (inode->i_dev == dev || !dev)) {
+                       if (inode->i_sb && inode->i_sb->s_op &&
                           !(inode->i_status & ST_FREEING)) {
                                inode->i_dirt = 0; 
                                _io(inode->i_sb->s_op->write_inode, inode,
@@ -596,12 +533,12 @@ blocking int _check_inodes(kdev_t dev, int complain)
        vfs_lock();
 startover:
        inode = all_i;
-       if(inode) do {
+       if (inode) do {
                struct inode * next;
 xcheck("_check_inodes",inode);
                next = inode->i_next;
-               if(inode->i_dev == dev) {
-                       if(inode->i_dirt || atomic_read(&inode->i_count)) {
+               if (inode->i_dev == dev) {
+                       if (inode->i_dirt || atomic_read(&inode->i_count)) {
                                bad++;
                        } else {
                                _clear_inode(inode, 0, 0);
@@ -609,14 +546,14 @@ xcheck("_check_inodes",inode);
                                /* _clear_inode() may recursively clear other
                                 * inodes, probably also the next one.
                                 */
-                               if(next->i_status & ST_EMPTY)
+                               if (next->i_status & ST_EMPTY)
                                        goto startover;
                        }
                }
                inode = next;
        } while(inode != all_i);
        vfs_unlock();
-       if(complain && bad)
+       if (complain && bad)
                printk("VFS: %d inode(s) busy on removed device `%s'\n",
                       bad, kdevname(dev));
        return (bad == 0);
@@ -642,16 +579,14 @@ int fs_may_remount_ro(kdev_t dev)
        return 1; /* not checked any more */
 }
 
-int fs_may_umount(kdev_t dev, struct inode * mount_root)
+int fs_may_umount(kdev_t dev, struct dentry * root)
 {
        struct inode * inode;
        vfs_lock();
        inode = all_i;
-       if(inode) do {
-xcheck("fs_may_umount",inode);
-               if(inode->i_dev == dev && atomic_read(&inode->i_count))
-                       if(inode != mount_root || atomic_read(&inode->i_count) > 
-                          (inode->i_mount == inode ? 2 : 1)) {
+       if (inode) do {
+               if (inode->i_dev == dev && atomic_read(&inode->i_count))
+                       if (inode != root->d_inode) {
                                vfs_unlock();
                                return 0;
                        }
@@ -668,7 +603,7 @@ blocking struct inode * get_pipe_inode(void)
        struct inode * inode = get_empty_inode();
 
        PIPE_BASE(*inode) = (char*)__get_free_page(GFP_USER);
-       if(!(PIPE_BASE(*inode))) {
+       if (!(PIPE_BASE(*inode))) {
                iput(inode);
                return NULL;
        }
@@ -682,21 +617,6 @@ blocking struct inode * get_pipe_inode(void)
        inode->i_op = &pipe_inode_operations;
        PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
 
-       /* I hope this does not introduce security problems.
-        * Please check and give me response.
-        */
-       {
-               char dummyname[32];
-               struct qstr dummy = { dummyname, 0 };
-               struct dentry * new;
-               sprintf(dummyname, ".anonymous-pipe-%06lud", inode->i_ino);
-               dummy.len = strlen(dummyname);
-               vfs_lock();
-               new = d_alloc(the_root, dummy.len, 0);
-               if(new)
-                       d_add(new, inode, &dummy, D_BASKET);
-               vfs_unlock();
-       }
        return inode;
 }
 
index b6041ad922050bf67ceb661724c80f873ce70e6c..30d52fbe400604b0b6463f6afbb717c33293c6b0 100644 (file)
@@ -697,7 +697,7 @@ start_up:
        retval = -ENOENT;
        if (!old_bh)
                goto end_rename;
-       old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
+       old_inode = __iget(old_dir->i_sb, old_de->inode);
        if (!old_inode)
                goto end_rename;
        retval = -EPERM;
@@ -707,7 +707,7 @@ start_up:
                goto end_rename;
        new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
        if (new_bh) {
-               new_inode = __iget(new_dir->i_sb, new_de->inode, 0);
+               new_inode = __iget(new_dir->i_sb, new_de->inode);
                if (!new_inode) {
                        brelse(new_bh);
                        new_bh = NULL;
index c95b1a36733694607fd23a4332a3fe9cb0999d22..55a135ca1b7d89e3e1fcb7eaf907e227c58056f7 100644 (file)
@@ -12,7 +12,6 @@
  * lookup logic.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #undef DEBUG           /* some other debugging */
 
 
-/* local flags for __namei() */
-#define NAM_SEMLOCK        8 /* set a semlock on the last dir */
-#define NAM_TRANSCREATE   16 /* last component may be created, try "=CREATE#" suffix*/
-#define NAM_NO_TRAILSLASH 32 /* disallow trailing slashes by returning EISDIR */
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
 /* [Feb-1997 T. Schoebel-Theuer]
@@ -56,7 +51,7 @@
  * is done solely in the VFS level, such that <fs>_follow_link() is not
  * used any more and could be removed in future.  As a side effect,
  * dir_namei(), _namei() and follow_link() are now replaced with a single
- * function __namei() that can handle all the special cases of the former
+ * function lookup_dentry() that can handle all the special cases of the former
  * code.
  *
  * With the new dcache, the pathname is stored at each inode, at least as
@@ -95,13 +90,13 @@ static inline char * get_page(void)
        char * res;
        down(&quicklock);
        res = quicklist;
-       if(res) {
+       if (res) {
 #ifdef DEBUG
                char * tmp = res;
                int i;
                for(i=0; i<quickcount; i++)
                        tmp = *(char**)tmp;
-               if(tmp)
+               if (tmp)
                        printk("bad quicklist %x\n", (int)tmp);
 #endif
                quicklist = *(char**)res;
@@ -113,9 +108,21 @@ static inline char * get_page(void)
        return res;
 }
 
+/*
+ * Kernel pointers have redundant information, so we can use a
+ * scheme where we can return either an error code or a dentry
+ * pointer with the same return value.
+ *
+ * This should be a per-architecture thing, to allow different
+ * error and pointer decisions.
+ */
+#define ERR_PTR(err)   ((void *)((long)(err)))
+#define PTR_ERR(ptr)   ((long)(ptr))
+#define IS_ERR(ptr)    ((unsigned long)(ptr) > (unsigned long)(-1000))
+
 inline void putname(char * name)
 {
-       if(name) {
+       if (name) {
                down(&quicklock);
                *(char**)name = quicklist;
                quicklist = name;
@@ -160,7 +167,7 @@ int getname(const char * filename, char **result)
        int retval;
 
        tmp = get_page();
-       if(!tmp)
+       if (!tmp)
                return -ENOMEM;
        retval = do_getname(filename, tmp);
        if (retval < 0)
@@ -222,417 +229,216 @@ void put_write_access(struct inode * inode)
        inode->i_writecount--;
 }
 
-static /*inline */ int concat(struct qstr * name, struct qstr * appendix, char * buf)
-{
-       int totallen = name->len;
-       if(name->len > MAX_TRANS_FILELEN ||
-          appendix->len > MAX_TRANS_SUFFIX) {
-               return -ENAMETOOLONG;
-       }
-       memcpy(buf, name->name, name->len);
-       memcpy(buf + name->len, appendix->name, appendix->len);
-       totallen += appendix->len;
-       buf[totallen] = '\0';
-       return totallen;
-}
-
-/* Internal lookup() using the new generic dcache.
- * buf must only be supplied if appendix!=NULL.
+/*
+ * This is called when everything else fails, and we actually have
+ * to go to the low-level filesystem to find out what we should do..
+ *
+ * We get the directory semaphore, and after getting that we also
+ * make sure that nobody added the entry to the dcache in the meantime..
  */
-static int cached_lookup(struct inode * dir, struct qstr * name,
-                        struct qstr * appendix, char * buf,
-                        struct qstr * res_name, struct dentry ** res_entry,
-                        struct inode ** result)
+static struct dentry * real_lookup(struct dentry * dentry, struct qstr * name)
 {
-       struct qstr tmp = { name->name, name->len };
-       int error;
-       struct dentry * cached;
+       struct inode *dir = dentry->d_inode;
+       struct dentry *result;
+       struct inode *inode;
+       int error = -ENOTDIR;
 
-       *result = NULL;
-       if(name->len >= D_MAXLEN)
-               return -ENAMETOOLONG;
-       vfs_lock();
-       cached = d_lookup(dir, name, appendix);
-       if(cached) {
-               struct inode *inode = NULL;
+       down(&dir->i_sem);
 
-               if(cached->u.d_inode && (inode = d_inode(&cached))) {
-                       error = 0;
-                       if(appendix && res_name) {
-                               tmp.len = error = concat(name, appendix, buf);
-                               tmp.name = buf;
-                               if(error > 0)
-                                       error = 0;
-                       }
-               } else {
-                       error = -ENOENT;
+       error = -ENOTDIR;
+       if (dir->i_op && dir->i_op->lookup)
+               error = dir->i_op->lookup(dir, name, &inode);
+       result = ERR_PTR(error);
+
+       if (!error || error == -ENOENT) {
+               struct dentry *new;
+               int isdir = 0, flags = D_NOCHECKDUP;
+
+               if (error) {
+                       flags = D_NEGATIVE;
+                       inode = NULL;
+               } else if (S_ISDIR(inode->i_mode)) {
+                       isdir = 1;
+                       flags = D_DIR|D_NOCHECKDUP;
                }
-               vfs_unlock();
-               if(res_entry)
-                       *res_entry = cached;
+               new = d_alloc(dentry, name, isdir);
 
-               /* Since we are bypassing the iget() mechanism, we have to
-                * fabricate the act of crossing any mount points.
+               /*
+                * Ok, now we can't sleep any more. Double-check that
+                * nobody else added this in the meantime..
                 */
-               if(!error && inode && inode->i_mount) {
-                       do {
-                               struct inode *mnti = inode->i_mount;
-                               iinc(mnti);
-                               iput(inode);
-                               inode = mnti;
-                       } while(inode->i_mount);
+               result = d_lookup(dentry, name);
+               if (result) {
+                       d_free(new);
+               } else {
+                       d_add(new, inode, flags);
+                       result = new;
                }
-               *result = inode;
-               goto done;
-       } else
-               vfs_unlock();
-
-       if(appendix) {
-               tmp.len = error = concat(name, appendix, buf);
-               tmp.name = buf;
-               if(error < 0)
-                       goto done;
-       }
-       atomic_inc(&dir->i_count);
-       error = dir->i_op->lookup(dir, tmp.name, tmp.len, result);
-       if(dir->i_dentry && tmp.len &&
-          (!error || (error == -ENOENT && (!dir->i_sb || !dir->i_sb->s_type ||
-           !(dir->i_sb->s_type->fs_flags & FS_NO_DCACHE))))) {
-               struct dentry * res;
-               vfs_lock();
-               res = d_entry(dir->i_dentry, &tmp, error ? NULL : *result);
-               vfs_unlock();
-               if(res_entry)
-                       *res_entry = res;
        }
-done:
-       if(res_name) {
-                if(error) {
-                       res_name->name = name->name;
-                       res_name->len = name->len;
-                } else {
-                       res_name->name = tmp.name;
-                       res_name->len = tmp.len;
-                }
-       }
-       return error;
+       up(&dir->i_sem);
+       return result;
+}
+
+/* Internal lookup() using the new generic dcache. */
+static inline struct dentry * cached_lookup(struct dentry * dentry, struct qstr * name)
+{
+       return d_lookup(dentry, name);
 }
 
-#ifdef CONFIG_TRANS_NAMES
-/* If a normal filename is seen, try to determine whether a
- * "#keyword=context#" file exists and return the new filename.
- * If the name is to be created (create_mode), check whether a
- * "#keyword=CREATE" name exists and optionally return the corresponding
- * context name even if it didn't exist before.
+/*
+ * "." and ".." are special - ".." especially so because it has to be able
+ * to know about the current root directory and parent relationships
  */
-static int check_suffixes(struct inode * dir, struct qstr * name,
-                         int create_mode, char * buf,
-                         struct qstr * res_name, struct dentry ** res_entry,
-                         struct inode ** result)
+static struct dentry * reserved_lookup(struct dentry * dir, struct qstr * name)
 {
-       struct translations * trans;
-       char * env;
-       struct qstr * suffixes;
-       int i;
-       int error = -ENOENT;
-
-       if(!buf)
-               panic("buf==NULL");
-       env = env_transl();
-#ifdef CONFIG_TRANS_RESTRICT
-       if(!env && dir->i_gid != CONFIG_TRANS_GID) {
-               return error;
-        }
-#endif
-       trans = get_translations(env);
-       suffixes = create_mode ? trans->c_name : trans->name;
-       for(i = 0; i < trans->count; i++) {
-               error = cached_lookup(dir, name, &suffixes[i],
-                                     buf, res_name, res_entry, result);
-               if(!error) {
-                       if(res_name && create_mode) {
-                               /* buf == res_name->name, but is writable */
-                               memcpy(buf + name->len,
-                                      trans->name[i].name,
-                                      trans->name[i].len);
-                               res_name->len = name->len + trans->name[i].len;
-                                buf[res_name->len] = '\0';
+       struct dentry *result = NULL;
+       if (name->name[0] == '.') {
+               switch (name->len) {
+               default:
+                       break;
+               case 2: 
+                       if (name->name[1] != '.')
+                               break;
+
+                       if (dir != current->fs->root) {
+                               dir = dir->d_covers->d_parent;
                        }
+                       /* fallthrough */
+               case 1:
+                       result = dget(dir);
                        break;
                }
        }
-       if(env)
-               free_page((unsigned long)trans);
-       return error;
+       return result;
 }
 
-#endif
-
-/* Any operations involving reserved names at the VFS level should go here. */
-static /*inline*/ int reserved_lookup(struct inode * dir, struct qstr * name,
-                                     int create_mode, char * buf,
-                                     struct inode ** result)
+static inline int is_reserved(struct dentry *dentry)
 {
-       int error = -ENOENT;
-       if(name->name[0] == '.') {
-               if(name->len == 1) {
-                       *result = dir;
-                       error = 0;
-               } else if (name->len==2 && name->name[1] == '.') {
-                       if (dir == current->fs->root) {
-                               *result = dir;
-                               error = 0;
-                       }
-                       else if(dir->i_dentry) {
-                               error = 0;
-                               *result = dir->i_dentry->d_parent->u.d_inode;
-                               if(!*result) {
-                                       printk("dcache parent directory is lost");
-                                       error = -ESTALE;        /* random error */
-                               }
-                       }
+       if (dentry->d_name.name[0] == '.') {
+               switch (dentry->d_name.len) {
+               case 2:
+                       if (dentry->d_name.name[1] != '.')
+                               break;
+                       /* fallthrough */
+               case 1:
+                       return 1;
                }
-               if(!error)
-                       atomic_inc(&(*result)->i_count);
        }
-       return error;
+       return 0;
 }
 
 /* In difference to the former version, lookup() no longer eats the dir. */
-static /*inline*/ int lookup(struct inode * dir, struct qstr * name, int create_mode,
-                            char * buf, struct qstr * res_name,
-                            struct dentry ** res_entry, struct inode ** result)
+static struct dentry * lookup(struct dentry * dir, struct qstr * name)
 {
-       int perm;
-
-       *result = NULL;
-       perm = -ENOENT;
-       if (!dir)
-               goto done;
+       int err;
+       struct dentry * result;
 
        /* Check permissions before traversing mount-points. */
-       perm = permission(dir,MAY_EXEC);
-       if (perm)
+       err = permission(dir->d_inode, MAY_EXEC);
+       result = ERR_PTR(err);
+       if (err)
                goto done;
-       perm = reserved_lookup(dir, name, create_mode, buf, result);
-       if(!perm) {
-               if(res_name) {
-                       res_name->name = name->name;
-                       res_name->len = name->len;
-               }
+
+       result = reserved_lookup(dir, name);
+       if (result)
                goto done;
-       }
-       perm = -ENOTDIR;
-       if (!dir->i_op || !dir->i_op->lookup)
+
+       result = cached_lookup(dir, name);
+       if (result)
                goto done;
-#ifdef CONFIG_TRANS_NAMES /* try suffixes */
-       perm = check_suffixes(dir, name, 0, buf, res_name, res_entry, result);
-       if(perm) /* try original name */
-#endif
-               perm = cached_lookup(dir, name, NULL, buf, res_name, res_entry, result);
-#ifdef CONFIG_TRANS_NAMES
-       if(perm == -ENOENT && create_mode) { /* try the =CREATE# suffix */
-               struct inode * dummy;
-               if(!check_suffixes(dir, name, 1, buf, res_name, NULL, &dummy)) {
-                       iput(dummy);
-               }
-       }
-#endif
+
+       result = real_lookup(dir, name);
+       if (!result)
+               result = ERR_PTR(-ENOTDIR);
 done:
-       return perm;
+       if (!IS_ERR(result))
+               result = dget(result->d_mounts);
+
+       return result;
 }
 
-/* [8-Feb-97 T. Schoebel-Theuer] follow_link() modified for generic operation
- * on the VFS layer: first call <fs>_readlink() and then open_namei().
- * All <fs>_follow_link() are not used any more and may be eliminated
- * (by Linus; I refrained in order to not break other patches).
- * Single exeption is procfs, where proc_follow_link() is used
- * internally (and perhaps should be rewritten).
- * Note: [partly obsolete] I removed parameters flag and mode, since now
- * __namei() is called instead of open_namei(). In the old semantics,
- * the _last_ instance of open_namei() did the real create() if O_CREAT was
- * set and the name existed already in form of a symlink. This has been
- * simplified now, and also the semantics when combined with O_EXCL has changed.
- ****************************************************************************
- * [13-Feb-97] Complete rewrite -> functionality of reading symlinks factored
- * out into _read_link(). The above notes remain valid in principle.
+/*
+ * This should check "link_count", but doesn't do that yet..
  */
-static /*inline*/ int _read_link(struct inode * inode, char ** linkname, int loopcount)
+static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry)
 {
-       unsigned long old_fs;
-       int error;
+       struct inode * inode = dentry->d_inode;
 
-       error = -ENOSYS;
-       if (!inode->i_op || !inode->i_op->readlink)
-               goto done;
-       error = -ELOOP;
-       if (current->link_count + loopcount > 10)
-               goto done;
-       error = -ENOMEM;
-       if(!*linkname && !(*linkname = get_page()))
-               goto done;
-       if (DO_UPDATE_ATIME(inode)) {
-               inode->i_atime = CURRENT_TIME;
-               inode->i_dirt = 1;
-       }
-       atomic_inc(&inode->i_count);
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       error = inode->i_op->readlink(inode, *linkname, PAGE_SIZE);
-       set_fs(old_fs);
-       if(!error) {
-               error = -ENOENT; /* ? or other error code ? */
-       } else if(error > 0) {
-               (*linkname)[error] = '\0';
-               error = 0;
+       if (inode->i_op && inode->i_op->follow_link) {
+               struct dentry *result;
+
+               /* This eats the base */
+               result = inode->i_op->follow_link(inode, base);
+               base = dentry;
+               dentry = result;
        }
-done:
-       iput(inode);
-       return error;
+       dput(base);
+       return dentry;
 }
 
-/* [13-Feb-97 T. Schoebel-Theuer] complete rewrite:
- * merged dir_name(), _namei() and follow_link() into one new routine
- * that obeys all the special cases hidden in the old routines in a
- * (hopefully) systematic way:
- * parameter retrieve_mode is bitwise or'ed of the ST_* flags.
- * if res_inode is a NULL pointer, dont try to retrieve the last component
- * at all. Parameters with prefix last_ are used only if res_inode is
- * non-NULL and refer to the last component of the path only.
+/*
+ * Name resolution.
+ *
+ * This is the basic name resolution function, turning a pathname
+ * into the final dentry.
  */
-int __namei(int retrieve_mode, const char * name, struct inode * base,
-           char * buf, struct inode ** res_dir, struct inode ** res_inode,
-           struct qstr * last_name, struct dentry ** last_entry,
-           int * last_error)
+struct dentry * lookup_dentry(const char * name, struct dentry * base, int follow_link)
 {
-       char c;
-       struct qstr this;
-       char * linkname = NULL;
-       char * oldlinkname = NULL;
-       int trail_flag = 0;
-       int loopcount = 0;
-       int error;
-#ifdef DEBUG
-       if(last_name) {
-               last_name->name = "(Uninitialized)";
-               last_name->len = 15;
-       }
-#endif
-again:
-       error = -ENOENT;
-       this.name = name;
-       if (this.name[0] == '/') {
-               if(base)
-                       iput(base);
-               if (__prefix_namei(retrieve_mode, this.name, base, buf,
-                                  res_dir, res_inode,
-                                  last_name, last_entry, last_error) == 0)
-                       return 0;
-               base = current->fs->root;
-               atomic_inc(&base->i_count);
-               this.name++;
+       struct dentry * dentry;
+
+       if (*name == '/') {
+               if (base)
+                       dput(base);
+               base = dget(current->fs->root);
+               do {
+                       name++;
+               } while (*name == '/');
        } else if (!base) {
-               base = current->fs->pwd;
-               atomic_inc(&base->i_count);
+               base = dget(current->fs->pwd);
        }
+
+       if (*name == '\0')
+               return base;
+
+       /* At this point we know we have a real path component. */
        for(;;) {
-               struct inode * inode;
-               const char * tmp = this.name;
                int len;
+               unsigned long hash;
+               struct qstr this;
+               char c, trailing;
+
+               this.name = name;
+               hash = init_name_hash();
+               for (len = 0; (c = *name++) && (c != '/') ; len++)
+                       hash = partial_name_hash(c, hash);
 
-               for(len = 0; (c = *tmp++) && (c != '/'); len++) ;
                this.len = len;
-               if(!c)
-                       break;
-               while((c = *tmp) == '/') /* remove embedded/trailing slashes */
-                       tmp++;
-               if(!c) {
-                       trail_flag = 1;
-                       if(retrieve_mode & NAM_NO_TRAILSLASH) {
-                               error = -EISDIR;
-                               goto alldone;
-                       }
-                       break;          
-               }
-#if 0
-               if(atomic_read(&base->i_count) == 0)
-                       printk("vor lookup this=%s tmp=%s\n", this.name, tmp);
-#endif
-               error = lookup(base, &this, 0, buf, NULL, NULL, &inode);
-#if 0
-               if(atomic_read(&base->i_count) == 0)
-                       printk("nach lookup this=%s tmp=%s\n", this.name, tmp);
-#endif
-               if (error)
-                       goto alldone;
-               if(S_ISLNK(inode->i_mode)) {
-                       error = _read_link(inode, &linkname, loopcount);
-                       if(error)
-                               goto alldone;
-                       current->link_count++;
-                       error = __namei((retrieve_mode & 
-                                        ~(NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH))
-                                       | NAM_FOLLOW_LINK,
-                                       linkname, base, buf,
-                                       &base, &inode, NULL, NULL, NULL);
-                       current->link_count--;
-                       if(error)
-                               goto alldone;
-               }
-#if 0
-               if(atomic_read(&base->i_count) == 0)
-                       printk("this=%s tmp=%s\n", this.name, tmp);
-#endif
-               this.name = tmp;
-               iput(base);
-               base = inode;
-       }
-       if(res_inode) {
-               if(retrieve_mode & NAM_SEMLOCK)
-                       down(&base->i_sem);
-               error = lookup(base, &this, retrieve_mode & NAM_TRANSCREATE,
-                              buf, last_name, last_entry, res_inode);
-               if(!error && S_ISLNK((*res_inode)->i_mode) &&
-                  ((retrieve_mode & NAM_FOLLOW_LINK) ||
-                   (trail_flag && (retrieve_mode & NAM_FOLLOW_TRAILSLASH)))) {
-                       char * tmp;
-
-                       error = _read_link(*res_inode, &linkname, loopcount);
-                       if(error)
-                               goto lastdone;
-                       if(retrieve_mode & NAM_SEMLOCK)
-                               up(&base->i_sem);
-                       /* exchange pages */
-                       name = tmp = linkname;
-                       linkname = oldlinkname; oldlinkname = tmp;
-                       loopcount++;
-                       goto again; /* Tail recursion elimination "by hand",
-                                    * uses less dynamic memory.
-                                    */
-
-                       /* Note that trail_flag is not reset, so it
-                        * does not matter in a symlink chain where a
-                        * trailing slash indicates a directory endpoint.
-                        */
-               }
-               if(!error && trail_flag && !S_ISDIR((*res_inode)->i_mode)) {
-                       iput(*res_inode);
-                       error = -ENOTDIR;
+               this.hash = end_name_hash(hash);
+
+               /* remove trailing slashes? */
+               trailing = c;
+               if (c) {
+                       while ((c = *name) == '/')
+                               name++;
                }
-       lastdone:
-               if(last_error) {
-                       *last_error = error;
-                       error = 0;
+
+               dentry = lookup(base, &this);
+               if (IS_ERR(dentry))
+                       break;
+               if (dentry->d_flag & D_NEGATIVE)
+                       break;
+
+               /* Last component? */
+               if (!c) {
+                       if (!trailing && !follow_link)
+                               break;
+                       return do_follow_link(base, dentry);
                }
+
+               base = do_follow_link(base, dentry);
        }
-alldone:
-       if(!error && res_dir)
-               *res_dir = base;
-       else
-               iput(base);
-       putname(linkname);
-       putname(oldlinkname);
-       return error;
+       dput(base);
+       return dentry;
 }
 
 /*
@@ -641,26 +447,55 @@ alldone:
  * is used by most simple commands to get the inode of a specified name.
  * Open, link etc use their own routines, but this is enough for things
  * like 'chmod' etc.
+ *
+ * namei exists in two versions: namei/lnamei. The only difference is
+ * that namei follows links, while lnamei does not.
  */
-
-/* [Feb 1997 T.Schoebel-Theuer] lnamei() completely removed; can be
- * simulated when calling with retrieve_mode==NAM_FOLLOW_TRAILSLASH.
- */
-int namei(int retrieve_mode, const char *pathname, struct inode **res_inode)
+int __namei(const char *pathname, struct inode **res_inode, int follow_link)
 {
        int error;
-       char * tmp;
+       char * name;
 
-       error = getname(pathname, &tmp);
+       error = getname(pathname, &name);
        if (!error) {
-               char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-               error = __namei(retrieve_mode, tmp, NULL,
-                               buf, NULL, res_inode, NULL, NULL, NULL);
-               putname(tmp);
+               struct dentry * dentry;
+
+               dentry = lookup_dentry(name, NULL, follow_link);
+               putname(name);
+               error = PTR_ERR(dentry);
+               if (!IS_ERR(dentry)) {
+                       error = -ENOENT;
+                       if (dentry) {
+                               if (!(dentry->d_flag & D_NEGATIVE)) {
+                                       struct inode *inode = dentry->d_inode;
+                                       atomic_inc(&inode->i_count);
+                                       *res_inode = inode;
+                                       error = 0;
+                               }
+                               dput(dentry);
+                       }
+               }
        }
        return error;
 }
 
+static inline struct inode *get_parent(struct dentry *dentry)
+{
+       struct inode *dir = dentry->d_parent->d_inode;
+
+       atomic_inc(&dir->i_count);
+       return dir;
+}
+
+static inline struct inode *lock_parent(struct dentry *dentry)
+{
+       struct inode *dir = dentry->d_parent->d_inode;
+
+       atomic_inc(&dir->i_count);
+       down(&dir->i_sem);
+       return dir;
+}
+
 /*
  *     open_namei()
  *
@@ -675,172 +510,155 @@ int namei(int retrieve_mode, const char *pathname, struct inode **res_inode)
  * for symlinks (where the permissions are checked later).
  */
 int open_namei(const char * pathname, int flag, int mode,
-               struct inode ** res_inode, struct inode * base)
+               struct inode ** res_inode, struct dentry * base)
 {
-       char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       struct qstr last;
        int error;
-       int lasterror;
-       struct inode * dir, * inode;
-       int namei_mode;
+       struct inode *inode;
+       struct dentry *dentry;
 
        mode &= S_IALLUGO & ~current->fs->umask;
        mode |= S_IFREG;
 
-       namei_mode = NAM_FOLLOW_LINK;
-       if(flag & O_CREAT)
-               namei_mode |= NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH;
-       error = __namei(namei_mode, pathname, base, buf,
-                       &dir, &inode, &last, NULL, &lasterror);
-       if (error)
-               goto exit;
-       error = lasterror;
+       dentry = lookup_dentry(pathname, base, 1);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+
        if (flag & O_CREAT) {
-               if (!error) {
-                       if (flag & O_EXCL) {
+               struct inode *dir;
+
+               dir = lock_parent(dentry);
+               /*
+                * The existence test must be done _after_ getting the directory
+                * semaphore - the dentry might otherwise change.
+                */
+               if (!(dentry->d_flag & D_NEGATIVE)) {
+                       error = 0;
+                       if (flag & O_EXCL)
                                error = -EEXIST;
-                       }
                } else if (IS_RDONLY(dir))
                        error = -EROFS;
                else if (!dir->i_op || !dir->i_op->create)
                        error = -EACCES;
-               else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
-                       ;       /* error is already set! */
-               else {
-                       d_del(d_lookup(dir, &last, NULL), D_REMOVE);
-                       atomic_inc(&dir->i_count);      /* create eats the dir */
+               else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) == 0) {
                        if (dir->i_sb && dir->i_sb->dq_op)
                                dir->i_sb->dq_op->initialize(dir, -1);
-                       error = dir->i_op->create(dir, last.name, last.len,
-                                                 mode, res_inode);
-#ifdef CONFIG_OMIRR
-                       if(!error)
-                               omirr_print(dir->i_dentry, NULL, &last,
-                                           " c %ld %d ", CURRENT_TIME, mode);
-#endif
-                       up(&dir->i_sem);
-                       goto exit_dir;
+                       error = dir->i_op->create(dir, dentry, mode);
                }
                up(&dir->i_sem);
+               iput(dir);
+               if (error)
+                       goto exit;
        }
+
+       error = -ENOENT;
+       if (dentry->d_flag & D_NEGATIVE)
+               goto exit;
+
+       inode = dentry->d_inode;
+       error = -EISDIR;
+       if (S_ISDIR(inode->i_mode) && (flag & 2))
+               goto exit;
+
+       error = permission(inode,ACC_MODE(flag));
        if (error)
-               goto exit_inode;
+               goto exit;
 
-       if (S_ISDIR(inode->i_mode) && (flag & 2)) {
-               error = -EISDIR;
-               goto exit_inode;
-       }
-       if ((error = permission(inode,ACC_MODE(flag))) != 0) {
-               goto exit_inode;
-       }
+       /*
+        * FIFO's, sockets and device files are special: they don't
+        * actually live on the filesystem itself, and as such you
+        * can write to them even if the filesystem is read-only.
+        */
        if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
-               /*
-                * 2-Feb-1995 Bruce Perens <Bruce@Pixar.com>
-                * Allow opens of Unix domain sockets and FIFOs for write on
-                * read-only filesystems. Their data does not live on the disk.
-                *
-                * If there was something like IS_NODEV(inode) for
-                * pipes and/or sockets I'd check it here.
-                */
                flag &= ~O_TRUNC;
-       }
-       else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-               if (IS_NODEV(inode)) {
-                       error = -EACCES;
-                       goto exit_inode;
-               }
+       } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
+               error = -EACCES;
+               if (IS_NODEV(inode))
+                       goto exit;
+
                flag &= ~O_TRUNC;
        } else {
-               if (IS_RDONLY(inode) && (flag & 2)) {
-                       error = -EROFS;
-                       goto exit_inode;
-               }
+               error = -EROFS;
+               if (IS_RDONLY(inode) && (flag & 2))
+                       goto exit;
        }
        /*
         * An append-only file must be opened in append mode for writing.
         */
-       if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND))) {
-               error = -EPERM;
-               goto exit_inode;
-       }
+       error = -EPERM;
+       if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND)))
+               goto exit;
+
        if (flag & O_TRUNC) {
-               if ((error = get_write_access(inode)))
-                       goto exit_inode;
+               error = get_write_access(inode);
+               if (error)
+                       goto exit;
+
                /*
                 * Refuse to truncate files with mandatory locks held on them.
                 */
                error = locks_verify_locked(inode);
-               if (error)
-                       goto exit_inode;
-               if (inode->i_sb && inode->i_sb->dq_op)
-                       inode->i_sb->dq_op->initialize(inode, -1);
+               if (!error) {
+                       if (inode->i_sb && inode->i_sb->dq_op)
+                               inode->i_sb->dq_op->initialize(inode, -1);
                        
-               error = do_truncate(inode, 0);
+                       error = do_truncate(inode, 0);
+               }
                put_write_access(inode);
+               if (error)
+                       goto exit;
        } else
                if (flag & FMODE_WRITE)
                        if (inode->i_sb && inode->i_sb->dq_op)
                                inode->i_sb->dq_op->initialize(inode, -1);
-exit_inode:
-       if(error) {
-               if(!lasterror)
-                       iput(inode);
-       } else
-               *res_inode = inode;
-exit_dir:
-       iput(dir);
+
+       *res_inode = inode;
+       atomic_inc(&inode->i_count);
+       error = 0;
+
 exit:
+       dput(dentry);
        return error;
 }
 
 int do_mknod(const char * filename, int mode, dev_t dev)
 {
-       char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       struct qstr last;
-       int error, lasterror;
-       struct inode * dir;
-       struct inode * inode;
+       int error;
+       struct inode *dir;
+       struct dentry *dentry;
 
        mode &= ~current->fs->umask;
-       error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH,
-                       filename, NULL, buf,
-                       &dir, &inode, &last, NULL, &lasterror);
-       if (error)
+       dentry = lookup_dentry(filename, NULL, 1);
+
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
                goto exit;
-       if(!lasterror) {
-               error = -EEXIST;
-               goto exit_inode;
-       }
-       if (!last.len) {
-               error = -ENOENT;
-               goto exit_inode;
-       }
-       if (IS_RDONLY(dir)) {
-               error = -EROFS;
-               goto exit_inode;
-       }
-       if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
-               goto exit_inode;
-       if (!dir->i_op || !dir->i_op->mknod) {
-               error = -ENOSYS; /* instead of EPERM, what does Posix say? */
-               goto exit_inode;
-       }
-       atomic_inc(&dir->i_count);
+
+       dir = lock_parent(dentry);
+
+       error = -EEXIST;
+       if (!(dentry->d_flag & D_NEGATIVE))
+               goto exit_lock;
+
+       error = -EROFS;
+       if (IS_RDONLY(dir))
+               goto exit_lock;
+
+       error = permission(dir,MAY_WRITE | MAY_EXEC);
+       if (error)
+               goto exit_lock;
+
+       error = -EPERM;
+       if (!dir->i_op || !dir->i_op->mknod)
+               goto exit_lock;
+
        if (dir->i_sb && dir->i_sb->dq_op)
                dir->i_sb->dq_op->initialize(dir, -1);
-       down(&dir->i_sem);
-       d_del(d_lookup(dir, &last, NULL), D_REMOVE);
-       error = dir->i_op->mknod(dir, last.name, last.len, mode, dev);
-#ifdef CONFIG_OMIRR
-       if(!error)
-               omirr_print(dir->i_dentry, NULL, &last, " n %ld %d %d ",
-                           CURRENT_TIME, mode, dev);
-#endif
+       error = dir->i_op->mknod(dir, dentry, mode, dev);
+
+exit_lock:
        up(&dir->i_sem);
-exit_inode:
-       if(!lasterror)
-               iput(inode);
        iput(dir);
+       dput(dentry);
 exit:
        return error;
 }
@@ -874,58 +692,48 @@ out:
        return error;
 }
 
-/* [Feb-97 T. Schoebel-Theuer] remove_trailing_slashes() is now obsolete,
- * its functionality is handled by observing trailing slashes in __namei().
+/*
+ * Look out: this function may change a normal dentry
+ * into a directory dentry (different size)..
  */
 static inline int do_mkdir(const char * pathname, int mode)
 {
-       char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       struct qstr last;
-       int error, lasterror;
-       struct inode * dir;
-       struct inode * inode;
+       int error;
+       struct inode *dir;
+       struct dentry *dentry;
 
-       mode &= 0777 & ~current->fs->umask;
+       dentry = lookup_dentry(pathname, NULL, 1);
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
+               goto exit;
 
-       error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, pathname, NULL, buf,
-                       &dir, &inode, &last, NULL, &lasterror);
+       dir = lock_parent(dentry);
+
+       error = -EEXIST;
+       if (!(dentry->d_flag & D_NEGATIVE))
+               goto exit_lock;
+
+       error = -EROFS;
+       if (IS_RDONLY(dir))
+               goto exit_lock;
+
+       error = permission(dir,MAY_WRITE | MAY_EXEC);
        if (error)
-               goto exit;
-       if(!lasterror) {
-               error = -EEXIST;
-               goto exit_inode;
-       }
-       if (!last.len) {
-               error = -ENOENT;
-               goto exit_inode;
-       }
-       if (IS_RDONLY(dir)) {
-               error = -EROFS;
-               goto exit_inode;
-       }
-       if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
-               goto exit_inode;
-       if (!dir->i_op || !dir->i_op->mkdir) {
-               error = -ENOSYS; /* instead of EPERM, what does Posix say? */
-               goto exit_inode;
-       }
-       atomic_inc(&dir->i_count);
+               goto exit_lock;
+
+       error = -EPERM;
+       if (!dir->i_op || !dir->i_op->mkdir)
+               goto exit_lock;
+
        if (dir->i_sb && dir->i_sb->dq_op)
                dir->i_sb->dq_op->initialize(dir, -1);
-       down(&dir->i_sem);
-       d_del(d_lookup(dir, &last, NULL), D_REMOVE);
-       mode &= 01777 & ~current->fs->umask;
-       error = dir->i_op->mkdir(dir, last.name, last.len, mode);
-#ifdef CONFIG_OMIRR
-       if(!error)
-               omirr_print(dir->i_dentry, NULL, &last, " d %ld %d ",
-                           CURRENT_TIME, mode);
-#endif
+       mode &= 0777 & ~current->fs->umask;
+       error = dir->i_op->mkdir(dir, dentry, mode);
+
+exit_lock:
        up(&dir->i_sem);
-exit_inode:
-       if(!lasterror)
-               iput(inode);
        iput(dir);
+       dput(dentry);
 exit:
        return error;
 }
@@ -945,124 +753,55 @@ asmlinkage int sys_mkdir(const char * pathname, int mode)
        return error;
 }
 
-#if 0 /* We need a "deletefs", someone please write it.  -DaveM */
-/* Perhaps this could be moved out into a new file. */
-static void basket_name(struct inode * dir, struct dentry * entry)
-{
-       char prefix[32];
-       struct qstr prename = { prefix, 14 };
-       struct qstr entname = { entry->d_name.name, entry->d_name.len };
-       struct inode * inode;
-       struct dentry * old = entry; /* dummy */
-       int i;
-       if(!entry || !(inode = d_inode(&entry)))
-               return;
-#if 0
-       if(atomic_read(&inode->i_count) > 2) {
-               extern void printpath(struct dentry *entry);
-
-               printk("Caution: in use ");
-               if(inode->i_dentry)
-                       printpath(inode->i_dentry);
-               printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n",
-                      inode->i_nlink, atomic_read(&inode->i_count),
-                      inode->i_ddir_count, inode->i_dent_count);
-       }
-#endif
-        vfs_lock();
-       for(i = 1; old; i++) {
-               sprintf(prefix, ".deleted-%04d.", i);
-               old = d_lookup(dir, &prename, &entname);
-       }
-       d_move(entry, dir, &prename, &entname);
-        vfs_unlock();
-       iput(inode);
-}
-#endif
-
 static inline int do_rmdir(const char * name)
 {
-       char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       struct qstr last;
-       struct dentry * lastent = NULL;
        int error;
-       struct inode * dir;
-       struct inode * inode;
-
-       /* [T.Schoebel-Theuer] I'm not sure which flags to use here.
-        *  Try the following on different platforms:
-        * [0] rm -rf test test2
-        * [1] ln -s test2 test
-        * [2] mkdir test  || mkdir test2
-        * [3] rmdir test  && mkdir test2
-        * [4] rmdir test/
-        * Now the rusults:
-        * cmd  |   HP-UX   |  SunOS   |  Solaris | Old Linux | New Linux |
-        * ----------------------------------------------------------------
-        * [2]  |   (OK)    |  EEXIST  |  EEXIST  |  EEXIST   |  (OK)
-        * [3]  |  ENOTDIR  |  ENOTDIR |  ENOTDIR |  ENOTDIR  |  ENOTDIR
-        * [4]  |   (OK)    |  EINVAL  |  ENOTDIR |  ENOTDIR  |  (OK)
-        * So I implemented the HP-UX semantics. If this is not right
-        * for Posix compliancy, change the flags accordingly. If Posix
-        * let the question open, I'd suggest to stay at the new semantics.
-        * I'd even make case [3] work by adding 2 to the flags parameter
-        * if Posix tolerates that.
-        */
-       error = __namei(NAM_FOLLOW_TRAILSLASH, name, NULL, buf,
-                       &dir, &inode, &last, &lastent, NULL);
-       if (error)
+       struct inode *dir;
+       struct dentry *dentry;
+
+       dentry = lookup_dentry(name, NULL, 1);
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
                goto exit;
-       if (IS_RDONLY(dir)) {
-               error = -EROFS;
-               goto exit_dir;
-       }
-       if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
-               goto exit_dir;
+
+       dir = lock_parent(dentry);
+       error = -ENOENT;
+       if (dentry->d_flag & D_NEGATIVE)
+               goto exit_lock;
+
+       error = -EROFS;
+       if (IS_RDONLY(dir))
+               goto exit_lock;
+
+       error = permission(dir,MAY_WRITE | MAY_EXEC);
+       if (error)
+               goto exit_lock;
+
        /*
         * A subdirectory cannot be removed from an append-only directory.
         */
-       if (IS_APPEND(dir)) {
-               error = -EPERM;
-               goto exit_dir;
-       }
-       if (!dir->i_op || !dir->i_op->rmdir) {
-               error = -ENOSYS; /* was EPERM */
-               goto exit_dir;
-       }
+       error = -EPERM;
+       if (IS_APPEND(dir))
+               goto exit_lock;
+
        /* Disallow removals of mountpoints. */
-       if(inode->i_mount) {
-               error = -EBUSY;
-               goto exit_dir;
-       }
+       error = -EBUSY;
+       if (dentry->d_covers != dentry)
+               goto exit_lock;
+
+       error = -EPERM;
+       if (!dir->i_op || !dir->i_op->rmdir)
+               goto exit_lock;
+
        if (dir->i_sb && dir->i_sb->dq_op)
                dir->i_sb->dq_op->initialize(dir, -1);
 
-        down(&dir->i_sem);
-#if 0
-       if(lastent && d_isbasket(lastent)) {
-               d_del(lastent, D_REMOVE);
-               error = 0;
-               goto exit_lock;
-       }
-#endif
-       atomic_inc(&dir->i_count);
-       error = dir->i_op->rmdir(dir, last.name, last.len);
-#ifdef CONFIG_OMIRR
-       if(!error)
-               omirr_print(lastent, NULL, NULL, " r %ld ", CURRENT_TIME);
-#endif
-#if 0
-       if(!error && lastent)
-               basket_name(dir, lastent);
+       error = dir->i_op->rmdir(dir, dentry);
+
 exit_lock:
-#else
-       if(!error && lastent)
-               d_del(lastent, D_REMOVE);
-#endif
         up(&dir->i_sem);
-exit_dir:
-       iput(inode);
-       iput(dir);
+        iput(dir);
+       dput(dentry);
 exit:
        return error;
 }
@@ -1084,90 +823,45 @@ asmlinkage int sys_rmdir(const char * pathname)
 
 static inline int do_unlink(const char * name)
 {
-       char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       struct qstr last;
-       struct dentry * lastent = NULL;
        int error;
-       struct inode * dir;
-       struct inode * inode;
-
-       /* HP-UX shows a strange behaviour:
-        * touch y; ln -s y x; rm x/
-        * this succeeds and removes the file y, not the symlink x!
-        * Solaris and old Linux remove the symlink instead, and
-        * old SunOS complains ENOTDIR.
-        * I chose the SunOS behaviour (by not using NAM_FOLLOW_TRAILSLASH),
-        * but I'm not shure whether I should.
-        * The current code generally prohibits using trailing slashes with
-        * non-directories if the name already exists, but not if
-        * it is to be newly created. 
-        * Perhaps this should be further strengthened (by introducing
-        * an additional flag bit indicating whether trailing slashes are
-        * allowed) to get it as consistant as possible, but I don't know
-        * what Posix says.
-        */
-       error = __namei(NAM_NO_TRAILSLASH, name, NULL, buf,
-                       &dir, &inode, &last, &lastent, NULL);
-       if (error)
+       struct inode *dir;
+       struct dentry *dentry;
+
+       dentry = lookup_dentry(name, NULL, 0);
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
                goto exit;
-       if (IS_RDONLY(dir)) {
-               error = -EROFS;
-               goto exit_dir;
-       }
-       if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
-               goto exit_dir;
+
+       dir = lock_parent(dentry);
+
+       error = -EROFS;
+       if (IS_RDONLY(dir))
+               goto exit_lock;
+
+       error = permission(dir,MAY_WRITE | MAY_EXEC);
+       if (error)
+               goto exit_lock;
+
        /*
         * A file cannot be removed from an append-only directory.
         */
-       if (IS_APPEND(dir)) {
-               error = -EPERM;
-               goto exit_dir;
-       }
-       if (!dir->i_op || !dir->i_op->unlink) {
-               error = -ENOSYS; /* was EPERM */
-               goto exit_dir;
-       }
+       error = -EPERM;
+       if (IS_APPEND(dir))
+               goto exit_lock;
+
+       error = -EPERM;
+       if (!dir->i_op || !dir->i_op->unlink)
+               goto exit_lock;
+
        if (dir->i_sb && dir->i_sb->dq_op)
                dir->i_sb->dq_op->initialize(dir, -1);
 
-        down(&dir->i_sem);
-#if 0
-       if(atomic_read(&inode->i_count) > 1) {
-               extern void printpath(struct dentry *entry);
-
-               printk("Fire ");
-               if(lastent)
-                       printpath(lastent);
-               printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n",
-                      inode->i_nlink, atomic_read(&inode->i_count),
-                      inode->i_ddir_count, inode->i_dent_count);
-       }
-#endif
-#if 0
-       if(lastent && d_isbasket(lastent)) {
-               d_del(lastent, D_REMOVE);
-               error = 0;
-               goto exit_lock;
-       }
-#endif
-       atomic_inc(&dir->i_count);
-       error = dir->i_op->unlink(dir, last.name, last.len);
-#ifdef CONFIG_OMIRR
-       if(!error)
-               omirr_print(lastent, NULL, NULL, " u %ld ", CURRENT_TIME);
-#endif
-#if 0
-       if(!error && lastent)
-               basket_name(dir, lastent);
+       error = dir->i_op->unlink(dir, dentry);
+
 exit_lock:
-#else
-       if(!error && lastent)
-               d_del(lastent, D_REMOVE);
-#endif
         up(&dir->i_sem);
-exit_dir:
-       iput(inode);
-       iput(dir);
+        iput(dir);
+       dput(dentry);
 exit:
        return error;
 }
@@ -1189,62 +883,42 @@ asmlinkage int sys_unlink(const char * pathname)
 
 static inline int do_symlink(const char * oldname, const char * newname)
 {
-       char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       struct qstr last;
-       int error, lasterror;
-       struct inode * dir;
-       struct inode * inode;
-
-       /* The following works on HP-UX and Solaris, by producing
-        * a symlink chain:
-        * rm -rf ? ; mkdir z ; ln -s z y ; ln -s y x/
-        * Under old SunOS, the following occurs:
-        * ln: x/: No such file or directory
-        * Under old Linux, very strange things occur:
-        * ln: cannot create symbolic link `x//y' to `y': No such file or directory
-        * This is very probably a bug, but may be caused by the ln program
-        * when checking for a directory target.
-        *
-        * I'm not shure whether to add NAM_NO_TRAILSLASH to inhibit trailing
-        * slashes in the target generally.
-        */
-       error = __namei(NAM_TRANSCREATE, newname, NULL, buf,
-                       &dir, &inode, &last, NULL, &lasterror);
-       if (error)
+       int error;
+       struct inode *dir;
+       struct dentry *dentry;
+
+       dentry = lookup_dentry(newname, NULL, 0);
+
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
                goto exit;
-       if(!lasterror) {
-               iput(inode);
-               error = -EEXIST;
-               goto exit_dir;
-       }
-       if (!last.len) {
-               error = -ENOENT;
-               goto exit_dir;
-       }
-       if (IS_RDONLY(dir)) {
-               error = -EROFS;
-               goto exit_dir;
-       }
-       if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
-               goto exit_dir;
-       if (!dir->i_op || !dir->i_op->symlink) {
-               error = -ENOSYS; /* was EPERM */
-               goto exit_dir;
-       }
-       atomic_inc(&dir->i_count);
+
+       error = -EEXIST;
+       if (!(dentry->d_flag & D_NEGATIVE))
+               goto exit;
+
+       dir = lock_parent(dentry);
+
+       error = -EROFS;
+       if (IS_RDONLY(dir))
+               goto exit_lock;
+
+       error = permission(dir,MAY_WRITE | MAY_EXEC);
+       if (error)
+               goto exit_lock;
+
+       error = -EPERM;
+       if (!dir->i_op || !dir->i_op->symlink)
+               goto exit_lock;
+
        if (dir->i_sb && dir->i_sb->dq_op)
                dir->i_sb->dq_op->initialize(dir, -1);
-       down(&dir->i_sem);
-       d_del(d_lookup(dir, &last, NULL), D_REMOVE);
-       error = dir->i_op->symlink(dir, last.name, last.len, oldname);
-#ifdef CONFIG_OMIRR
-       if(!error)
-               omirr_print(dir->i_dentry, NULL, &last,
-                           " s %ld %s\0", CURRENT_TIME, oldname);
-#endif
+       error = dir->i_op->symlink(dir, dentry, oldname);
+
+exit_lock:
        up(&dir->i_sem);
-exit_dir:
        iput(dir);
+       dput(dentry);
 exit:
        return error;
 }
@@ -1270,73 +944,64 @@ asmlinkage int sys_symlink(const char * oldname, const char * newname)
 
 static inline int do_link(const char * oldname, const char * newname)
 {
-       char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       struct qstr oldlast;
-       struct qstr newlast;
-       struct dentry * oldent = NULL;
-       struct inode * oldinode;
-       struct inode * newinode;
-       struct inode * newdir;
-       int error, lasterror;
-
-       error = __namei(NAM_FOLLOW_LINK|NAM_NO_TRAILSLASH,
-                       oldname, NULL, oldbuf,
-                       NULL, &oldinode, &oldlast, &oldent, NULL);
-       if (error)
+       struct dentry *old_dentry, *new_dentry;
+       struct inode *dir, *inode;
+       int error;
+
+       old_dentry = lookup_dentry(oldname, NULL, 1);
+       error = PTR_ERR(old_dentry);
+       if (IS_ERR(old_dentry))
                goto exit;
 
-       error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf,
-                       &newdir, &newinode, &newlast, NULL, &lasterror);
+       new_dentry = lookup_dentry(newname, NULL, 1);
+       error = PTR_ERR(new_dentry);
+       if (IS_ERR(new_dentry))
+               goto exit_old;
+
+       dir = lock_parent(new_dentry);
+
+       error = -ENOENT;
+       if (old_dentry->d_flag & D_NEGATIVE)
+               goto exit_lock;
+
+       error = -EEXIST;
+       if (!(new_dentry->d_flag & D_NEGATIVE))
+               goto exit_lock;
+
+       error = -EROFS;
+       if (IS_RDONLY(dir))
+               goto exit_lock;
+
+       inode = old_dentry->d_inode;
+       error = -EXDEV;
+       if (dir->i_dev != inode->i_dev)
+               goto exit_lock;
+
+       error = permission(dir, MAY_WRITE | MAY_EXEC);
        if (error)
-               goto old_exit;
-       if(!lasterror) {
-               iput(newinode);
-               error = -EEXIST;
-               goto new_exit;
-       }
-       if (!newlast.len) {
-               error = -EPERM;
-               goto new_exit;
-       }
-       if (IS_RDONLY(newdir)) {
-               error = -EROFS;
-               goto new_exit;
-       }
-       if (newdir->i_dev != oldinode->i_dev) {
-               error = -EXDEV;
-               goto new_exit;
-       }
-       if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0)
-               goto new_exit;
+               goto exit_lock;
+
        /*
         * A link to an append-only or immutable file cannot be created.
         */
-       if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
-               error = -EPERM;
-               goto new_exit;
-       }
-       if (!newdir->i_op || !newdir->i_op->link) {
-               error = -ENOSYS; /* was EPERM */
-               goto new_exit;
-       }
-       atomic_inc(&oldinode->i_count);
-       atomic_inc(&newdir->i_count);
-       if (newdir->i_sb && newdir->i_sb->dq_op)
-               newdir->i_sb->dq_op->initialize(newdir, -1);
-       down(&newdir->i_sem);
-       d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE);
-       error = newdir->i_op->link(oldinode, newdir, newlast.name, newlast.len);
-#ifdef CONFIG_OMIRR
-       if(!error)
-               omirr_print(oldent, newdir->i_dentry, &newlast,
-                           " l %ld ", CURRENT_TIME);
-#endif
-       up(&newdir->i_sem);
-new_exit:
-       iput(newdir);
-old_exit:
-       iput(oldinode);
+       error = -EPERM;
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               goto exit_lock;
+
+       error = -EPERM;
+       if (!dir->i_op || !dir->i_op->link)
+               goto exit_lock;
+
+       if (dir->i_sb && dir->i_sb->dq_op)
+               dir->i_sb->dq_op->initialize(dir, -1);
+       error = dir->i_op->link(inode, dir, new_dentry);
+
+exit_lock:
+       up(&dir->i_sem);
+       iput(dir);
+       dput(new_dentry);
+exit_old:
+       dput(old_dentry);
 exit:
        return error;
 }
@@ -1360,105 +1025,98 @@ asmlinkage int sys_link(const char * oldname, const char * newname)
        return error;
 }
 
+/*
+ * Whee.. Deadlock country. Happily there is only one VFS
+ * operation that does this..
+ */
+static inline void double_down(struct semaphore *s1, struct semaphore *s2)
+{
+       if ((unsigned long) s1 < (unsigned long) s2) {
+               down(s1);
+               down(s2);
+       } else if (s1 == s2) {
+               down(s1);
+               atomic_dec(&s1->count);
+       } else {
+               down(s2);
+               down(s1);
+       }
+}
+
 static inline int do_rename(const char * oldname, const char * newname)
 {
-       char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       struct qstr oldlast;
-       char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
-       struct qstr newlast;
-       struct dentry * oldent = NULL;
-       struct inode * olddir, * newdir;
-       struct inode * oldinode, * newinode;
-       int error, newlasterror;
-
-       error = __namei(NAM_FOLLOW_TRAILSLASH, oldname, NULL, oldbuf,
-                       &olddir, &oldinode, &oldlast, &oldent, NULL);
-       if (error)
+       int error;
+       struct inode * old_dir, * new_dir;
+       struct dentry * old_dentry, *new_dentry;
+
+       old_dentry = lookup_dentry(oldname, NULL, 1);
+
+       error = PTR_ERR(old_dentry);
+       if (IS_ERR(old_dentry))
                goto exit;
-       if ((error = permission(olddir,MAY_WRITE | MAY_EXEC)) != 0)
-               goto old_exit;
-       if (!oldlast.len || (oldlast.name[0] == '.' &&
-           (oldlast.len == 1 || (oldlast.name[1] == '.' &&
-            oldlast.len == 2)))) {
-               error = -EPERM;
-               goto old_exit;
-       }
-       /* Disallow moves of mountpoints. */
-       if(oldinode->i_mount) {
-               error = -EBUSY;
-               goto old_exit;
-       }
 
-       error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf,
-                       &newdir, &newinode, &newlast, NULL, &newlasterror);
+       new_dentry = lookup_dentry(newname, NULL, 1);
+
+       error = PTR_ERR(new_dentry);
+       if (IS_ERR(new_dentry))
+               goto exit_old;
+
+       new_dir = get_parent(new_dentry);
+       old_dir = get_parent(old_dentry);
+
+       double_down(&new_dir->i_sem, &old_dir->i_sem);
+
+       error = -ENOENT;
+       if (old_dentry->d_flag & D_NEGATIVE)
+               goto exit_lock;
+
+       error = permission(old_dir,MAY_WRITE | MAY_EXEC);
        if (error)
-               goto old_exit;
-       if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0)
-               goto new_exit;
-       if (!newlast.len || (newlast.name[0] == '.' &&
-           (newlast.len == 1 || (newlast.name[1] == '.' &&
-            newlast.len == 2)))) {
-               error = -EPERM;
-               goto new_exit;
-       }
-       if (newdir->i_dev != olddir->i_dev) {
-               error = -EXDEV;
-               goto new_exit;
-       }
-       if (IS_RDONLY(newdir) || IS_RDONLY(olddir)) {
-               error = -EROFS;
-               goto new_exit;
-       }
+               goto exit_lock;
+       error = permission(new_dir,MAY_WRITE | MAY_EXEC);
+       if (error)
+               goto exit_lock;
+
+       error = -EPERM;
+       if (is_reserved(new_dentry) || is_reserved(old_dentry))
+               goto exit_lock;
+
+       /* Disallow moves of mountpoints. */
+       error = -EBUSY;
+       if (old_dentry->d_covers != old_dentry)
+               goto exit_lock;
+
+       error = -EXDEV;
+       if (new_dir->i_dev != old_dir->i_dev)
+               goto exit_lock;
+
+       error = -EROFS;
+       if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir))
+               goto exit_lock;
+
        /*
         * A file cannot be removed from an append-only directory.
         */
-       if (IS_APPEND(olddir)) {
-               error = -EPERM;
-               goto new_exit;
-       }
-       if (!olddir->i_op || !olddir->i_op->rename) {
-               error = -ENOSYS; /* was EPERM */
-               goto new_exit;
-       }
-#ifdef CONFIG_TRANS_NAMES
-       /* if oldname has been translated, but newname not (and
-        * has not already a suffix), take over the suffix from oldname.
-        */
-       if(oldlast.name == oldbuf && newlast.name != newbuf &&
-          newlast.name[newlast.len-1] != '#') {
-               int i = oldlast.len - 2;
-               while (i > 0 && oldlast.name[i] != '#')
-                       i--;
-               memcpy(newbuf, newlast.name, newlast.len);
-               memcpy(newbuf+newlast.len, oldlast.name+i, oldlast.len - i);
-               newlast.len += oldlast.len - i;
-               newlast.name = newbuf;
-       }
-#endif
-       atomic_inc(&olddir->i_count);
-       atomic_inc(&newdir->i_count);
-       if (newdir->i_sb && newdir->i_sb->dq_op)
-               newdir->i_sb->dq_op->initialize(newdir, -1);
-       down(&newdir->i_sem);
-       error = olddir->i_op->rename(olddir, oldlast.name, oldlast.len, 
-               newdir, newlast.name, newlast.len);
-#ifdef CONFIG_OMIRR
-       if(!error)
-               omirr_print(oldent, newdir->i_dentry, &newlast,
-                           " m %ld ", CURRENT_TIME);
-#endif
-       if(!error) {
-               d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE);
-               d_move(d_lookup(olddir, &oldlast, NULL), newdir, &newlast, NULL);
-       }
-       up(&newdir->i_sem);
-new_exit:
-       if(!newlasterror)
-               iput(newinode);
-       iput(newdir);
-old_exit:
-       iput(oldinode);
-       iput(olddir);
+       error = -EPERM;
+       if (IS_APPEND(old_dir))
+               goto exit_lock;
+
+       error = -EPERM;
+       if (!old_dir->i_op || !old_dir->i_op->rename)
+               goto exit_lock;
+
+       if (new_dir->i_sb && new_dir->i_sb->dq_op)
+               new_dir->i_sb->dq_op->initialize(new_dir, -1);
+       error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+
+exit_lock:
+       up(&new_dir->i_sem);
+       up(&old_dir->i_sem);
+       iput(old_dir);
+       iput(new_dir);
+       dput(new_dentry);
+exit_old:
+       dput(old_dentry);
 exit:
        return error;
 }
index 71835c2556db30cc7c49ac8343ae905733af9673..aa0d1345baaa7c5f2fb2699cbfee2e19d1e9e1cc 100644 (file)
@@ -42,16 +42,15 @@ struct nfs_dirent {
 static int nfs_dir_open(struct inode * inode, struct file * file);
 static long nfs_dir_read(struct inode *, struct file *, char *, unsigned long);
 static int nfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int nfs_lookup(struct inode *, const char *, int, struct inode **);
-static int nfs_create(struct inode *, const char *, int, int, struct inode **);
-static int nfs_mkdir(struct inode *, const char *, int, int);
-static int nfs_rmdir(struct inode *, const char *, int);
-static int nfs_unlink(struct inode *, const char *, int);
-static int nfs_symlink(struct inode *, const char *, int, const char *);
-static int nfs_link(struct inode *, struct inode *, const char *, int);
-static int nfs_mknod(struct inode *, const char *, int, int, int);
-static int nfs_rename(struct inode *, const char *, int,
-                     struct inode *, const char *, int);
+static int nfs_lookup(struct inode *, struct qstr *, struct inode **);
+static int nfs_create(struct inode *, struct dentry *, int);
+static int nfs_mkdir(struct inode *, struct dentry *, int);
+static int nfs_rmdir(struct inode *, struct dentry *);
+static int nfs_unlink(struct inode *, struct dentry *);
+static int nfs_symlink(struct inode *, struct dentry *, const char *);
+static int nfs_link(struct inode *, struct inode *, struct dentry *);
+static int nfs_mknod(struct inode *, struct dentry *, int, int);
+static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
 
 static struct file_operations nfs_dir_operations = {
        NULL,                   /* lseek - default */
@@ -78,6 +77,7 @@ struct inode_operations nfs_dir_inode_operations = {
        nfs_mknod,              /* mknod */
        nfs_rename,             /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -328,488 +328,268 @@ nfs_free_dircache(void)
 }
  
 
-/*
- * Lookup caching is a big win for performance but this is just
- * a trial to see how well it works on a small scale.
- * For example, bash does a lookup on ".." 13 times for each path
- * element when running pwd.  Yes, hard to believe but true.
- * Try pwd in a filesystem mounted with noac.
- *
- * It trades a little cpu time and memory for a lot of network bandwidth.
- * Since the cache is not hashed yet, it is a good idea not to make it too
- * large because every lookup looks through the entire cache even
- * though most of them will fail.
- *
- * FIXME: The lookup cache should also cache failed lookups. This can
- * be a considerable win on diskless clients.
- */
-
-static struct nfs_lookup_cache_entry {
-       kdev_t          dev;
-       ino_t           inode;
-       char            filename[NFS_MAXNAMLEN + 1];
-       struct nfs_fh   fhandle;
-       struct nfs_fattr fattr;
-       unsigned long   expiration_date;
-} nfs_lookup_cache[NFS_LOOKUP_CACHE_SIZE];
-
-static struct nfs_lookup_cache_entry *nfs_lookup_cache_index(struct inode *dir,
-                                                            const char *filename)
-{
-       struct nfs_lookup_cache_entry *entry;
-       int i;
-
-       for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
-               entry = nfs_lookup_cache + i;
-               if (entry->dev == dir->i_dev
-                   && entry->inode == dir->i_ino
-                   && !strncmp(filename, entry->filename, NFS_MAXNAMLEN))
-                       return entry;
-       }
-       return NULL;
-}
-
-static int nfs_lookup_cache_lookup(struct inode *dir, const char *filename,
-                                  struct nfs_fh *fhandle,
-                                  struct nfs_fattr *fattr)
-{
-       static int nfs_lookup_cache_in_use = 0;
-
-       struct nfs_lookup_cache_entry *entry;
-
-       dfprintk(LOOKUPCACHE, "NFS: lookup_cache_lookup(%x/%ld, %s)\n",
-                               dir->i_dev, dir->i_ino, filename);
-       if (!nfs_lookup_cache_in_use) {
-               memset(nfs_lookup_cache, 0, sizeof(nfs_lookup_cache));
-               nfs_lookup_cache_in_use = 1;
-       }
-       if ((entry = nfs_lookup_cache_index(dir, filename))) {
-               if (jiffies > entry->expiration_date) {
-                       entry->dev = 0;
-                       return 0;
-               }
-               *fhandle = entry->fhandle;
-               *fattr = entry->fattr;
-               return 1;
-       }
-       return 0;
-}
-
-static void nfs_lookup_cache_add(struct inode *dir, const char *filename,
-                                struct nfs_fh *fhandle,
-                                struct nfs_fattr *fattr)
-{
-       static int nfs_lookup_cache_pos = 0;
-       struct nfs_lookup_cache_entry *entry;
-
-       dfprintk(LOOKUPCACHE, "NFS: lookup_cache_add(%x/%ld, %s\n",
-                               dir->i_dev, dir->i_ino, filename);
-
-       /* compensate for bug in SGI NFS server */
-       if (fattr->size == -1 || fattr->uid == -1 || fattr->gid == -1
-           || fattr->atime.seconds == -1 || fattr->mtime.seconds == -1)
-               return;
-       if (!(entry = nfs_lookup_cache_index(dir, filename))) {
-               entry = nfs_lookup_cache + nfs_lookup_cache_pos++;
-               if (nfs_lookup_cache_pos == NFS_LOOKUP_CACHE_SIZE)
-                       nfs_lookup_cache_pos = 0;
-       }
-
-       entry->dev = dir->i_dev;
-       entry->inode = dir->i_ino;
-       strcpy(entry->filename, filename);
-       entry->fhandle = *fhandle;
-       entry->fattr = *fattr;
-       entry->expiration_date = jiffies + (S_ISDIR(fattr->mode)
-               ? NFS_SERVER(dir)->acdirmin : NFS_SERVER(dir)->acregmin);
-}
-
-static void nfs_lookup_cache_remove(struct inode *dir, struct inode *inode,
-                                   const char *filename)
-{
-       struct nfs_lookup_cache_entry *entry;
-       kdev_t  dev;
-       ino_t   fileid;
-       int     i;
-
-       if (inode) {
-               dev = inode->i_dev;
-               fileid = inode->i_ino;
-       }
-       else if ((entry = nfs_lookup_cache_index(dir, filename))) {
-               dev = entry->dev;
-               fileid = entry->fattr.fileid;
-       }
-       else
-               return;
-
-       dfprintk(LOOKUPCACHE, "NFS: lookup_cache_remove(%x/%ld)\n",
-                               dev, (long)fileid);
-
-       for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
-               entry = nfs_lookup_cache + i;
-               if (entry->dev == dev && entry->fattr.fileid == fileid)
-                       entry->dev = 0;
-       }
-}
-
-static void nfs_lookup_cache_refresh(struct inode *file,
-                                    struct nfs_fattr *fattr)
-{
-       struct nfs_lookup_cache_entry *entry;
-       kdev_t dev = file->i_dev;
-       int fileid = file->i_ino;
-       int i;
-
-       for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
-               entry = nfs_lookup_cache + i;
-               if (entry->dev == dev && entry->fattr.fileid == fileid)
-                       entry->fattr = *fattr;
-       }
-}
-
-static int nfs_lookup(struct inode *dir, const char *__name, int len,
+static int nfs_lookup(struct inode *dir, struct qstr * __name,
                      struct inode **result)
 {
        struct nfs_fh fhandle;
        struct nfs_fattr fattr;
+       int len = __name->len;
        char name[len > NFS_MAXNAMLEN? 1 : len+1];
        int error;
 
        dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n",
-                               dir->i_dev, dir->i_ino, len, __name);
+                               dir->i_dev, dir->i_ino, len, __name->name);
 
        *result = NULL;
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk("nfs_lookup: inode is NULL or not a directory\n");
-               iput(dir);
                return -ENOENT;
        }
-       if (len > NFS_MAXNAMLEN) {
-               iput(dir);
+
+       if (len > NFS_MAXNAMLEN)
                return -ENAMETOOLONG;
-       }
-       memcpy(name,__name,len);
+
+       memcpy(name,__name->name,len);
        name[len] = '\0';
-       if (len == 0 || (len == 1 && name[0] == '.')) { /* cheat for "" and "." */
-               *result = dir;
-               return 0;
-       }
-       if ((NFS_SERVER(dir)->flags & NFS_MOUNT_NOAC)
-           || !nfs_lookup_cache_lookup(dir, name, &fhandle, &fattr)) {
-               if ((error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
-                   name, &fhandle, &fattr))) {
-                       iput(dir);
-                       return error;
-               }
-               nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
-       }
-       if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) {
-               iput(dir);
+
+       error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
+               name, &fhandle, &fattr);
+       if (error)
+               return error;
+
+       if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr)))
                return -EACCES;
-       }
-       iput(dir);
+
        return 0;
 }
 
-static int nfs_create(struct inode *dir, const char *name, int len, int mode,
-                     struct inode **result)
+static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
 {
        struct nfs_sattr sattr;
        struct nfs_fattr fattr;
        struct nfs_fh fhandle;
+       struct inode *inode;
        int error;
 
        dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
-                               dir->i_dev, dir->i_ino, name);
+                               dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-       *result = NULL;
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk("nfs_create: inode is NULL or not a directory\n");
-               iput(dir);
                return -ENOENT;
        }
-       if (len > NFS_MAXNAMLEN) {
-               iput(dir);
+
+       if (dentry->d_name.len > NFS_MAXNAMLEN)
                return -ENAMETOOLONG;
-       }
+
        sattr.mode = mode;
        sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
        sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
-       if ((error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
-               name, &sattr, &fhandle, &fattr))) {
-               iput(dir);
+       error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
+               dentry->d_name.name, &sattr, &fhandle, &fattr);
+
+       if (error)
                return error;
-       }
-       if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) {
-               iput(dir);
+
+       inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+       if (!inode)
                return -EACCES;
-       }
-       nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
-       nfs_invalidate_dircache(dir);
-       iput(dir);
+
+       d_instantiate(dentry, inode, 0);
        return 0;
 }
 
-static int nfs_mknod(struct inode *dir, const char *name, int len,
-                    int mode, int rdev)
+static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
 {
        struct nfs_sattr sattr;
        struct nfs_fattr fattr;
        struct nfs_fh fhandle;
+       struct inode *inode;
        int error;
 
        dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
-                               dir->i_dev, dir->i_ino, name);
+                               dir->i_dev, dir->i_ino, dentry->d_name.name);
 
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk("nfs_mknod: inode is NULL or not a directory\n");
-               iput(dir);
                return -ENOENT;
        }
-       if (len > NFS_MAXNAMLEN) {
-               iput(dir);
+
+       if (dentry->d_name.len > NFS_MAXNAMLEN)
                return -ENAMETOOLONG;
-       }
+
        sattr.mode = mode;
-       sattr.uid = sattr.gid = (unsigned) -1;
+       sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
        if (S_ISCHR(mode) || S_ISBLK(mode))
                sattr.size = rdev; /* get out your barf bag */
-       else
-               sattr.size = (unsigned) -1;
+
        sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
        error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
-               name, &sattr, &fhandle, &fattr);
-       if (!error)
-               nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
-       nfs_invalidate_dircache(dir);
-       iput(dir);
-       return error;
+               dentry->d_name.name, &sattr, &fhandle, &fattr);
+
+       if (error)
+               return error;
+
+       inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+       if (!inode)
+               return -EACCES;
+
+       d_instantiate(dentry, inode, 0);
+       return 0;
 }
 
-static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode)
+static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
        struct nfs_sattr sattr;
        struct nfs_fattr fattr;
        struct nfs_fh fhandle;
+       struct inode * inode;
        int error;
 
        dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
-                               dir->i_dev, dir->i_ino, name);
+                               dir->i_dev, dir->i_ino, dentry->d_name.name);
 
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk("nfs_mkdir: inode is NULL or not a directory\n");
-               iput(dir);
                return -ENOENT;
        }
-       if (len > NFS_MAXNAMLEN) {
-               iput(dir);
+
+       if (dentry->d_name.len > NFS_MAXNAMLEN)
                return -ENAMETOOLONG;
-       }
+
        sattr.mode = mode;
        sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
        sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+
        error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
-               name, &sattr, &fhandle, &fattr);
-       if (!error)
-               nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
-       nfs_invalidate_dircache(dir);
-       iput(dir);
-       return error;
+               dentry->d_name.name, &sattr, &fhandle, &fattr);
+
+       if (error)
+               return error;
+
+       inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+       if (!inode)
+               return -EACCES;
+
+       d_instantiate(dentry, inode, D_DIR);
+       return 0;
 }
 
-static int nfs_rmdir(struct inode *dir, const char *name, int len)
+static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
        dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
-                               dir->i_dev, dir->i_ino, name);
+                               dir->i_dev, dir->i_ino, dentry->d_name.name);
 
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk("nfs_rmdir: inode is NULL or not a directory\n");
-               iput(dir);
                return -ENOENT;
        }
-       if (len > NFS_MAXNAMLEN) {
-               iput(dir);
-               return -ENAMETOOLONG;
-       }
-       error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), name);
-       if (!error)
-               nfs_lookup_cache_remove(dir, NULL, name);
-       nfs_invalidate_dircache(dir);
-       iput(dir);
-       return error;
-}
 
-static int nfs_sillyrename(struct inode *dir, const char *name, int len)
-{
-       struct inode    *inode;
-       char            silly[16];
-       int             slen, ret;
-
-       atomic_inc(&dir->i_count);
-       if (nfs_lookup(dir, name, len, &inode) < 0)
-               return -EIO;            /* arbitrary */
-
-       if (atomic_read(&inode->i_count) == 1) {
-               iput(inode);
-               return -EIO;
-       }
-       if (NFS_RENAMED_DIR(inode)) {
-               iput(NFS_RENAMED_DIR(inode));
-               NFS_RENAMED_DIR(inode) = NULL;
-               iput(inode);
-               return -EIO;
-       }
-
-       slen = sprintf(silly, ".nfs%ld", inode->i_ino);
-       if (len == slen && !strncmp(name, silly, len)) {
-               iput(inode);
-               return -EIO;            /* DWIM */
-       }
+       if (dentry->d_name.len > NFS_MAXNAMLEN)
+               return -ENAMETOOLONG;
 
-       dfprintk(VFS, "NFS: sillyrename(%x/%ld, %s)\n",
-                               dir->i_dev, dir->i_ino, name);
+       error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
+       if (error)
+               return error;
 
-       ret = nfs_proc_rename(NFS_SERVER(dir), NFS_FH(dir), name,
-                                              NFS_FH(dir), silly);
-       if (ret >= 0) {
-               nfs_lookup_cache_remove(dir, NULL, name);
-               nfs_lookup_cache_remove(dir, NULL, silly);
-               NFS_RENAMED_DIR(inode) = dir;
-               atomic_inc(&dir->i_count);
-       }
-       nfs_invalidate_dircache(dir);
-       iput(inode);
-       return ret;
+       d_delete(dentry);
+       return 0;
 }
 
 /*
- * When releasing the inode, finally remove any unlinked but open files.
- * Note that we have to clear the set of pending signals temporarily;
- * otherwise the RPC call will fail.
+ * We should do silly-rename here, but I'm too lazy to fix
+ * up the directory entry implications of it..
  */
-void nfs_sillyrename_cleanup(struct inode *inode)
-{
-       unsigned long   oldsig;
-       struct inode    *dir = NFS_RENAMED_DIR(inode);
-       char            silly[14];
-       int             error, slen;
-
-       dfprintk(VFS, "NFS: sillyrename cleanup(%x/%ld)\n",
-                               inode->i_dev, inode->i_ino);
-
-       oldsig = current->signal;
-       current->signal = 0;
-
-       slen = sprintf(silly, ".nfs%ld", inode->i_ino);
-       error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), silly);
-       if (error < 0)
-               printk("NFS: silly_rename cleanup failed (err %d)\n", -error);
-
-       nfs_lookup_cache_remove(dir, NULL, silly);
-       nfs_invalidate_dircache(dir);
-       NFS_RENAMED_DIR(inode) = NULL;
-       iput(dir);
-
-       current->signal |= oldsig;
-}
-
-static int nfs_unlink(struct inode *dir, const char *name, int len)
+static int nfs_unlink(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
        dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
-                               dir->i_dev, dir->i_ino, name);
+                               dir->i_dev, dir->i_ino, dentry->d_name.name);
 
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk("nfs_unlink: inode is NULL or not a directory\n");
-               iput(dir);
                return -ENOENT;
        }
-       if (len > NFS_MAXNAMLEN) {
-               iput(dir);
+
+       if (dentry->d_name.len > NFS_MAXNAMLEN)
                return -ENAMETOOLONG;
-       }
-       if ((error = nfs_sillyrename(dir, name, len)) < 0) {
-               error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), name);
-               if (!error)
-                       nfs_lookup_cache_remove(dir, NULL, name);
-       }
-       nfs_invalidate_dircache(dir);
-       iput(dir);
-       return error;
+
+       error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
+       if (error)
+               return error;
+
+       d_delete(dentry);
+       return 0;
 }
 
-static int nfs_symlink(struct inode *dir, const char *name, int len,
-                      const char *symname)
+static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
        struct nfs_sattr sattr;
+       struct nfs_fattr fattr;
+       struct nfs_fh fhandle;
+       struct inode * inode;
        int error;
 
        dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
-                               dir->i_dev, dir->i_ino, name, symname);
+                               dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
 
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk("nfs_symlink: inode is NULL or not a directory\n");
-               iput(dir);
                return -ENOENT;
        }
-       if (len > NFS_MAXNAMLEN) {
-               iput(dir);
+
+       if (dentry->d_name.len > NFS_MAXNAMLEN)
                return -ENAMETOOLONG;
-       }
-       if (strlen(symname) > NFS_MAXPATHLEN) {
-               iput(dir);
+
+       if (strlen(symname) > NFS_MAXPATHLEN)
                return -ENAMETOOLONG;
-       }
+
        sattr.mode = S_IFLNK | S_IRWXUGO; /* SunOS 4.1.2 crashes without this! */
        sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
        sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+
        error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
-               name, symname, &sattr);
-       nfs_invalidate_dircache(dir);
-       iput(dir);
-       return error;
+               dentry->d_name.name, symname, &sattr);
+
+       if (error)
+               return error;
+
+       inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+       if (!inode)
+               return -EACCES;
+
+       d_instantiate(dentry, inode, 0);
+       return 0;
 }
 
-static int nfs_link(struct inode *oldinode, struct inode *dir,
-                   const char *name, int len)
+static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry)
 {
        int error;
 
        dfprintk(VFS, "NFS: link(%x/%ld -> %x/%ld, %s)\n",
-                               oldinode->i_dev, oldinode->i_ino,
-                               dir->i_dev, dir->i_ino, name);
+                               inode->i_dev, inode->i_ino,
+                               dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-       if (!oldinode) {
-               printk("nfs_link: old inode is NULL\n");
-               iput(oldinode);
-               iput(dir);
-               return -ENOENT;
-       }
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk("nfs_link: dir is NULL or not a directory\n");
-               iput(oldinode);
-               iput(dir);
                return -ENOENT;
        }
-       if (len > NFS_MAXNAMLEN) {
-               iput(oldinode);
-               iput(dir);
+
+       if (dentry->d_name.len > NFS_MAXNAMLEN)
                return -ENAMETOOLONG;
-       }
-       error = nfs_proc_link(NFS_SERVER(oldinode), NFS_FH(oldinode),
-               NFS_FH(dir), name);
-       if (!error) {
-               nfs_lookup_cache_remove(dir, oldinode, NULL);
-               NFS_READTIME(oldinode) = 0;     /* force getattr */
-       }
-       nfs_invalidate_dircache(dir);
-       iput(oldinode);
-       iput(dir);
-       return error;
+
+       error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode),
+               NFS_FH(dir), dentry->d_name.name);
+
+       if (error)
+               return error;
+
+       atomic_inc(&inode->i_count);
+       d_instantiate(dentry, inode, 0);
+       return 0;
 }
 
 /*
@@ -821,45 +601,39 @@ static int nfs_link(struct inode *oldinode, struct inode *dir,
  * rename the old file using the silly_rename stuff. This way, the original
  * file in old_dir will go away when the last process iput()s the inode.
  */
-static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len,
-                     struct inode *new_dir, const char *new_name, int new_len)
+static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+                     struct inode *new_dir, struct dentry *new_dentry)
 {
        int error;
 
        dfprintk(VFS, "NFS: rename(%x/%ld, %s -> %x/%ld, %s)\n",
-                               old_dir->i_dev, old_dir->i_ino, old_name,
-                               new_dir->i_dev, new_dir->i_ino, new_name);
+                               old_dir->i_dev, old_dir->i_ino, old_dentry->d_name.name,
+                               new_dir->i_dev, new_dir->i_ino, new_dentry->d_name.name);
 
        if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
                printk("nfs_rename: old inode is NULL or not a directory\n");
-               iput(old_dir);
-               iput(new_dir);
                return -ENOENT;
        }
+
        if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
                printk("nfs_rename: new inode is NULL or not a directory\n");
-               iput(old_dir);
-               iput(new_dir);
                return -ENOENT;
        }
-       if (old_len > NFS_MAXNAMLEN || new_len > NFS_MAXNAMLEN) {
-               iput(old_dir);
-               iput(new_dir);
+
+       if (old_dentry->d_name.len > NFS_MAXNAMLEN || new_dentry->d_name.len > NFS_MAXNAMLEN)
                return -ENAMETOOLONG;
-       }
 
        error = nfs_proc_rename(NFS_SERVER(old_dir),
-               NFS_FH(old_dir), old_name,
-               NFS_FH(new_dir), new_name);
-       if (!error) {
-               nfs_lookup_cache_remove(old_dir, NULL, old_name);
-               nfs_lookup_cache_remove(new_dir, NULL, new_name);
-       }
-       nfs_invalidate_dircache(old_dir);
-       nfs_invalidate_dircache(new_dir);
-       iput(old_dir);
-       iput(new_dir);
-       return error;
+               NFS_FH(old_dir), old_dentry->d_name.name,
+               NFS_FH(new_dir), new_dentry->d_name.name);
+
+       if (error)
+               return error;
+
+       /* Update the dcache */
+       d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
+       d_delete(new_dentry);
+       return 0;
 }
 
 /*
@@ -925,6 +699,4 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
                        init_fifo(inode);
        } else
                inode->i_op = NULL;
-       nfs_lookup_cache_refresh(inode, fattr);
 }
-
index 56540bbdc5e36ed191887c6e6554b61805bbc769..4688954762c0f47f927dd81245a35686991fddf6 100644 (file)
@@ -69,6 +69,7 @@ struct inode_operations nfs_file_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        nfs_readpage,           /* readpage */
        nfs_writepage,          /* writepage */
        NULL,                   /* bmap */
index b9156417836bb182b36550eb391700e01333c80d..871f5fd4d7e19b8d91962808ef0dc5bb887bfb84 100644 (file)
@@ -74,8 +74,6 @@ nfs_put_inode(struct inode * inode)
 {
        dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
 
-       if (NFS_RENAMED_DIR(inode))
-               nfs_sillyrename_cleanup(inode);
        if (inode->i_pipe)
                clear_inode(inode);
 }
@@ -230,7 +228,8 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
        /* Unlock super block and try to get root fh attributes */
        unlock_super(sb);
 
-       if ((sb->s_mounted = nfs_fhget(sb, &data->root, NULL)) != NULL) {
+       sb->s_root = d_alloc_root(nfs_fhget(sb, &data->root, NULL), NULL);
+       if (sb->s_root != NULL) {
                /* We're airborne */
                if (!(server->flags & NFS_MOUNT_NONLM))
                        lockd_up();
index a22f9623987f44d150ba600cad8a88129c4798a8..3d545f7d8e701130e7a736a92535fdc15da8dca1 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/uaccess.h>
 
 static int nfs_readlink(struct inode *, char *, int);
+static struct dentry *nfs_follow_link(struct inode *, struct dentry *);
 
 /*
  * symlinks can't do much...
@@ -35,6 +36,7 @@ struct inode_operations nfs_symlink_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        nfs_readlink,           /* readlink */
+       nfs_follow_link,        /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -55,7 +57,6 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
                buflen = NFS_MAXPATHLEN;
        error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
                &res, &len, buflen);
-       iput(inode);
        if (! error) {
                copy_to_user(buffer, res, len);
                put_user('\0', buffer + len);
@@ -64,3 +65,36 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
        kfree(mem);
        return error;
 }
+
+static struct dentry * nfs_follow_link(struct inode * inode, struct dentry *base)
+{
+       int error;
+       unsigned int len;
+       char *res;
+       void *mem;
+       char *path;
+
+       dfprintk(VFS, "nfs: follow_link(%x/%ld)\n", inode->i_dev, inode->i_ino);
+
+       error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
+               &res, &len, NFS_MAXPATHLEN);
+
+       if (error) {
+               dput(base);
+               kfree(mem);
+               return ERR_PTR(error);
+       }
+       path = kmalloc(len + 1, GFP_KERNEL);
+       if (!path) {
+               dput(base);
+               kfree(mem);
+               return ERR_PTR(-ENOMEM);
+       }
+       memcpy(path, res, len);
+       path[len] = 0;
+       kfree(mem);
+
+       base = lookup_dentry(path, base, 1);
+       kfree(path);
+       return base;
+}
index 70b8a8a58281c8336ea16bd1b8b869428b184027..4444653d5664d6330bedce64d024687f936f31b2 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -35,7 +35,7 @@ asmlinkage int sys_statfs(const char * path, struct statfs * buf)
        error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
        if (error)
                goto out;
-       error = namei(NAM_FOLLOW_LINK, path, &inode);
+       error = namei(path, &inode);
        if (error)
                goto out;
        error = -ENOSYS;
@@ -102,7 +102,7 @@ asmlinkage int sys_truncate(const char * path, unsigned long length)
        int error;
 
        lock_kernel();
-       error = namei(NAM_FOLLOW_LINK, path, &inode);
+       error = namei(path, &inode);
        if (error)
                goto out;
 
@@ -189,7 +189,7 @@ asmlinkage int sys_utime(char * filename, struct utimbuf * times)
 
        lock_kernel();
        /* Hmm, should I always follow symlinks or not ? */
-       error = namei(NAM_FOLLOW_LINK, filename, &inode);
+       error = namei(filename, &inode);
        if (error)
                goto out;
        error = -EROFS;
@@ -237,7 +237,7 @@ asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
        struct iattr newattrs;
 
        lock_kernel();
-       error = namei(NAM_FOLLOW_LINK, filename, &inode);
+       error = namei(filename, &inode);
        if (error)
                goto out;
        error = -EROFS;
@@ -287,7 +287,7 @@ asmlinkage int sys_access(const char * filename, int mode)
        old_fsgid = current->fsgid;
        current->fsuid = current->uid;
        current->fsgid = current->gid;
-       res = namei(NAM_FOLLOW_LINK, filename, &inode);
+       res = namei(filename, &inode);
        if (!res) {
                res = permission(inode, mode);
                iput(inode);
@@ -301,24 +301,37 @@ out:
 
 asmlinkage int sys_chdir(const char * filename)
 {
-       struct inode * inode;
-       struct inode * tmpi;
        int error;
+       struct inode *inode;
+       struct dentry *dentry, *tmp;
 
        lock_kernel();
-       error = namei(NAM_FOLLOW_LINK, filename, &inode);
-       if (error)
+       
+       dentry = lookup_dentry(filename, NULL, 1);
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
                goto out;
+
+       error = -ENOENT;
+       if (dentry->d_flag & D_NEGATIVE)
+               goto dput_and_out;
+
        error = -ENOTDIR;
+       inode = dentry->d_inode;
        if (!S_ISDIR(inode->i_mode))
-               goto iput_and_out;
-       if ((error = permission(inode,MAY_EXEC)) != 0)
-               goto iput_and_out;
+               goto dput_and_out;
 
-       /* exchange inodes */
-       tmpi = current->fs->pwd; current->fs->pwd = inode; inode = tmpi;
-iput_and_out:
-       iput(inode);
+       error = permission(inode,MAY_EXEC);
+       if (error)
+               goto dput_and_out;
+
+       /* exchange dentries */
+       tmp = current->fs->pwd;
+       current->fs->pwd = dentry;
+       dentry = tmp;
+
+dput_and_out:
+       dput(dentry);
 out:
        unlock_kernel();
        return error;
@@ -326,24 +339,33 @@ out:
 
 asmlinkage int sys_fchdir(unsigned int fd)
 {
-       struct inode * inode;
-       struct file * file;
-       int error = -EBADF;
+       struct file *file;
+       struct inode *inode;
+       struct dentry *dentry, *tmp;
+       int error;
 
        lock_kernel();
+
+       error = -EBADF;
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
                goto out;
+
        error = -ENOENT;
        if (!(inode = file->f_inode))
                goto out;
+
        error = -ENOTDIR;
        if (!S_ISDIR(inode->i_mode))
                goto out;
-       if ((error = permission(inode,MAY_EXEC)) != 0)
+
+       error = permission(inode,MAY_EXEC);
+       if (error)
                goto out;
-       iput(current->fs->pwd);
-       current->fs->pwd = inode;
-       atomic_inc(&inode->i_count);
+
+       dentry = dget(inode->i_dentry);
+       tmp = current->fs->pwd;
+       current->fs->pwd = dentry;
+       dput(tmp);
 out:
        unlock_kernel();
        return error;
@@ -351,24 +373,41 @@ out:
 
 asmlinkage int sys_chroot(const char * filename)
 {
-       struct inode * inode;
-       struct inode * tmpi;
        int error;
+       struct inode *inode;
+       struct dentry *dentry, *tmp;
 
        lock_kernel();
-       error = namei(NAM_FOLLOW_LINK, filename, &inode);
-       if (error)
+       
+       dentry = lookup_dentry(filename, NULL, 1);
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
                goto out;
+
+       error = -ENOENT;
+       if (dentry->d_flag & D_NEGATIVE)
+               goto dput_and_out;
+
        error = -ENOTDIR;
+       inode = dentry->d_inode;
        if (!S_ISDIR(inode->i_mode))
-               goto iput_and_out;
+               goto dput_and_out;
+
+       error = permission(inode,MAY_EXEC);
+       if (error)
+               goto dput_and_out;
+
        error = -EPERM;
        if (!fsuser())
-               goto iput_and_out;
-       tmpi = current->fs->root; current->fs->root = inode; inode = tmpi;
-       error = 0;
-iput_and_out:
-       iput(inode);
+               goto dput_and_out;
+
+       /* exchange dentries */
+       tmp = current->fs->root;
+       current->fs->root = dentry;
+       dentry = tmp;
+
+dput_and_out:
+       dput(dentry);
 out:
        unlock_kernel();
        return error;
@@ -419,7 +458,7 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode)
         * because permissions on symlinks now can never be changed,
         * but on the other hand they are never needed.
         */
-       error = namei(NAM_FOLLOW_LINK, filename, &inode);
+       error = namei(filename, &inode);
        if (error)
                goto out;
        error = -EROFS;
@@ -517,7 +556,7 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
        struct iattr newattrs;
 
        lock_kernel();
-       error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
+       error = namei(filename, &inode);
        if (error)
                goto out;
        error = -EROFS;
index 1e18e594ec26565bcb0d1d9eaa7fdfd0a61e5e09..390934e25575f2976779608b694abfe8bd6d18a6 100644 (file)
@@ -53,6 +53,5 @@ int proc_arbitrary_lookup(struct inode * dir, const char * name,
                        error = 0;
        }
 done:
-       iput(dir);
        return error;
 }
index e8aefc08ca9ec6f1d53d68ec279a3bbdce4ffe9e..82a3257d2056d32c46ce424c66c64a4c4e385d18 100644 (file)
@@ -1216,6 +1216,7 @@ struct inode_operations proc_array_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -1261,6 +1262,7 @@ struct inode_operations proc_arraylong_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
index b983e73f67069eb9ee17e0ea2fd294f3b7081cb5..7e9a65e088e7fcaccc090ff51d6a95feec6ffc07 100644 (file)
@@ -42,6 +42,7 @@ static struct inode_operations proc_base_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
index 884631db80ad04ebfa9befd6b6c5af585a4e0007..1249c14809e1acee3e7257b5800dc6c6b39ad8fb 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/stat.h>
 
 static int proc_readfd(struct inode *, struct file *, void *, filldir_t);
-static int proc_lookupfd(struct inode *,const char *,int,struct inode **);
+static int proc_lookupfd(struct inode *,struct qstr *,struct inode **);
 
 static struct file_operations proc_fd_operations = {
        NULL,                   /* lseek - default */
@@ -44,6 +44,7 @@ struct inode_operations proc_fd_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -51,12 +52,13 @@ struct inode_operations proc_fd_inode_operations = {
        NULL                    /* permission */
 };
 
-static int proc_lookupfd(struct inode * dir, const char * name, int len,
-       struct inode ** result)
+static int proc_lookupfd(struct inode * dir, struct qstr *str, struct inode ** result)
 {
        unsigned int ino, pid, fd, c;
        struct task_struct * p;
        struct super_block * sb;
+       const char *name;
+       int len;
 
        *result = NULL;
        ino = dir->i_ino;
@@ -65,25 +67,12 @@ static int proc_lookupfd(struct inode * dir, const char * name, int len,
        if (!dir)
                return -ENOENT;
        sb = dir->i_sb;
-       if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode)) {
-               iput(dir);
+       if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode))
                return -ENOENT;
-       }
-       if (!len || (name[0] == '.' && (len == 1 ||
-           (name[1] == '.' && len == 2)))) {
-               if (len < 2) {
-                       *result = dir;
-                       return 0;
-               }
-               if (!(*result = proc_get_inode(sb, (pid << 16)+PROC_PID_INO, &proc_pid))) {
-                       iput(dir);
-                       return -ENOENT;
-               }
-               iput(dir);
-               return 0;
-       }
-       iput(dir);
+
        fd = 0;
+       len = str->len;
+       name = str->name;
        while (len-- > 0) {
                c = *name - '0';
                name++;
index 1424dd1efb4482fec6bbc4df96c59ca76feab9ef..35806002045149abccd7440c876d4916d2ca7ea2 100644 (file)
@@ -23,6 +23,15 @@ static long proc_file_write(struct inode * inode, struct file * file,
 static long long proc_file_lseek(struct inode * inode, struct file * file, 
                                 long long offset, int orig);
 
+int proc_match(int len, const char *name,struct proc_dir_entry * de)
+{
+       if (!de || !de->low_ino)
+               return 0;
+       if (de->namelen != len)
+               return 0;
+       return !memcmp(name, de->name, len);
+}
+
 static struct file_operations proc_file_operations = {
     proc_file_lseek,   /* lseek   */
     proc_file_read,    /* read    */
@@ -51,6 +60,7 @@ struct inode_operations proc_file_inode_operations = {
     NULL,          /* mknod       */
     NULL,          /* rename      */
     NULL,          /* readlink    */
+    NULL,          /* follow_link */
     NULL,          /* readpage    */
     NULL,          /* writepage   */
     NULL,          /* bmap        */
@@ -73,6 +83,7 @@ struct inode_operations proc_net_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
index 943137bf4d6b28e9861da875bd535994a7b7719a..18a40ffd85b4cec7db681ff31599bd1e566ff172 100644 (file)
@@ -131,12 +131,13 @@ struct super_block *proc_read_super(struct super_block *s,void *data,
        s->s_magic = PROC_SUPER_MAGIC;
        s->s_op = &proc_sops;
        unlock_super(s);
-       if (!(s->s_mounted = proc_get_inode(s, PROC_ROOT_INO, &proc_root))) {
+       s->s_root = d_alloc_root(proc_get_inode(s, PROC_ROOT_INO, &proc_root), NULL);
+       if (!s->s_root) {
                s->s_dev = 0;
                printk("get root inode failed\n");
                return NULL;
        }
-       parse_options(data, &s->s_mounted->i_uid, &s->s_mounted->i_gid);
+       parse_options(data, &s->s_root->d_inode->i_uid, &s->s_root->d_inode->i_gid);
        return s;
 }
 
index 6ef386ffaba05c7e28a71f4c6c27a0ddcdedd095..1cc6a9c835598ad21a886fc1ebcc3edeba9a5a6f 100644 (file)
@@ -70,6 +70,7 @@ struct inode_operations proc_kmsg_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
index 695ed9bba72bb8c2e5a007a7d6ca316fe012fa88..42b7ae392b768834a85cce7fedaace08072a786c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/dalloc.h>
 
 static int proc_readlink(struct inode *, char *, int);
+static struct dentry * proc_follow_link(struct inode *, struct dentry *);
 
 /*
  * PLAN9_SEMANTICS won't work any more: it used an ugly hack that broke 
@@ -52,6 +53,7 @@ struct inode_operations proc_link_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        proc_readlink,          /* readlink */
+       proc_follow_link,       /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -59,59 +61,52 @@ struct inode_operations proc_link_inode_operations = {
        NULL                    /* permission */
 };
 
-/* [Feb-1997 T. Schoebel-Theuer] This is no longer called from the
- * VFS, but only from proc_readlink(). All the functionality
- * should the moved there (without using temporary inodes any more)
- * and then it could be eliminated.
- */
-static int proc_follow_link(struct inode * dir, struct inode * inode,
-       int flag, int mode, struct inode ** res_inode)
+static struct dentry * proc_follow_link(struct inode *inode, struct dentry *base)
 {
-       unsigned int pid, ino;
-       struct task_struct * p;
-       struct inode * new_inode;
+       struct task_struct *p;
+       struct dentry * result;
+       int ino, pid;
        int error;
 
-       *res_inode = NULL;
-       if (dir)
-               iput(dir);
-       if (!inode)
-               return -ENOENT;
-       if ((error = permission(inode, MAY_EXEC)) != 0){
-               iput(inode);
-               return error;
-       }
+       /* We don't need a base pointer in the /proc filesystem */
+       dput(base);
+
+       error = permission(inode, MAY_EXEC);
+       result = ERR_PTR(error);
+       if (error)
+               return result;
+
        ino = inode->i_ino;
        pid = ino >> 16;
        ino &= 0x0000ffff;
 
        p = find_task_by_pid(pid);
-       if (!p) {
-               iput(inode);
-               return -ENOENT;
-       }
-       new_inode = NULL;
+       result = ERR_PTR(-ENOENT);
+       if (!p)
+               return result;
+
        switch (ino) {
                case PROC_PID_CWD:
-                       if (!p->fs)
+                       if (!p->fs || !p->fs->pwd)
                                break;
-                       new_inode = p->fs->pwd;
+                       result = dget(p->fs->pwd);
                        break;
+
                case PROC_PID_ROOT:
-                       if (!p->fs)
+                       if (!p->fs || !p->fs->root)
                                break;
-                       new_inode = p->fs->root;
+                       result = dget(p->fs->root);
                        break;
+
                case PROC_PID_EXE: {
                        struct vm_area_struct * vma;
                        if (!p->mm)
                                break;
                        vma = p->mm->mmap;
                        while (vma) {
-                               if (vma->vm_flags & VM_EXECUTABLE) {
-                                       new_inode = vma->vm_inode;
-                                       break;
-                               }
+                               if (vma->vm_flags & VM_EXECUTABLE)
+                                       return dget(vma->vm_inode->i_dentry);
+
                                vma = vma->vm_next;
                        }
                        break;
@@ -122,45 +117,38 @@ static int proc_follow_link(struct inode * dir, struct inode * inode,
                                if (!p->files)
                                        break;
                                ino &= 0xff;
-                               if (ino < NR_OPEN && p->files->fd[ino]) {
-                                       new_inode = p->files->fd[ino]->f_inode;
-                               }
+                               if (ino >= NR_OPEN)
+                                       break;
+                               if (!p->files->fd[ino])
+                                       break;
+                               if (!p->files->fd[ino]->f_inode)
+                                       break;
+                               result = dget(p->files->fd[ino]->f_inode->i_dentry);
                                break;
                        }
        }
-       iput(inode);
-       if (!new_inode)
-               return -ENOENT;
-       *res_inode = new_inode;
-       atomic_inc(&new_inode->i_count);
-       return 0;
+       return result;
 }
 
 static int proc_readlink(struct inode * inode, char * buffer, int buflen)
 {
-       int error = proc_follow_link(NULL, inode, 0, 0, &inode);
+       int error;
+       struct dentry * dentry = proc_follow_link(inode, NULL);
 
-       if (error)
-               return error;
-       if (!inode)
-               return -EIO;
-
-       /* This will return *one* of the alias names (which is not quite
-        * correct). I have to rethink the problem, so this is only a
-        * quick hack...
-        */
-       if(inode->i_dentry) {
-               char * tmp = (char*)__get_free_page(GFP_KERNEL);
-               int len = d_path(inode->i_dentry, current->fs->root, tmp);
-               int min = buflen<PAGE_SIZE ? buflen : PAGE_SIZE;
-               if(len <= min)
-                       min = len+1;
-               copy_to_user(buffer, tmp, min);
-               free_page((unsigned long)tmp);
-               error = len;
-       } else {
-               error= -ENOENT;
+       error = PTR_ERR(dentry);
+       if (!IS_ERR(dentry)) {
+               error = -ENOENT;
+               if (dentry) {
+                       char * tmp = (char*)__get_free_page(GFP_KERNEL);
+                       int len = d_path(dentry, current->fs->root, tmp);
+                       int min = buflen<PAGE_SIZE ? buflen : PAGE_SIZE;
+                       if(len <= min)
+                               min = len+1;
+                       dput(dentry);
+                       copy_to_user(buffer, tmp, min);
+                       free_page((unsigned long)tmp);
+                       error = len;
+               }
        }
-       iput(inode);
        return error;
 }
index a64ead62472ba664c00604b8c45e6a222d1ea4ea..97acb5ee8703f9775150a4c46b75d30307525557 100644 (file)
@@ -328,6 +328,7 @@ struct inode_operations proc_mem_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
index 3bc5c339cdd12cffa083c6d553ccfb18b85e9d20..2574875697a944f280f23a341c8c593f2f81d274 100644 (file)
@@ -111,6 +111,7 @@ struct inode_operations proc_net_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
index 0e6377fb227347affe2da9931f5b4c59448983eb..7e23c3cc9db1dd34c0940463bccec64470a7d7dc 100644 (file)
@@ -288,6 +288,7 @@ struct inode_operations proc_omirr_inode_operations = {
     NULL, /* mknod */
     NULL, /* rename */
     NULL, /* readlink */
+    NULL, /* follow_link */
     NULL, /* readpage */
     NULL, /* writepage */
     NULL, /* bmap */
index 7d741cfafcd12012ac9e8fcb1832d9ec2473ff55..8ea14c3e7e7ccebdfe2f37d27f0e48137d2b419e 100644 (file)
@@ -484,6 +484,7 @@ static struct inode_operations openpromfs_prop_inode_ops = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -516,6 +517,7 @@ static struct inode_operations openpromfs_nodenum_inode_ops = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -548,6 +550,7 @@ static struct inode_operations openprom_alias_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
index f42557d2c5a05ed7ae7fc6a5e42c7faa485a6cca..ab6fcab1638b0c8d59dc2538ded227a328a1b867 100644 (file)
@@ -24,7 +24,7 @@
 #define FIRST_PROCESS_ENTRY 256
 
 static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
-static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
+static int proc_root_lookup(struct inode *,struct qstr *,struct inode **);
 
 static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
 
@@ -64,6 +64,7 @@ struct inode_operations proc_dir_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -104,6 +105,7 @@ static struct inode_operations proc_root_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -149,14 +151,14 @@ struct proc_dir_entry proc_sys_root = {
 #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
 
 static int (*proc_openprom_defreaddir_ptr)(struct inode *, struct file *, void *, filldir_t);
-static int (*proc_openprom_deflookup_ptr)(struct inode *, const char *, int, struct inode **);
+static int (*proc_openprom_deflookup_ptr)(struct inode *, struct qstr *, struct inode **);
 void (*proc_openprom_use)(struct inode *, int) = 0;
 static struct openpromfs_dev *proc_openprom_devices = NULL;
 static ino_t proc_openpromdev_ino = PROC_OPENPROMD_FIRST;
 
 struct inode_operations *
 proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
-                      int (*lookup)(struct inode *, const char *, int, struct inode **),
+                      int (*lookup)(struct inode *, struct qstr *, struct inode **),
                       void (*use)(struct inode *, int),
                       struct openpromfs_dev ***devices)
 {
@@ -218,14 +220,13 @@ proc_openprom_defreaddir(struct inode * inode, struct file * filp,
 }
 
 static int 
-proc_openprom_deflookup(struct inode * dir,const char * name, int len,
-                       struct inode ** result)
+proc_openprom_deflookup(struct inode * dir, struct qstr *str, struct inode ** result)
 {
        request_module("openpromfs");
        if (proc_openprom_inode_operations.lookup !=
            proc_openprom_deflookup)
                return proc_openprom_inode_operations.lookup 
-                               (dir, name, len, result);
+                               (dir, str, result);
        iput(dir);
        return -ENOENT;
 }
@@ -264,6 +265,7 @@ struct inode_operations proc_openprom_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
+       NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -350,7 +352,6 @@ static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
        int len;
        char tmp[30];
 
-       iput(inode);
        len = sprintf(tmp, "%d", current->pid);
        if (buflen < len)
                len = buflen;
@@ -358,6 +359,15 @@ static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
        return len;
 }
 
+static struct dentry * proc_self_follow_link(struct inode *inode, struct dentry *base)
+{
+       int len;
+       char tmp[30];
+
+       len = sprintf(tmp, "%d", current->pid);
+       return lookup_dentry(tmp, base, 1);
+}      
+
 static struct inode_operations proc_self_inode_operations = {
        NULL,                   /* no file-ops */
        NULL,                   /* create */
@@ -370,6 +380,7 @@ static struct inode_operations proc_self_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        proc_self_readlink,     /* readlink */
+       proc_self_follow_link,  /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -612,90 +623,41 @@ void proc_root_init(void)
 }
 
 
-int proc_match(int len,const char * name,struct proc_dir_entry * de)
-{
-       if (!de || !de->low_ino)
-               return 0;
-       /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
-       if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
-               return 1;
-       if (de->namelen != len)
-               return 0;
-       return !memcmp(name, de->name, len);
-}
-
-int proc_lookup(struct inode * dir,const char * name, int len,
-       struct inode ** result)
+int proc_lookup(struct inode * dir, struct qstr * str, struct inode ** result)
 {
        struct proc_dir_entry * de;
-       int ino;
 
        *result = NULL;
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               iput(dir);
+       if (!dir || !S_ISDIR(dir->i_mode))
                return -ENOTDIR;
-       }
 
        de = (struct proc_dir_entry *) dir->u.generic_ip;
-       if (!de) {
-               iput(dir);
+       if (!de)
                return -EINVAL;
-       }
 
-       /* Either remove this as soon as possible due to security problems,
-        * or uncomment the root-only usage.
-        */
-
-       /* Allow generic inode lookups everywhere.
-        * No other name in /proc must begin with a '['.
-        */
-       if(/*!current->uid &&*/ name[0] == '[')
-               return proc_arbitrary_lookup(dir,name,len,result);
-
-       /* Special case "." and "..": they aren't on the directory list */
-       *result = dir;
-       if (!len)
-               return 0;
-       if (name[0] == '.') {
-               if (len == 1)
-                       return 0;
-               if (name[1] == '.' && len == 2) {
-                       struct inode * inode;
-                       inode = proc_get_inode(dir->i_sb, de->parent->low_ino, de->parent);
-                       iput(dir);
-                       if (!inode)
+       *result = NULL;
+       for (de = de->subdir; de ; de = de->next) {
+               if (!de || !de->low_ino)
+                       continue;
+               if (de->namelen != str->len)
+                       continue;
+               if (!memcmp(str->name, de->name, str->len)) {
+                       int ino = de->low_ino | (dir->i_ino & ~(0xffff));
+                       if (!(*result = proc_get_inode(dir->i_sb, ino, de)))
                                return -EINVAL;
-                       *result = inode;
                        return 0;
                }
        }
-
-       *result = NULL;
-       for (de = de->subdir; de ; de = de->next) {
-               if (proc_match(len, name, de))
-                       break;
-       }
-       if (!de) {
-               iput(dir);
-               return -ENOENT;
-       }
-
-       ino = de->low_ino | (dir->i_ino & ~(0xffff));
-
-       if (!(*result = proc_get_inode(dir->i_sb, ino, de))) {
-               iput(dir);
-               return -EINVAL;
-       }
-       iput(dir);
-       return 0;
+       return -ENOENT;
 }
 
-static int proc_root_lookup(struct inode * dir,const char * name, int len,
-       struct inode ** result)
+static int proc_root_lookup(struct inode * dir,struct qstr *str, struct inode ** result)
 {
        unsigned int pid, c;
        int ino, retval;
        struct task_struct *p;
+       const char *name;
+       int len;
 
        atomic_inc(&dir->i_count);
 
@@ -710,13 +672,13 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len,
                read_unlock(&tasklist_lock);
        }
 
-       retval = proc_lookup(dir, name, len, result);
-       if (retval != -ENOENT) {
-               iput(dir);
+       retval = proc_lookup(dir, str, result);
+       if (retval != -ENOENT)
                return retval;
-       }
        
        pid = 0;
+       name = str->name;
+       len = str->len;
        while (len-- > 0) {
                c = *name - '0';
                name++;
@@ -732,16 +694,12 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len,
                }
        }
        p = find_task_by_pid(pid);
-       if (!pid || !p) {
-               iput(dir);
+       if (!pid || !p)
                return -ENOENT;
-       }
+
        ino = (pid << 16) + PROC_PID_INO;
-       if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid))) {
-               iput(dir);
+       if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid)))
                return -EINVAL;
-       }
-       iput(dir);
        return 0;
 }
 
index fd629a75c08f4fdf6b5e905e728a35b41d5b27c0..b1e77398c4a989c4d9b013948608f3b72ef35bd0 100644 (file)
@@ -69,6 +69,7 @@ struct inode_operations proc_scsi_inode_operations = {
     NULL,          /* mknod       */
     NULL,          /* rename      */
     NULL,          /* readlink    */
+    NULL,          /* follow_link */
     NULL,          /* readpage    */
     NULL,          /* writepage   */
     NULL,          /* bmap        */
index df2f5fb84b2014bd853b560aaecc223e9ba4cd7b..aaea5b45fca26306b1e5aefe9de04c78f8e8f35e 100644 (file)
@@ -1,35 +1,20 @@
 /*
- *  fs/readdir.c
+ *  linux/fs/readdir.c
  *
  *  Copyright (C) 1995  Linus Torvalds
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#ifdef CONFIG_TRANS_NAMES
-#include <linux/nametrans.h>
-#endif
-#include <linux/dalloc.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
-/* [T.Schoebel-Theuer] I am assuming that directories never get too large.
- * The problem is that getdents() delivers d_offset's that can be used
- * for lseek() by the user, so I must encode the status information for
- * name translation and dcache baskets in the offset.
- * Note that the linux man page getdents(2) does not mention that
- * the d_offset is fs-specific and can be used for lseek().
- */
-#define BASKET_BIT (1<<30) /* 31 is already used by affs */
-#define TRANS_BIT  (1<<29)
-
 /*
  * Traditional linux readdir() handling..
  *
@@ -50,9 +35,6 @@ struct old_linux_dirent {
 
 struct readdir_callback {
        struct old_linux_dirent * dirent;
-       struct file * file;
-       int translate;
-       off_t oldoffset;
        int count;
 };
 
@@ -65,26 +47,11 @@ static int fillonedir(void * __buf, const char * name, int namlen, off_t offset,
                return -EINVAL;
        buf->count++;
        dirent = buf->dirent;
-       copy_to_user(dirent->d_name, name, namlen);
-       put_user(0, dirent->d_name + namlen);
-#ifdef CONFIG_TRANS_NAMES
-       if(!buf->translate) {
-               char * cut;
-#ifdef CONFIG_TRANS_RESTRICT
-               struct inode * inode = buf->file->f_inode;
-               cut = testname(inode && inode->i_gid != CONFIG_TRANS_GID, dirent->d_name);
-#else
-               cut = testname(1, dirent->d_name);
-#endif
-               if(cut) {
-                       put_user(0, cut);
-                       buf->translate = 1;
-               }
-       }
-#endif
        put_user(ino, &dirent->d_ino);
        put_user(offset, &dirent->d_offset);
        put_user(namlen, &dirent->d_namlen);
+       copy_to_user(dirent->d_name, name, namlen);
+       put_user(0, dirent->d_name + namlen);
        return 0;
 }
 
@@ -93,7 +60,6 @@ asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
        int error = -EBADF;
        struct file * file;
        struct readdir_callback buf;
-       off_t oldpos;
 
        lock_kernel();
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
@@ -104,21 +70,11 @@ asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
        error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent));
        if (error)
                goto out;
-       oldpos = file->f_pos;
-       buf.file = file;
-       buf.dirent = dirent;
        buf.count = 0;
-       buf.translate = 0;
-       if(file->f_pos & TRANS_BIT) {
-               file->f_pos &= ~TRANS_BIT;
-               buf.translate = 1;
-       }
+       buf.dirent = dirent;
        error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
        if (error < 0)
                goto out;
-       if(buf.translate) {
-               file->f_pos = oldpos | TRANS_BIT;
-       }
        error = buf.count;
 out:
        unlock_kernel();
@@ -139,11 +95,8 @@ struct linux_dirent {
 struct getdents_callback {
        struct linux_dirent * current_dir;
        struct linux_dirent * previous;
-       struct file * file;
        int count;
-        int error;
-        int restricted;
-       int do_preload;
+       int error;
 };
 
 static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
@@ -152,51 +105,18 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
        struct getdents_callback * buf = (struct getdents_callback *) __buf;
        int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
 
-       /* Do not touch buf->error any more if everything is ok! */
+       buf->error = -EINVAL;   /* only used if we fail.. */
        if (reclen > buf->count)
-               return  (buf->error = -EINVAL);
-#ifdef CONFIG_DCACHE_PRELOAD
-       if(buf->do_preload && (name[0] != '.' || namlen > 2)) {
-               struct qstr qname = { name, namlen };
-               struct inode * dir = buf->file->f_inode;
-               d_entry_preliminary(dir->i_dentry, &qname, ino);
-       }
-#endif
+               return -EINVAL;
+       dirent = buf->previous;
+       if (dirent)
+               put_user(offset, &dirent->d_off);
        dirent = buf->current_dir;
-       copy_to_user(dirent->d_name, name, namlen);
-       put_user(0, dirent->d_name + namlen);
-#ifdef CONFIG_TRANS_NAMES
-       {
-               char * cut;
-#ifdef CONFIG_TRANS_RESTRICT
-               cut = testname(buf->restricted, dirent->d_name);
-#else
-               cut = testname(1, dirent->d_name);
-#endif
-               if(cut) {
-                       int newlen = (int)cut - (int)dirent->d_name;
-                       int newreclen = ROUND_UP(NAME_OFFSET(dirent) + newlen + 1);
-                       /* Either both must fit or none. This way we need
-                        * no status information in f_pos */
-                       if (reclen+newlen > buf->count)
-                               return -EINVAL;
-                       put_user(0, cut);
-                       put_user(ino, &dirent->d_ino);
-                       put_user(newreclen, &dirent->d_reclen);
-                       put_user(offset, &dirent->d_off);
-                       ((char *) dirent) += newreclen;
-                       buf->count -= newreclen;
-                       put_user(offset, &dirent->d_off);
-                       copy_to_user(dirent->d_name, name, namlen);
-                       put_user(0, dirent->d_name + namlen);
-               }
-       }
-#endif
+       buf->previous = dirent;
        put_user(ino, &dirent->d_ino);
        put_user(reclen, &dirent->d_reclen);
-       if (buf->previous)
-               put_user(buf->file->f_pos, &buf->previous->d_off);
-       buf->previous = dirent;
+       copy_to_user(dirent->d_name, name, namlen);
+       put_user(0, dirent->d_name + namlen);
        ((char *) dirent) += reclen;
        buf->current_dir = dirent;
        buf->count -= reclen;
@@ -206,6 +126,7 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
 asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
 {
        struct file * file;
+       struct linux_dirent * lastdirent;
        struct getdents_callback buf;
        int error = -EBADF;
 
@@ -218,72 +139,18 @@ asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
        error = verify_area(VERIFY_WRITE, dirent, count);
        if (error)
                goto out;
-       buf.file = file;
        buf.current_dir = (struct linux_dirent *) dirent;
        buf.previous = NULL;
        buf.count = count;
        buf.error = 0;
-       buf.restricted = 0;
-#ifdef CONFIG_TRANS_RESTRICT
-       buf.restricted = file->f_inode && file->f_inode->i_gid != CONFIG_TRANS_GID;
-#endif
-       buf.do_preload = 0;
-#ifdef CONFIG_DCACHE_PRELOAD
-       if(file->f_inode && file->f_inode->i_dentry &&
-          !(file->f_inode->i_sb->s_type->fs_flags & (FS_NO_DCACHE|FS_NO_PRELIM)) &&
-          !(file->f_inode->i_dentry->d_flag & D_PRELOADED))
-               buf.do_preload = 1;
-#endif
-       
-       if(!(file->f_pos & BASKET_BIT)) {
-               int oldcount;
-               do {
-                       oldcount = buf.count;
-                       error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
-                       if (error < 0)
-                               goto out;
-               } while(!buf.error && buf.count != oldcount);
-       }
-       if(!buf.error) {
-               int nr = 0;
-               struct dentry * list = file->f_inode ?
-                       d_basket(file->f_inode->i_dentry) : NULL;
-               struct dentry * ptr = list;
-#ifdef CONFIG_DCACHE_PRELOAD
-               if(buf.do_preload) {
-                       buf.do_preload = 0;
-                       file->f_inode->i_dentry->d_flag |= D_PRELOADED;
-               }
-#endif
-               if(ptr) {
-                       if(!(file->f_pos & BASKET_BIT))
-                               file->f_pos = BASKET_BIT;
-                       do {
-                               struct dentry * next = ptr->d_basket_next;
-                               struct inode * inode;
-                               /* vfs_locks() are missing here */
-                               inode = d_inode(&ptr);
-                               if(inode) {
-                                       nr++;
-                                       if(nr > (file->f_pos & ~BASKET_BIT)) {
-                                               int err = filldir(&buf, ptr->d_name.name,
-                                                                 ptr->d_name.len,
-                                                                 file->f_pos,
-                                                                 inode->i_ino);
-                                               if(err)
-                                                       break;
-                                               file->f_pos++;
-                                       }
-                                       iput(inode);
-                               }
-                               ptr = next;
-                       } while(ptr != list);
-               }
-       }
-       if (!buf.previous) {
+       error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
+       if (error < 0)
+               goto out;
+       lastdirent = buf.previous;
+       if (!lastdirent) {
                error = buf.error;
        } else {
-               put_user(file->f_pos, &buf.previous->d_off);
+               put_user(file->f_pos, &lastdirent->d_off);
                error = count - buf.count;
        }
 out:
index 03f6855528f7f62a611659aaa31c79833aeaafeb..0ab291256c0a43c1d5f95289992d743010620fe5 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -127,7 +127,7 @@ asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf)
        int error;
 
        lock_kernel();
-       error = namei(NAM_FOLLOW_LINK, filename, &inode);
+       error = namei(filename, &inode);
        if (error)
                goto out;
        if ((error = do_revalidate(inode)) == 0)
@@ -145,7 +145,7 @@ asmlinkage int sys_newstat(char * filename, struct stat * statbuf)
        int error;
 
        lock_kernel();
-       error = namei(NAM_FOLLOW_LINK, filename, &inode);
+       error = namei(filename, &inode);
        if (error)
                goto out;
        if ((error = do_revalidate(inode)) == 0)
@@ -168,7 +168,7 @@ asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
        int error;
 
        lock_kernel();
-       error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
+       error = lnamei(filename, &inode);
        if (error)
                goto out;
        if ((error = do_revalidate(inode)) == 0)
@@ -187,7 +187,7 @@ asmlinkage int sys_newlstat(char * filename, struct stat * statbuf)
        int error;
 
        lock_kernel();
-       error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
+       error = lnamei(filename, &inode);
        if (error)
                goto out;
        if ((error = do_revalidate(inode)) == 0)
@@ -241,15 +241,13 @@ out:
 asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
 {
        struct inode * inode;
-       int error = -EINVAL;
+       int error;
 
-       lock_kernel();
        if (bufsiz <= 0)
-               goto out;
-       error = verify_area(VERIFY_WRITE,buf,bufsiz);
-       if (error)
-               goto out;
-       error = namei(NAM_FOLLOW_TRAILSLASH, path, &inode);
+               return -EINVAL;
+
+       lock_kernel();
+       error = lnamei(path, &inode);
        if (error)
                goto out;
        error = -EINVAL;
@@ -263,6 +261,7 @@ asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
                inode->i_dirt = 1;
        }
        error = inode->i_op->readlink(inode,buf,bufsiz);
+       iput(inode);
 out:
        unlock_kernel();
        return error;
index 94fc31fc05b1aef2a1e85d1583194b13d0b2f286..e2b9eec925c9d4a9fd98fac8eab3ddc11a44b40a 100644 (file)
@@ -465,7 +465,7 @@ void put_super(kdev_t dev)
        }
        if (!(sb = get_super(dev)))
                return;
-       if (sb->s_covered) {
+       if (sb->s_root != sb->s_root->d_mounts) {
                printk("VFS: Mounted device %s - tssk, tssk\n",
                       kdevname(dev));
                return;
@@ -535,7 +535,6 @@ static struct super_block * read_super(kdev_t dev,const char *name,int flags,
                return NULL;
        }
        s->s_dev = dev;
-       s->s_covered = NULL;
        s->s_rd_only = 0;
        s->s_dirt = 0;
        s->s_type = type;
@@ -570,6 +569,30 @@ void put_unnamed_dev(kdev_t dev)
                        kdevname(dev));
 }
 
+static void d_umount(struct dentry *dentry)
+{
+       struct dentry * covers = dentry->d_covers;
+
+       if (covers == dentry) {
+               printk("VFS: unmount - covers == dentry?\n");
+               return;
+       }
+       covers->d_mounts = covers;
+       dentry->d_covers = dentry;
+       dput(covers);
+       dput(dentry);
+}
+
+static void d_mount(struct dentry *covers, struct dentry *dentry)
+{
+       if (covers->d_mounts != covers) {
+               printk("VFS: mount - already mounted\n");
+               return;
+       }
+       covers->d_mounts = dentry;
+       dentry->d_covers = covers;
+}
+
 static int do_umount(kdev_t dev,int unmount_root)
 {
        struct super_block * sb;
@@ -597,11 +620,9 @@ static int do_umount(kdev_t dev,int unmount_root)
                }
                return 0;
        }
-       if (!(sb=get_super(dev)) || !(sb->s_covered))
+       sb=get_super(dev);
+       if (!sb)
                return -ENOENT;
-       if (!sb->s_covered->i_mount)
-               printk("VFS: umount(%s): mounted inode has i_mount=NULL\n",
-                      kdevname(dev));
 
        /*
         * Before checking if the filesystem is still busy make sure the kernel
@@ -609,20 +630,16 @@ static int do_umount(kdev_t dev,int unmount_root)
         * too bad there are no quotas running anymore. Turn them on again by hand.
         */
        quota_off(dev, -1);
-       if (!fs_may_umount(dev, sb->s_mounted))
+       if (!fs_may_umount(dev, sb->s_root))
                return -EBUSY;
 
        /* Clear up the dcache tree. This should be cleaner.. */
-       while (sb->s_ibasket)
-               free_ibasket(sb);
-       if (sb->s_mounted->i_dentry)
-               d_del(sb->s_mounted->i_dentry, D_NO_CLEAR_INODE);
-
-       sb->s_covered->i_mount = NULL;
-       iput(sb->s_covered);
-       sb->s_covered = NULL;
-       iput(sb->s_mounted);
-       sb->s_mounted = NULL;
+       if (sb->s_root) {
+               d_umount(sb->s_root);
+               d_delete(sb->s_root);
+       }
+
+       sb->s_root = NULL;
        if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
                sb->s_op->write_super(sb);
        put_super(dev);
@@ -651,12 +668,7 @@ asmlinkage int sys_umount(char * name)
        lock_kernel();
        if (!suser())
                goto out;
-       retval = namei(NAM_FOLLOW_LINK, name, &inode);
-       if (retval) {
-               retval = namei(NAM_FOLLOW_TRAILSLASH, name, &inode);
-               if (retval)
-                       goto out;
-       }
+       retval = namei(name, &inode);
        if (S_ISBLK(inode->i_mode)) {
                dev = inode->i_rdev;
                retval = -EACCES;
@@ -666,7 +678,7 @@ asmlinkage int sys_umount(char * name)
                }
        } else {
                retval = -EINVAL;
-               if (!inode->i_sb || inode != inode->i_sb->s_mounted) {
+               if (!inode->i_sb || inode != inode->i_sb->s_root->d_inode) {
                        iput(inode);
                        goto out;
                }
@@ -719,45 +731,44 @@ out:
 
 int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
 {
-       struct inode * dir_i = NULL;
+       struct dentry * dir_d = NULL;
        struct super_block * sb;
        struct vfsmount *vfsmnt;
        int error;
-       int override = 0;
 
-       if(dir_name) {
-               char c;
-
-               get_user(c, dir_name);
-               override = (c == '!');
-       }
        if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
                return -EACCES;
                /*flags |= MS_RDONLY;*/
-       if(override)
-               dir_name++;
-       error = namei(NAM_FOLLOW_LINK, dir_name, &dir_i);
-       if (error)
+
+       dir_d = lookup_dentry(dir_name, NULL, 1);
+       error = PTR_ERR(dir_d);
+       if (IS_ERR(dir_d))
                return error;
-       if (!override && (atomic_read(&dir_i->i_count) != 1 || dir_i->i_mount)) {
-               iput(dir_i);
+
+       if (dir_d->d_flag & D_NEGATIVE) {
+               dput(dir_d);
+               return -ENOENT;
+       }
+
+       if (dir_d->d_covers != dir_d) {
+               dput(dir_d);
                return -EBUSY;
        }
-       if (!S_ISDIR(dir_i->i_mode)) {
-               iput(dir_i);
+       if (!S_ISDIR(dir_d->d_inode->i_mode)) {
+               dput(dir_d);
                return -ENOTDIR;
        }
-       if (!fs_may_mount(dev) && !override) {
-               iput(dir_i);
+       if (!fs_may_mount(dev)) {
+               dput(dir_d);
                return -EBUSY;
        }
        sb = read_super(dev,type,flags,data,0);
        if (!sb) {
-               iput(dir_i);
+               dput(dir_d);
                return -EINVAL;
        }
-       if (sb->s_covered) {
-               iput(dir_i);
+       if (sb->s_root->d_covers != sb->s_root) {
+               dput(dir_d);
                return -EBUSY;
        }
        vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
@@ -765,25 +776,8 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha
                vfsmnt->mnt_sb = sb;
                vfsmnt->mnt_flags = flags;
        }
-       {
-               struct dentry * old = dir_i->i_dentry;
-               struct dentry * new;
-               vfs_lock();
-               new = d_alloc(old->d_parent, old->d_name.len, 1);
-               if(new) {
-                       struct qstr copy = { old->d_name.name, old->d_name.len };
-                       d_add(new, sb->s_mounted, &copy, D_DUPLICATE);
-                       vfs_unlock();
-               } else {
-                       printk("VFS: cannot setup dentry for mount\n");
-                       iput(dir_i);
-                       return -ENOMEM;
-               }
-               vfs_unlock();
-       }
-       sb->s_covered = dir_i;
-       dir_i->i_mount = sb->s_mounted;
-       return 0;               /* we don't iput(dir_i) - see umount */
+       d_mount(dir_d, sb->s_root);
+       return 0;               /* we don't dput(dir) - see umount */
 }
 
 
@@ -824,10 +818,10 @@ static int do_remount(const char *dir,int flags,char *data)
        struct inode *dir_i;
        int retval;
 
-       retval = namei(NAM_FOLLOW_LINK, dir, &dir_i);
+       retval = namei(dir, &dir_i);
        if (retval)
                return retval;
-       if (dir_i != dir_i->i_sb->s_mounted) {
+       if (dir_i != dir_i->i_sb->s_root->d_inode) {
                iput(dir_i);
                return -EINVAL;
        }
@@ -916,7 +910,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
        t = fstype->name;
        fops = NULL;
        if ((fstype->fs_flags & FS_REQUIRES_DEV)) {
-               retval = namei(NAM_FOLLOW_LINK, dev_name, &inode);
+               retval = namei(dev_name, &inode);
                if (retval)
                        goto out;
                retval = -ENOTBLK;
@@ -986,7 +980,7 @@ __initfunc(static void do_mount_root(void))
        struct file_system_type * fs_type;
        struct super_block * sb;
        struct vfsmount *vfsmnt;
-       struct inode * inode, * d_inode = NULL;
+       struct inode * d_inode = NULL;
        struct file filp;
        int retval;
   
@@ -1005,15 +999,11 @@ __initfunc(static void do_mount_root(void))
                        sb->s_dev = get_unnamed_dev();
                        sb->s_flags = root_mountflags & ~MS_RDONLY;
                        if (nfs_root_mount(sb) >= 0) {
-                               inode = sb->s_mounted;
-                               atomic_add(3, &inode->i_count);
-                               sb->s_covered = inode;
                                sb->s_rd_only = 0;
                                sb->s_dirt = 0;
                                sb->s_type = fs_type;
-                               current->fs->pwd = inode;
-                               current->fs->root = inode;
-                               (void)d_alloc_root(inode);
+                               current->fs->root = dget(sb->s_root);
+                               current->fs->pwd = dget(sb->s_root);
                                ROOT_DEV = sb->s_dev;
                                printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
                                vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
@@ -1070,15 +1060,9 @@ __initfunc(static void do_mount_root(void))
                        continue;
                sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
                if (sb) {
-                       inode = sb->s_mounted;
-
-                       /* NOTE! it is logically used 4 times, not 1 */
-                       atomic_add(3, &inode->i_count);
-                       sb->s_covered = inode;
                        sb->s_flags = root_mountflags;
-                       current->fs->pwd = inode;
-                       current->fs->root = inode;
-                       (void)d_alloc_root(inode);
+                       current->fs->root = dget(sb->s_root);
+                       current->fs->pwd = dget(sb->s_root);
                        printk ("VFS: Mounted root (%s filesystem)%s.\n",
                                fs_type->name,
                                (sb->s_flags & MS_RDONLY) ? " readonly" : "");
@@ -1125,7 +1109,7 @@ __initfunc(static int do_change_root(kdev_t new_root_dev,const char *put_old))
        do_mount_root();
        old_fs = get_fs();
        set_fs(get_ds());
-        error = namei(NAM_FOLLOW_LINK, put_old, &inode);
+        error = namei(put_old, &inode);
        if (error) inode = NULL;
        set_fs(old_fs);
        if (!error && (atomic_read(&inode->i_count) != 1 || inode->i_mount))
index 2f40ad67322dd8d1bfcb81671099dec809b36da0..7d80c32f82b8c6ad7b015b534c7ffd91e9ced21c 100644 (file)
@@ -517,4 +517,7 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 #define SWP_OFFSET(entry) ((entry) >> 40)
 #define SWP_ENTRY(type,offset) pte_val(mk_swap_pte((type),(offset)))
 
+#define module_map     vmalloc
+#define module_unmap   vfree
+
 #endif /* _ALPHA_PGTABLE_H */
index 7d973530c47ae6b848d55d394e77b4b7731c442d..347611f1bd10e11d3acd3128c05b212a8a304b36 100644 (file)
@@ -491,4 +491,7 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
 #define SWP_OFFSET(entry) ((entry) >> 8)
 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
 
+#define module_map      vmalloc
+#define module_unmap    vfree
+
 #endif /* _I386_PAGE_H */
index 512e0b05423072eb928999757dbeafa87c8750c2..ab3ca802e7618e20897a187295c259552410c700 100644 (file)
@@ -12,4 +12,6 @@ extern unsigned int local_irq_count[NR_CPUS];
 #define hardirq_enter(cpu)     (local_irq_count[cpu]++)
 #define hardirq_exit(cpu)      (local_irq_count[cpu]--)
 
+#define synchronize_irq()      do { } while (0)
+
 #endif
index 9463700a3e471e42d66d6e84f729b00decc2bffd..589dfe956cb3381f38c512d50e0c4f7489f45e4c 100644 (file)
@@ -95,38 +95,23 @@ extern void cache_push_v (unsigned long vaddr, int len);
 
 extern inline void flush_cache_mm(struct mm_struct *mm)
 {
-#if FLUSH_VIRTUAL_CACHE_040
-       if (mm == current->mm) __flush_cache_all();
-#else
-       if (mm == current->mm) __flush_cache_030();
-#endif
+       if (mm == current->mm)
+               __flush_cache_030();
 }
 
 extern inline void flush_cache_range(struct mm_struct *mm,
                                     unsigned long start,
                                     unsigned long end)
 {
-       if (mm == current->mm){
-#if FLUSH_VIRTUAL_CACHE_040
-           if (CPU_IS_040_OR_060)
-               cache_push_v(start, end-start);
-           else
-#endif
+       if (mm == current->mm)
                __flush_cache_030();
-       }
 }
 
 extern inline void flush_cache_page(struct vm_area_struct *vma,
                                    unsigned long vmaddr)
 {
-       if (vma->vm_mm == current->mm){
-#if FLUSH_VIRTUAL_CACHE_040
-           if (CPU_IS_040_OR_060)
-               cache_push_v(vmaddr, PAGE_SIZE);
-           else
-#endif
+       if (vma->vm_mm == current->mm)
                __flush_cache_030();
-       }
 }
 
 /* Push the page at kernel virtual address and clear the icache */
@@ -783,4 +768,7 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
 
 #endif /* __ASSEMBLY__ */
 
+#define module_map      vmalloc
+#define module_unmap    vfree
+
 #endif /* _M68K_PGTABLE_H */
index 7b11877686fb6e78fae4a9e52d3c7b039d48d067..cd8cb1dc56351c670fdce50d528540121d1b8213 100644 (file)
  * for more details.
  *
  * Copyright (C) 1996 by Ralf Baechle
+ *
+ * $Id: atomic.h,v 1.2 1997/06/25 19:10:33 ralf Exp $
  */
 #ifndef __ASM_MIPS_ATOMIC_H
 #define __ASM_MIPS_ATOMIC_H
 
 #include <asm/sgidefs.h>
 
-/*
- * Make sure gcc doesn't try to be clever and move things around
- * on us. We need to use _exactly_ the address the user gave us,
- * not some alias that contains the same information.
- */
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
-
 #ifdef __SMP__
 typedef struct { volatile int counter; } atomic_t;
 #else
 typedef struct { int counter; } atomic_t;
 #endif
 
+#ifdef __KERNEL__
 #define ATOMIC_INIT(i)    { (i) }
 
 #define atomic_read(v) ((v)->counter)
@@ -97,6 +93,14 @@ extern __inline__ int atomic_sub_return(int i, atomic_t * v)
  * ... while for MIPS II and better we can use ll/sc instruction.  This
  * implementation is SMP safe ...
  */
+
+/*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+ * not some alias that contains the same information.
+ */
+#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+
 extern __inline__ void atomic_add(int i, volatile atomic_t * v)
 {
        unsigned long temp;
@@ -181,5 +185,6 @@ extern __inline__ int atomic_sub_return(int i, atomic_t * v)
 
 #define atomic_inc(v) atomic_add(1,(v))
 #define atomic_dec(v) atomic_sub(1,(v))
+#endif /* defined(__KERNEL__) */
 
 #endif /* __ASM_MIPS_ATOMIC_H */
index 92e3b8863f50a60631566d0b78eda5ac3f6a7dfa..d7356d91a8500e4ba5ba7ec19f7e6716b27927e2 100644 (file)
@@ -6,15 +6,12 @@
  * for more details.
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: byteorder.h,v 1.5 1997/06/25 19:10:18 ralf Exp $
  */
 #ifndef __ASM_MIPS_BYTEORDER_H
 #define __ASM_MIPS_BYTEORDER_H
 
-extern unsigned long int ntohl(unsigned long int __x);
-extern unsigned short int ntohs(unsigned short int __x);
-extern unsigned short int htons(unsigned short int __x);
-extern unsigned long int htonl(unsigned long int __x);
-
 #define __swap32(x) \
        ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
                             (((unsigned long int)(x) & 0x0000ff00U) <<  8) | \
@@ -94,6 +91,66 @@ extern unsigned long int htonl(unsigned long int __x);
 #error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
 #endif
 
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
+{
+       return cpu_to_le16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+       return cpu_to_le32(*addr);
+}
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+       return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+       return cpu_to_be32(*addr);
+}
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+       *addr = cpu_to_le16(*addr);
+}
+
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+       *addr = cpu_to_le32(*addr);
+}
+
+extern __inline__ void cpu_to_be16s(__u16 *addr)
+{
+       *addr = cpu_to_be16(*addr);
+}
+
+extern __inline__ void cpu_to_be32s(__u32 *addr)
+{
+       *addr = cpu_to_be32(*addr);
+}
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
+
+#ifdef __KERNEL__
+extern unsigned long int ntohl(unsigned long int __x);
+extern unsigned short int ntohs(unsigned short int __x);
+extern unsigned short int htons(unsigned short int __x);
+extern unsigned long int htonl(unsigned long int __x);
+
+
 extern __inline__ unsigned long int ntohl(unsigned long int __x)
 {
        return __constant_ntohl(__x);
@@ -113,5 +170,6 @@ extern __inline__ unsigned short int htons(unsigned short int __x)
 {
        return __constant_htons(__x);
 }
+#endif /* __KERNEL__ */
 
 #endif /* __ASM_MIPS_BYTEORDER_H */
index c5f9d20c7ee3c607bf71f013768dadd5acebd817..776c658d48e78dea0752ba27c9012c246187d3e4 100644 (file)
@@ -52,23 +52,20 @@ unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, un
  */
 static inline unsigned short int csum_fold(unsigned int sum)
 {
-       unsigned int __res;
-
-    __asm__("
-       .set    noat
-       srl     $1,%0,16
-       andi    %0,0xffff
-       addu    $1,%0
-       srl     %0,$1,16                # addup halfword carry
-       andi    $1,0xffff
-       addu    $1,%0
-       nor     %0,$0,$1
+       __asm__("
+       .set    noat            
+       sll     $1,%0,16
+       addu    %0,$1
+       sltu    $1,%0,$1
+       srl     %0,%0,16
+       addu    %0,$1
+       xori    %0,0xffff
        .set    at"
-       : "=r"(__res)
+       : "=r" (sum)
        : "0" (sum)
        : "$1");
 
-       return __res;
+       return sum;
 }
  
 /*
@@ -140,20 +137,14 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
        addu    %0,%2
        sltu    $1,%0,%2
        addu    %0,$1
+
        addu    %0,%3
        sltu    $1,%0,%3
        addu    %0,$1
+
        addu    %0,%4
        sltu    $1,%0,%4
        addu    %0,$1
-
-       srl     $1,%0,16
-       andi    %0,0xffff
-       addu    %0,$1
-       srl     $1,%0,16                # addup halfword carry
-       andi    %0,0xffff
-       addu    %0,$1
-       nor     %0,$0,%0
        .set    at"
        : "=r" (sum)
        : "0" (daddr), "r"(saddr),
@@ -165,7 +156,7 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
            "r"(sum)
        : "$1");
 
-       return (unsigned short)sum;
+       return csum_fold(sum);
 }
 
 /*
@@ -174,22 +165,10 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
  */
 static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
 {
-    unsigned short int sum;
-
-    __asm__("
-       .set    noat
-       srl     $1,%0,16
-       andi    %0,0xffff
-       addu    %0,$1
-       sltu    $1,%0,$1
-       addu    %0,$1
-       nor     %0,$0,%0
-       .set    at"
-       : "=r"(sum)
-       : "0" (csum_partial(buff, len, 0))
-       : "$1");
+       unsigned int sum;
 
-       return sum;
+       sum = csum_partial(buff, len, 0);
+       return csum_fold(sum);
 }
 
 #define _HAVE_ARCH_IPV6_CSUM
index 0f6e63a257cf408a34f0b6526b19c714853f7b1e..3f5430d977717c87ea01621e194a35e4655561be 100644 (file)
 #define MM_PGD        8
 #define MM_CONTEXT    28
 
+/* Linux sigcontext offsets. */
+#define SC_REGMASK    0
+#define SC_STATUS     4
+#define SC_PC         8
+#define SC_REGS       16
+#define SC_FPREGS     272
+#define SC_OWNEDFP    528
+#define SC_FPC_CSR    532
+#define SC_FPC_EIR    536
+#define SC_SSFLAGS    540
+#define SC_MDHI       544
+#define SC_MDLO       552
+#define SC_CAUSE      560
+#define SC_BADVADDR   564
+#define SC_SIGSET     568
+
 #endif /* !(_MIPS_OFFSET_H) */
index c6bb9b2de2d637a2d4e126ee44881e3b69d16171..5d080f822676074e1251cee1df2bbd9867ac29b5 100644 (file)
@@ -765,4 +765,7 @@ extern inline void set_context(unsigned long val)
 
 #endif /* !defined (__LANGUAGE_ASSEMBLY__) */
 
+#define module_map      vmalloc
+#define module_unmap    vfree
+
 #endif /* __ASM_MIPS_PGTABLE_H */
index ebacf77603a0236529023919d2f2ea00e7379e8d..c08923223f8c1e8a93eab93d33fa0c62108cd2a1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: r4kcache.h,v 1.1 1997/06/06 09:39:42 ralf Exp $
+/* $Id: r4kcache.h,v 1.2 1997/06/25 17:04:19 ralf Exp $
  * r4kcache.h: Inline assembly cache operations.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -339,6 +339,7 @@ extern inline void blast_dcache32_page(unsigned long page)
        unsigned long start = page;
        unsigned long end = (start + PAGE_SIZE);
 
+       __asm__ __volatile__("nop;nop;nop;nop");
        while(start < end) {
                __asm__ __volatile__("
                        .set noreorder
@@ -429,7 +430,7 @@ extern inline void blast_dcache32_page_indexed(unsigned long page)
                        .set reorder"
                        :
                        : "r" (start),
-                         "i" (Index_Invalidate_I));
+                         "i" (Index_Writeback_Inv_D));
                start += 0x800;
        }
 }
index 3e7346dee1020db36ffc52323139a52a0b8fe21f..6b25821bb5b8cd70a091399e21286b86c7920a90 100644 (file)
@@ -1,30 +1,20 @@
+/*
+ * include/asm-mips/uaccess.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: sigcontext.h,v 1.3 1997/06/25 16:57:31 ralf Exp $
+ */
 #ifndef __ASM_MIPS_SIGCONTEXT_H
 #define __ASM_MIPS_SIGCONTEXT_H
 
-#ifdef __LANGUAGE_ASSEMBLY__
-
-#define SC_REGMASK     0
-#define SC_STATUS      4
-#define SC_PC          8
-#define SC_REGS                16
-#define SC_FPREGS      272
-#define SC_OWNEDFP     528
-#define SC_FPC_CSR     532
-#define SC_FPC_EIR     536
-#define SC_SSFLAGS     540
-#define SC_MDHI                544
-#define SC_MDLO                552
-
-#endif
-
-#if defined(__LANGUAGE_C__) || \
-    defined(_LANGUAGE_C) || \
-    defined(__LANGUAGE_C_PLUS_PLUS__) || \
-    defined(__LANGUAGE_OBJECTIVE_C__)
-
 /*
- * Whenever this structure is changed you must update the offsets in
- * arch/mips/mips<isa>/fp-context.S.
+ * Keep this struct definition in sync with the sigcontext fragment
+ * in arch/mips/tools/offset.c
  */
 struct sigcontext {
        unsigned int       sc_regmask;          /* Unused */
@@ -45,6 +35,5 @@ struct sigcontext {
        sigset_t           sc_sigset;
        unsigned long      __pad0[3];           /* pad for constant size */
 };
-#endif
 
 #endif /* __ASM_MIPS_SIGCONTEXT_H */
index b650209dd3c612567ee511ed28d5e2f30bf4b8af..b7ab2d8540d0fee56b7be08122b44fa1de032e2e 100644 (file)
@@ -5,7 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: uaccess.h,v 1.4 1997/07/01 08:23:56 ralf Exp $
  */
 #ifndef __ASM_MIPS_UACCESS_H
 #define __ASM_MIPS_UACCESS_H
@@ -124,57 +126,48 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
        __cu_len; \
 })
 
+/*
+ * Yuck.  We need two variants, one for 64bit operation and one
+ * for 32 bit mode and old iron.
+ */
+#ifdef __mips64
+#define __GET_USER_DW __get_user_asm("ld")
+#else
+#define __GET_USER_DW __get_user_asm_ll32
+#endif
+
 #define __get_user_nocheck(x,ptr,size) ({ \
 long __gu_err; \
-long __gu_val; \
+__typeof(*(ptr)) __gu_val; \
 long __gu_addr; \
 __asm__("":"=r" (__gu_val)); \
 __gu_addr = (long) (ptr); \
-__gu_err = 0; \
+__asm__("":"=r" (__gu_err)); \
 switch (size) { \
-case 1: __get_user_nocheck_asm("lb"); break; \
-case 2: __get_user_nocheck_asm("lh"); break; \
-case 4: __get_user_nocheck_asm("lw"); break; \
-case 8: __get_user_nocheck_asm("ld"); break; \
+case 1: __get_user_asm("lb"); break; \
+case 2: __get_user_asm("lh"); break; \
+case 4: __get_user_asm("lw"); break; \
+case 8: __GET_USER_DW; break; \
 default: __get_user_unknown(); break; \
 } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
 
-#define __get_user_nocheck_asm(insn) \
-({ \
-__asm__ __volatile__( \
-       "1:\t" insn "\t%1,%3\n" \
-       "2:\n\t" \
-       ".section\t.fixup,\"ax\"\n" \
-       "3:\t.set\tnoat\n\t" \
-       "la\t$1,2b\n\t" \
-       "li\t%0,%4\n\t" \
-       "jr\t$1\n\t" \
-       ".set\tat\n\t" \
-       ".previous\n\t" \
-       ".section\t__ex_table,\"a\"\n\t" \
-       STR(PTR)"\t1b,3b\n\t" \
-       ".previous" \
-       :"=r" (__gu_err), "=r" (__gu_val) \
-       :"0" (__gu_err), "o" (__m(__gu_addr)), "i" (-EFAULT) \
-       :"$1"); })
-
 #define __get_user_check(x,ptr,size,mask) ({ \
 long __gu_err; \
-long __gu_val; \
+__typeof__(*(ptr)) __gu_val; \
 long __gu_addr; \
 __asm__("":"=r" (__gu_val)); \
 __gu_addr = (long) (ptr); \
-__gu_err = -EFAULT; \
+__asm__("":"=r" (__gu_err)); \
 if (__access_ok(__gu_addr,size,mask)) { \
 switch (size) { \
-case 1: __get_user_check_asm("lb"); break; \
-case 2: __get_user_check_asm("lh"); break; \
-case 4: __get_user_check_asm("lw"); break; \
-case 8: __get_user_check_asm("ld"); break; \
+case 1: __get_user_asm("lb"); break; \
+case 2: __get_user_asm("lh"); break; \
+case 4: __get_user_asm("lw"); break; \
+case 8: __GET_USER_DW; break; \
 default: __get_user_unknown(); break; \
 } } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
 
-#define __get_user_check_asm(insn) \
+#define __get_user_asm(insn) \
 ({ \
 __asm__ __volatile__( \
        "1:\t" insn "\t%1,%2\n\t" \
@@ -183,6 +176,7 @@ __asm__ __volatile__( \
        ".section\t.fixup,\"ax\"\n" \
        "3:\t.set\tnoat\n\t" \
        "la\t$1,2b\n\t" \
+       "li\t%0,%3\n\t" \
        "jr\t$1\n\t" \
        ".set\tat\n\t" \
        ".previous\n\t" \
@@ -190,30 +184,82 @@ __asm__ __volatile__( \
        STR(PTR)"\t1b,3b\n\t" \
        ".previous" \
        :"=r" (__gu_err), "=r" (__gu_val) \
-       :"o" (__m(__gu_addr)) \
+       :"o" (__m(__gu_addr)), "i" (-EFAULT) \
+       :"$1"); })
+
+/*
+ * Get a long long 64 using 32 bit registers.
+ */
+#define __get_user_asm_ll32 \
+({ \
+__asm__ __volatile__( \
+       "1:\tlw\t%1,%2\n" \
+       "2:\tlw\t%D1,%3\n\t" \
+       "move\t%0,$0\n" \
+       "3:\t.section\t.fixup,\"ax\"\n" \
+       "4:\t.set\tnoat\n\t" \
+       "la\t$1,3b\n\t" \
+       "li\t%0,%4\n\t" \
+       "jr\t$1\n\t" \
+       ".set\tat\n\t" \
+       ".previous\n\t" \
+       ".section\t__ex_table,\"a\"\n\t" \
+       STR(PTR)"\t1b,4b\n\t" \
+       STR(PTR)"\t2b,4b\n\t" \
+       ".previous" \
+       :"=r" (__gu_err), "=&r" (__gu_val) \
+       :"o" (__m(__gu_addr)), "o" (__m(__gu_addr + 4)), \
+        "i" (-EFAULT) \
        :"$1"); })
 
 extern void __get_user_unknown(void);
 
+/*
+ * Yuck.  We need two variants, one for 64bit operation and one
+ * for 32 bit mode and old iron.
+ */
+#ifdef __mips64
+#define __PUT_USER_DW __put_user_asm("sd")
+#else
+#define __PUT_USER_DW __put_user_asm_ll32
+#endif
+
 #define __put_user_nocheck(x,ptr,size) ({ \
 long __pu_err; \
 __typeof__(*(ptr)) __pu_val; \
 long __pu_addr; \
 __pu_val = (x); \
 __pu_addr = (long) (ptr); \
-__pu_err = 0; \
+__asm__("":"=r" (__pu_err)); \
 switch (size) { \
-case 1: __put_user_nocheck_asm("sb"); break; \
-case 2: __put_user_nocheck_asm("sh"); break; \
-case 4: __put_user_nocheck_asm("sw"); break; \
-case 8: __put_user_nocheck_asm("sd"); break; \
+case 1: __put_user_asm("sb"); break; \
+case 2: __put_user_asm("sh"); break; \
+case 4: __put_user_asm("sw"); break; \
+case 8: __PUT_USER_DW; break; \
 default: __put_user_unknown(); break; \
 } __pu_err; })
 
-#define __put_user_nocheck_asm(insn) \
+#define __put_user_check(x,ptr,size,mask) ({ \
+long __pu_err; \
+__typeof__(*(ptr)) __pu_val; \
+long __pu_addr; \
+__pu_val = (x); \
+__pu_addr = (long) (ptr); \
+__asm__("":"=r" (__pu_err)); \
+if (__access_ok(__pu_addr,size,mask)) { \
+switch (size) { \
+case 1: __put_user_asm("sb"); break; \
+case 2: __put_user_asm("sh"); break; \
+case 4: __put_user_asm("sw"); break; \
+case 8: __PUT_USER_DW; break; \
+default: __put_user_unknown(); break; \
+} } __pu_err; })
+
+#define __put_user_asm(insn) \
 ({ \
 __asm__ __volatile__( \
-       "1:\t" insn "\t%1,%2\n" \
+       "1:\t" insn "\t%1,%2\n\t" \
+       "move\t%0,$0\n" \
        "2:\n\t" \
        ".section\t.fixup,\"ax\"\n" \
        "3:\t.set\tnoat\n\t" \
@@ -229,39 +275,27 @@ __asm__ __volatile__( \
        :"r" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT) \
        :"$1"); })
 
-#define __put_user_check(x,ptr,size,mask) ({ \
-long __pu_err; \
-__typeof__(*(ptr)) __pu_val; \
-long __pu_addr; \
-__pu_val = (x); \
-__pu_addr = (long) (ptr); \
-__pu_err = -EFAULT; \
-if (__access_ok(__pu_addr,size,mask)) { \
-switch (size) { \
-case 1: __put_user_check_asm("sb"); break; \
-case 2: __put_user_check_asm("sh"); break; \
-case 4: __put_user_check_asm("sw"); break; \
-case 8: __put_user_check_asm("sd"); break; \
-default: __put_user_unknown(); break; \
-} } __pu_err; })
-
-#define __put_user_check_asm(insn) \
+#define __put_user_asm_ll32 \
 ({ \
 __asm__ __volatile__( \
-       "1:\t" insn "\t%1,%2\n\t" \
+       "1:\tsw\t%1,%2\n\t" \
+       "2:\tsw\t%D1,%3\n" \
        "move\t%0,$0\n" \
-       "2:\n\t" \
+       "3:\n\t" \
        ".section\t.fixup,\"ax\"\n" \
-       "3:\t.set\tnoat\n\t" \
-       "la\t$1,2b\n\t" \
+       "4:\t.set\tnoat\n\t" \
+       "la\t$1,3b\n\t" \
+       "li\t%0,%4\n\t" \
        "jr\t$1\n\t" \
        ".set\tat\n\t" \
        ".previous\n\t" \
        ".section\t__ex_table,\"a\"\n\t" \
-       STR(PTR)"\t1b,3b\n\t" \
+       STR(PTR)"\t1b,4b\n\t" \
+       STR(PTR)"\t2b,4b\n\t" \
        ".previous" \
        :"=r" (__pu_err) \
-       :"r" (__pu_val), "o" (__m(__pu_addr)) \
+       :"r" (__pu_val), "o" (__m(__pu_addr)), "o" (__m(__pu_addr + 4)), \
+        "i" (-EFAULT) \
        :"$1"); })
 
 extern void __put_user_unknown(void);
index 243a0b115223551370d5d2f71cf1765736e75031..e9c400345491681356df4949afeded68df6bddc3 100644 (file)
@@ -361,4 +361,7 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
 #define SWP_OFFSET(entry) ((entry) >> 8)
 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
 
+#define module_map      vmalloc
+#define module_unmap    vfree
+
 #endif /* _PPC_PAGE_H */
index f81ab33b9cb08ea932649808e5f2f0613a8e1f13..59fcd4337e7def62c5114ac3e336e159695e76c2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: asi.h,v 1.16 1996/04/25 06:12:43 davem Exp $ */
+/* $Id: asi.h,v 1.17 1997/06/24 15:48:10 jj Exp $ */
 #ifndef _SPARC_ASI_H
 #define _SPARC_ASI_H
 
@@ -69,7 +69,7 @@
 /* Block-copy operations are available only on certain V8 cpus. */
 #define ASI_M_BCOPY         0x17   /* Block copy */
 
-/* These affect only the ICACHE and are Ross HyperSparc specific. */
+/* These affect only the ICACHE and are Ross HyperSparc and TurboSparc specific. */
 #define ASI_M_IFLUSH_PAGE   0x18   /* Flush I Cache Line (page); wo, ss */
 #define ASI_M_IFLUSH_SEG    0x19   /* Flush I Cache Line (seg); wo, ss */
 #define ASI_M_IFLUSH_REGION 0x1A   /* Flush I Cache Line (region); wo, ss */
@@ -97,7 +97,7 @@
 /* This is ROSS HyperSparc only. */
 #define ASI_M_FLUSH_IWHOLE 0x31   /* Flush entire ICACHE; wo, ss */
 
-/* Tsunami/Viking i/d cache flash clear. */
+/* Tsunami/Viking/TurboSparc i/d cache flash clear. */
 #define ASI_M_IC_FLCLEAR   0x36
 #define ASI_M_DC_FLCLEAR   0x37
 
index 80eff02ea5b8ea9eb5ee012b4daad848ef4d2224..ccc5e7fced500972bd395c8bd379642487df51ee 100644 (file)
@@ -63,8 +63,8 @@
 /* 119 is the non-posix getpgrp tty ioctl */
 #define __TIOCCDTR        _IO('t', 120) /* SunOS Specific */
 #define __TIOCSDTR        _IO('t', 121) /* SunOS Specific */
-#define __TIOCCBRK        _IO('t', 122) /* SunOS Specific */
-#define __TIOCSBRK        _IO('t', 123) /* SunOS Specific */
+#define TIOCCBRK        _IO('t', 122)
+#define TIOCSBRK        _IO('t', 123)
 #define __TIOCLGET        _IOW('t', 124, int) /* SunOS Specific */
 #define __TIOCLSET        _IOW('t', 125, int) /* SunOS Specific */
 #define __TIOCLBIC        _IOW('t', 126, int) /* SunOS Specific */
index e5e5a18c86c1d13bb703d0be567720ee1ed3471c..5f27490153421ed8b7f5f535351196517b703d8d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mbus.h,v 1.8 1996/08/29 09:48:21 davem Exp $
+/* $Id: mbus.h,v 1.9 1997/06/24 15:48:12 jj Exp $
  * mbus.h:  Various defines for MBUS modules.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -25,7 +25,8 @@ enum mbus_module {
        Viking_30         = 10,
        Viking_35         = 11,
        Viking_new        = 12,
-       SRMMU_INVAL_MOD   = 13,
+       TurboSparc        = 13,
+       SRMMU_INVAL_MOD   = 14,
 };
 
 extern enum mbus_module srmmu_modtype;
@@ -71,6 +72,7 @@ extern unsigned int hwbug_bitmask;
 
 /* Fujitsu */
 #define FMI_AURORA             0x4   /* MB8690x, a Swift module... */
+#define FMI_TURBO              0x5   /* MB86907, a TurboSparc module... */
 
 /* For multiprocessor support we need to be able to obtain the CPU id and
  * the MBUS Module id.
index 40c6de10b41988343cf62cb651acb34f3a08d141..bb404745f3d6f021af03f23bb0a2bb69190431e3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.15 1997/03/18 18:00:18 jj Exp $
+/* $Id: oplib.h,v 1.16 1997/06/27 14:55:04 jj Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -272,12 +272,12 @@ extern int prom_searchsiblings(int node_start, char *name);
 /* Return the first property type, as a string, for the given node.
  * Returns a null string on error.
  */
-extern char *prom_firstprop(int node);
+extern char *prom_firstprop(int node, char *buffer);
 
 /* Returns the next property after the passed property for the given
  * node.  Returns null string on failure.
  */
-extern char *prom_nextprop(int node, char *prev_property);
+extern char *prom_nextprop(int node, char *prev_property, char *buffer);
 
 /* Returns 1 if the specified node has given property. */
 extern int prom_node_has_property(int node, char *property);
index 5b54f967ca638ba3b2c0edbbef5148493f6f55b9..de8ce568720f1b43b8066311fea402e276069ca0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.61 1997/06/06 10:56:34 jj Exp $ */
+/* $Id: pgtable.h,v 1.62 1997/06/27 14:55:00 jj Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -394,4 +394,7 @@ __get_iospace (unsigned long addr)
        }
 }
 
+#define module_map      vmalloc
+#define module_unmap    vfree
+
 #endif /* !(_SPARC_PGTABLE_H) */
diff --git a/include/asm-sparc/turbosparc.h b/include/asm-sparc/turbosparc.h
new file mode 100644 (file)
index 0000000..b0adb81
--- /dev/null
@@ -0,0 +1,114 @@
+/* $Id: turbosparc.h,v 1.3 1997/06/26 12:59:27 jj Exp $
+ * turbosparc.h:  Defines specific to the TurboSparc module.
+ *            This is SRMMU stuff.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+#ifndef _SPARC_TURBOSPARC_H
+#define _SPARC_TURBOSPARC_H
+
+#include <asm/asi.h>
+#include <asm/pgtsrmmu.h>
+
+/* Bits in the SRMMU control register for TurboSparc modules.
+ *
+ * -------------------------------------------------------------------
+ * |impl-vers| RSV| PMC |PE|PC| RSV |BM| RFR |IC|DC|PSO|RSV|ICS|NF|ME|
+ * -------------------------------------------------------------------
+ *  31    24 23-21 20-19 18 17 16-15 14 13-10  9  8  7  6-3   2  1  0
+ *
+ * BM: Boot Mode -- 0 = not in boot mode, 1 = in boot mode
+ *
+ * This indicates whether the TurboSparc is in boot-mode or not.
+ *
+ * IC: Instruction Cache -- 0 = off, 1 = on
+ * DC: Data Cache -- 0 = off, 1 = 0n
+ *
+ * These bits enable the on-cpu TurboSparc split I/D caches.
+ *
+ * ICS: ICache Snooping -- 0 = disable, 1 = enable snooping of icache
+ * NF: No Fault -- 0 = faults generate traps, 1 = faults don't trap
+ * ME: MMU enable -- 0 = mmu not translating, 1 = mmu translating
+ *
+ */
+
+#define TURBOSPARC_MMUENABLE    0x00000001
+#define TURBOSPARC_NOFAULT      0x00000002
+#define TURBOSPARC_ICSNOOP     0x00000004
+#define TURBOSPARC_PSO          0x00000080
+#define TURBOSPARC_DCENABLE     0x00000100   /* Enable data cache */
+#define TURBOSPARC_ICENABLE     0x00000200   /* Enable instruction cache */
+#define TURBOSPARC_BMODE        0x00004000   
+#define TURBOSPARC_PARITYODD   0x00020000   /* Parity odd, if enabled */
+#define TURBOSPARC_PCENABLE    0x00040000   /* Enable parity checking */
+
+/* Bits in the CPU configuration register for TurboSparc modules.
+ *
+ * -------------------------------------------------------
+ * |IOClk|SNP|AXClk| RAH |  WS |  RSV  |SBC|WT|uS2|SE|SCC|
+ * -------------------------------------------------------
+ *    31   30 29-28 27-26 25-23   22-8  7-6  5  4   3 2-0
+ *
+ */
+
+#define TURBOSPARC_SCENABLE 0x00000008  /* Secondary cache enable */
+#define TURBOSPARC_uS2     0x00000010   /* Swift compatibility mode */
+#define TURBOSPARC_WTENABLE 0x00000020  /* Write thru for dcache */
+#define TURBOSPARC_SNENABLE 0x40000000  /* DVMA snoop enable */
+
+#ifndef __ASSEMBLY__
+
+/* Bits [13:5] select one of 512 instruction cache tags */
+extern __inline__ void turbosparc_inv_insn_tag(unsigned long addr)
+{
+        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                             "r" (addr), "i" (ASI_M_TXTC_TAG));
+}
+
+/* Bits [13:5] select one of 512 data cache tags */
+extern __inline__ void turbosparc_inv_data_tag(unsigned long addr)
+{
+        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                             "r" (addr), "i" (ASI_M_DATAC_TAG));
+}
+
+extern __inline__ void turbosparc_flush_icache(void)
+{
+       __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+                            "i" (ASI_M_IC_FLCLEAR));
+}
+
+extern __inline__ void turbosparc_flush_dcache(void)
+{
+       unsigned long addr;
+
+        for(addr = 0; addr < 0x4000; addr += 0x20)
+                turbosparc_inv_data_tag(addr);
+}
+
+extern __inline__ void turbosparc_idflash_clear(void)
+{
+       turbosparc_flush_icache(); turbosparc_flush_dcache();
+}
+
+extern __inline__ void turbosparc_set_ccreg(unsigned long regval)
+{
+       __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+                            "r" (regval), "r" (0x600),
+                            "i" (ASI_M_MMUREGS));
+}
+
+extern __inline__ unsigned long turbosparc_get_ccreg(void)
+{
+       unsigned long regval;
+
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (regval) :
+                            "r" (0x600),
+                            "i" (ASI_M_MMUREGS));
+       return regval;
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* !(_SPARC_TURBOSPARC_H) */
index e1fa6f88afd49f2bd125fd80fc1e4f602e48c12d..18cf7c54158265380ee43c353d7d1901301effbd 100644 (file)
 #define AOFF_task_ldt  0x00000370
 #define ASIZ_task_ldt  0x00000008
 #define AOFF_task_tss  0x00000380
-#define ASIZ_task_tss  0x00000600
-#define AOFF_task_fs   0x00000980
+#define ASIZ_task_tss  0x000004c0
+#define AOFF_task_fs   0x00000840
 #define ASIZ_task_fs   0x00000008
-#define AOFF_task_files        0x00000988
+#define AOFF_task_files        0x00000848
 #define ASIZ_task_files        0x00000008
-#define AOFF_task_mm   0x00000990
+#define AOFF_task_mm   0x00000850
 #define ASIZ_task_mm   0x00000008
-#define AOFF_task_sig  0x00000998
+#define AOFF_task_sig  0x00000858
 #define ASIZ_task_sig  0x00000008
-#define AOFF_task_has_cpu      0x000009a0
+#define AOFF_task_has_cpu      0x00000860
 #define ASIZ_task_has_cpu      0x00000004
-#define AOFF_task_processor    0x000009a4
+#define AOFF_task_processor    0x00000864
 #define ASIZ_task_processor    0x00000004
-#define AOFF_task_last_processor       0x000009a8
+#define AOFF_task_last_processor       0x00000868
 #define ASIZ_task_last_processor       0x00000004
-#define AOFF_task_lock_depth   0x000009ac
+#define AOFF_task_lock_depth   0x0000086c
 #define ASIZ_task_lock_depth   0x00000004
-#define AOFF_task_sigmask_lock 0x000009b0
+#define AOFF_task_sigmask_lock 0x00000870
 #define ASIZ_task_sigmask_lock 0x00000000
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000008
 #define ASIZ_mm_def_flags      0x00000008
 #define AOFF_mm_cpu_vm_mask    0x000000b8
 #define ASIZ_mm_cpu_vm_mask    0x00000008
-#define AOFF_thread_float_regs 0x00000000
-#define ASIZ_thread_float_regs 0x00000100
-#define AOFF_thread_fsr        0x00000100
-#define ASIZ_thread_fsr        0x00000008
-#define AOFF_thread_ksp        0x00000108
+#define AOFF_thread_ksp        0x00000000
 #define ASIZ_thread_ksp        0x00000008
-#define AOFF_thread_kpc        0x00000110
+#define AOFF_thread_kpc        0x00000008
 #define ASIZ_thread_kpc        0x00000008
-#define AOFF_thread_wstate     0x00000118
+#define AOFF_thread_wstate     0x00000010
 #define ASIZ_thread_wstate     0x00000008
-#define AOFF_thread_cwp        0x00000120
-#define ASIZ_thread_cwp        0x00000008
-#define AOFF_thread_ctx        0x00000128
-#define ASIZ_thread_ctx        0x00000008
-#define AOFF_thread_reg_window 0x00000130
+#define AOFF_thread_cwp        0x00000018
+#define ASIZ_thread_cwp        0x00000004
+#define AOFF_thread_ctx        0x0000001c
+#define ASIZ_thread_ctx        0x00000004
+#define AOFF_thread_flags      0x00000020
+#define ASIZ_thread_flags      0x00000004
+#define AOFF_thread_new_signal 0x00000024
+#define ASIZ_thread_new_signal 0x00000004
+#define AOFF_thread_current_ds 0x00000028
+#define ASIZ_thread_current_ds 0x00000008
+#define AOFF_thread_w_saved    0x00000030
+#define ASIZ_thread_w_saved    0x00000008
+#define AOFF_thread_kregs      0x00000038
+#define ASIZ_thread_kregs      0x00000008
+#define AOFF_thread_reg_window 0x00000040
 #define ASIZ_thread_reg_window 0x00000400
-#define AOFF_thread_rwbuf_stkptrs      0x00000530
+#define AOFF_thread_rwbuf_stkptrs      0x00000440
 #define ASIZ_thread_rwbuf_stkptrs      0x00000040
-#define AOFF_thread_w_saved    0x00000570
-#define ASIZ_thread_w_saved    0x00000008
-#define AOFF_thread_flags      0x00000578
-#define ASIZ_thread_flags      0x00000008
-#define AOFF_thread_sig_address        0x00000580
+#define AOFF_thread_sig_address        0x00000480
 #define ASIZ_thread_sig_address        0x00000008
-#define AOFF_thread_sig_desc   0x00000588
+#define AOFF_thread_sig_desc   0x00000488
 #define ASIZ_thread_sig_desc   0x00000008
-#define AOFF_thread_sstk_info  0x00000590
+#define AOFF_thread_sstk_info  0x00000490
 #define ASIZ_thread_sstk_info  0x00000010
-#define AOFF_thread_current_ds 0x000005a0
-#define ASIZ_thread_current_ds 0x00000008
-#define AOFF_thread_new_signal 0x000005a8
-#define ASIZ_thread_new_signal 0x00000008
-#define AOFF_thread_kregs      0x000005b0
-#define ASIZ_thread_kregs      0x00000008
-#define AOFF_thread_core_exec  0x000005b8
+#define AOFF_thread_core_exec  0x000004a0
 #define ASIZ_thread_core_exec  0x00000020
 
 #endif /* __ASM_OFFSETS_H__ */
index ec496fa17db5a702549a71a137e80388dc439a1e..12baf0222d97c6bc5d47a87d5a2f0debf606bd31 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: atomic.h,v 1.14 1997/04/16 05:57:06 davem Exp $
+/* $Id: atomic.h,v 1.15 1997/07/03 09:18:09 davem Exp $
  * atomic.h: Thankfully the V9 is at least reasonable for this
  *           stuff.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #ifndef __ARCH_SPARC64_ATOMIC__
@@ -22,73 +22,63 @@ typedef struct { int counter; } atomic_t;
 
 extern __inline__ void atomic_add(int i, atomic_t *v)
 {
-       unsigned long temp0, temp1;
        __asm__ __volatile__("
-       lduw            [%3], %0
-1:
-       add             %0, %2, %1
-       cas             [%3], %0, %1
-       cmp             %0, %1
-       bne,a,pn        %%icc, 1b
-        lduw           [%3], %0
-2:
-"      : "=&r" (temp0), "=&r" (temp1)
+1:     lduw            [%1], %%g1
+       add             %%g1, %0, %%g2
+       cas             [%1], %%g1, %%g2
+       sub             %%g1, %%g2, %%g1
+       brnz,pn         %%g1, 1b
+        nop"
+       : /* No outputs */
        : "HIr" (i), "r" (__atomic_fool_gcc(v))
-       : "cc");
+       : "g1", "g2");
 }
 
 extern __inline__ void atomic_sub(int i, atomic_t *v)
 {
-       unsigned long temp0, temp1;
        __asm__ __volatile__("
-       lduw            [%3], %0
-1:
-       sub             %0, %2, %1
-       cas             [%3], %0, %1
-       cmp             %0, %1
-       bne,a,pn        %%icc, 1b
-        lduw           [%3], %0
-2:
-"      : "=&r" (temp0), "=&r" (temp1)
+1:     lduw            [%1], %%g1
+       sub             %%g1, %0, %%g2
+       cas             [%1], %%g1, %%g2
+       sub             %%g1, %%g2, %%g1
+       brnz,pn         %%g1, 1b
+        nop"
+       : /* No outputs */
        : "HIr" (i), "r" (__atomic_fool_gcc(v))
-       : "cc");
+       : "g1", "g2");
 }
 
 /* Same as above, but return the result value. */
 extern __inline__ int atomic_add_return(int i, atomic_t *v)
 {
-       unsigned long temp0, oldval;
+       unsigned long oldval;
        __asm__ __volatile__("
-       lduw            [%3], %0
-1:
-       add             %0, %2, %1
-       cas             [%3], %0, %1
-       cmp             %0, %1
-       bne,a,pn        %%icc, 1b
-        lduw           [%3], %0
-2:
-"      : "=&r" (temp0), "=&r" (oldval)
+1:     lduw            [%2], %%g1
+       add             %%g1, %1, %%g2
+       cas             [%2], %%g1, %%g2
+       sub             %%g1, %%g2, %%g1
+       brnz,pn         %%g1, 1b
+        add            %%g2, %1, %0"
+       : "=&r" (oldval)
        : "HIr" (i), "r" (__atomic_fool_gcc(v))
-       : "cc");
-       return (((int)oldval) + 1);
+       : "g1", "g2");
+       return (int)oldval;
 }
 
 extern __inline__ int atomic_sub_return(int i, atomic_t *v)
 {
-       unsigned long temp0, oldval;
+       unsigned long oldval;
        __asm__ __volatile__("
-       lduw            [%3], %0
-1:
-       sub             %0, %2, %1
-       cas             [%3], %0, %1
-       cmp             %0, %1
-       bne,a,pn        %%icc, 1b
-        lduw           [%3], %0
-2:
-"      : "=&r" (temp0), "=&r" (oldval)
+1:     lduw            [%2], %%g1
+       sub             %%g1, %1, %%g2
+       cas             [%2], %%g1, %%g2
+       sub             %%g1, %%g2, %%g1
+       brnz,pn         %%g1, 1b
+        sub            %%g2, %1, %0"
+       : "=&r" (oldval)
        : "HIr" (i), "r" (__atomic_fool_gcc(v))
-       : "cc");
-       return (((int)oldval) - 1);
+       : "g1", "g2");
+       return (int)oldval;
 }
 
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
index f71f7e0e5c9a38167fd93cba44d071fe2cff6e2e..dabc83297a9433aa33afbee9c5eb1d795f16cda2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.17 1997/06/14 17:35:05 davem Exp $
+/* $Id: bitops.h,v 1.18 1997/06/30 12:36:18 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -121,7 +121,7 @@ extern __inline__ unsigned long ffz(unsigned long word)
          : "0" (word)
          : "g1", "g2");
 #else
-#ifdef EASY_CHEESE_VERSION
+#if 1 /* def EASY_CHEESE_VERSION */
        result = 0;
        while(word & 1) {
                result++;
@@ -177,13 +177,11 @@ extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long siz
                size -= 64;
                result += 64;
        }
-       offset = size >> 6;
-       size &= 63UL;
-       while (offset) {
+       while (size & ~63UL) {
                if (~(tmp = *(p++)))
                        goto found_middle;
                result += 64;
-               offset--;
+               size -= 64;
        }
        if (!size)
                return result;
@@ -289,13 +287,11 @@ extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long
                size -= 64;
                result += 64;
        }
-       offset = size >> 6;
-       size &= 63UL;
-       while(offset) {
+       while(size & ~63) {
                if(~(tmp = __swab64p(p++)))
                        goto found_middle;
                result += 64;
-               offset--;
+               size -= 64;
        }
        if(!size)
                return result;
index d04abac7e43548e8b08ff0ae23e3f11e1a6aee92..b1ff474c32b00196c59adf1ee42e1dedc9536da6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.8 1997/05/29 12:45:03 jj Exp $ */
+/* $Id: checksum.h,v 1.9 1997/06/26 04:05:17 davem Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -108,31 +108,30 @@ extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
         *       both operands.
         */
        __asm__ __volatile__("
-       sub             %2, 4, %%g7
-       lduw            [%1 + 0x00], %0
-       lduw            [%1 + 0x04], %%g2
-       lduw            [%1 + 0x08], %%g3
-       addcc           %%g2, %0, %0
-       addccc          %%g3, %0, %0
-       lduw            [%1 + 0x0c], %%g2
-       lduw            [%1 + 0x10], %%g3
-       addccc          %%g2, %0, %0
-       addc            %0, %%g0, %0
-1:
-       addcc           %%g3, %0, %0
-       add             %1, 4, %1
-       addccc          %0, %%g0, %0
-       subcc           %%g7, 1, %%g7
-       be,a,pt         %%icc, 2f
-        sll            %0, 16, %%g2
-       ba,pt           %%xcc, 1b
-        lduw           [%1 + 0x10], %%g3
-2:
-       addcc           %0, %%g2, %%g2
-       srl             %%g2, 16, %0
-       addc            %0, %%g0, %0
-       xnor            %%g0, %0, %0
-       srl             %0, 0, %0
+       sub             %2, 4, %%g7             ! IEU0
+       lduw            [%1 + 0x00], %0         ! Load  Group
+       lduw            [%1 + 0x04], %%g2       ! Load  Group
+       lduw            [%1 + 0x08], %%g3       ! Load  Group
+       addcc           %%g2, %0, %0            ! IEU1  1 Load Bubble + Group
+       lduw            [%1 + 0x0c], %%g2       ! Load
+       addccc          %%g3, %0, %0            ! Sngle Group no Bubble
+       lduw            [%1 + 0x10], %%g3       ! Load  Group
+       addccc          %%g2, %0, %0            ! Sngle Group no Bubble
+       addc            %0, %%g0, %0            ! Sngle Group
+1:     addcc           %%g3, %0, %0            ! IEU1  Group no Bubble
+       add             %1, 4, %1               ! IEU0
+       addccc          %0, %%g0, %0            ! Sngle Group no Bubble
+       subcc           %%g7, 1, %%g7           ! IEU1  Group
+       be,a,pt         %%icc, 2f               ! CTI
+        sll            %0, 16, %%g2            ! IEU0
+       lduw            [%1 + 0x10], %%g3       ! Load  Group
+       ba,pt           %%xcc, 1b               ! CTI
+        nop                                    ! IEU0
+2:     addcc           %0, %%g2, %%g2          ! IEU1  Group
+       srl             %%g2, 16, %0            ! IEU0  Group regdep    XXX Scheisse!
+       addc            %0, %%g0, %0            ! Sngle Group
+       xnor            %%g0, %0, %0            ! IEU0  Group
+       srl             %0, 0, %0               ! IEU0  Group           XXX Scheisse!
 "      : "=r" (sum), "=&r" (iph)
        : "r" (ihl), "1" (iph)
        : "g2", "g3", "g7", "cc");
index 7923b50143be5674cdb411074b6a256c87feb566..f70d99b685c1cfc541ef4bd0d4ca03fed12d0489 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.4 1997/04/10 23:32:44 davem Exp $
+/* $Id: delay.h,v 1.5 1997/06/18 12:36:23 jj Exp $
  * delay.h: Linux delay routines on the V9.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu).
@@ -12,7 +12,9 @@ extern unsigned long loops_per_sec;
 extern __inline__ void __delay(unsigned long loops)
 {
        __asm__ __volatile__("
-       cmp     %0, 0
+       b,pt    %%xcc, 1f
+        cmp    %0, 0
+       .align  32
 1:
        bne,pt  %%xcc, 1b
         subcc  %0, 1, %0
index f6323254d259e5223ab04896e3e095c8c63457c0..dab13447254f4db5e09f946b5bfebe2d96fa588d 100644 (file)
@@ -21,68 +21,44 @@ extern __inline__ void fprs_write(unsigned long val)
        __asm__ __volatile__("wr %0, 0x0, %%fprs" : : "r" (val));
 }
 
-extern __inline__ void fpsave32(unsigned int *fpregs, unsigned long *fsr)
+extern __inline__ void fpsave(unsigned long *fpregs,
+                             unsigned long *fsr,
+                             unsigned long *gsr)
 {
        __asm__ __volatile__ ("
-       wr      %%g0, %2, %%asi
-       stx     %%fsr, [%1]
-       stda    %%f0, [%0] %%asi
-       stda    %%f16, [%0 + 64] %%asi
-       " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
-}
-
-extern __inline__ void fpload32(unsigned int *fpregs, unsigned long *fsr)
-{
-       __asm__ __volatile__ ("
-       wr      %%g0, %2, %%asi
-       ldda    [%0] %%asi, %%f0
-       ldda    [%0 + 64] %%asi, %%f16
-       ldx     [%1], %%fsr
-       " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
-}
-
-extern __inline__ void fpsave64hi(unsigned int *fpregs, unsigned long *fsr)
-{
-       __asm__ __volatile__ ("
-       wr      %%g0, %2, %%asi
-       stx     %%fsr, [%1]
-       stda    %%f32, [%0 + 128] %%asi
-       stda    %%f48, [%0 + 192] %%asi
-       " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
-}
-
-extern __inline__ void fpload64hi(unsigned int *fpregs, unsigned long *fsr)
-{
-       __asm__ __volatile__ ("
-       wr      %%g0, %2, %%asi
-       ldda    [%0 + 128] %%asi, %%f32
-       ldda    [%0 + 192] %%asi, %%f48
-       ldx     [%1], %%fsr
-       " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
-}
-
-extern __inline__ void fpsave(unsigned int *fpregs, unsigned long *fsr)
-{
-       __asm__ __volatile__ ("
-       wr      %%g0, %2, %%asi
+       wr      %%g0, %3, %%asi
+       rd      %%gsr, %%g1
+       membar  #LoadStore | #StoreStore
        stx     %%fsr, [%1]
+       stx     %%g1, [%2]
        stda    %%f0, [%0] %%asi
        stda    %%f16, [%0 + 64] %%asi
        stda    %%f32, [%0 + 128] %%asi
        stda    %%f48, [%0 + 192] %%asi
-       " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+       membar  #Sync
+"      : /* No outputs */
+       : "r" (fpregs), "r" (fsr), "r" (gsr), "i" (ASI_BLK_P)
+       : "g1");
 }
 
-extern __inline__ void fpload(unsigned int *fpregs, unsigned long *fsr)
+extern __inline__ void fpload(unsigned long *fpregs,
+                             unsigned long *fsr,
+                             unsigned long *gsr)
 {
        __asm__ __volatile__ ("
-       wr      %%g0, %2, %%asi
+       wr      %%g0, %3, %%asi
+       membar  #StoreLoad | #LoadLoad
        ldda    [%0] %%asi, %%f0
        ldda    [%0 + 64] %%asi, %%f16
        ldda    [%0 + 128] %%asi, %%f32
        ldda    [%0 + 192] %%asi, %%f48
        ldx     [%1], %%fsr
-       " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+       ldx     [%2], %%g1
+       wr      %%g1, 0, %%gsr
+       membar  #Sync
+"      : /* No outputs */
+       : "r" (fpregs), "r" (fsr), "r" (gsr), "i" (ASI_BLK_P)
+       : "g1");
 }
 
 #endif /* !(_SPARC64_FPUMACRO_H) */
index 7c6be4849643e9ad4c20143df081077f48ada585..73c4e1acf346e6911865363e26793150e684fff4 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: head.h,v 1.23 1997/06/14 13:25:50 davem Exp $ */
+/* $Id: head.h,v 1.26 1997/07/07 03:05:23 davem Exp $ */
 #ifndef _SPARC64_HEAD_H
 #define _SPARC64_HEAD_H
 
 #include <asm/pstate.h>
 
-#define KERNBASE    0xFFFFF80000000000
+#define KERNBASE    0x400000
 #define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
 
 /* We need a "cleaned" instruction... */
        nop;                                            \
        nop;
        
-/* Just for testing */
-#define PROM_TRAP                                      \
-       rd      %pc, %g1;                               \
-       sethi   %uhi(KERNBASE), %g4;                    \
-       sethi   %hi(0xf0000000-0x8000), %g2;            \
-       sllx    %g4, 32, %g4;                           \
-       add     %g1, %g2, %g1;                          \
-       sub     %g1, %g4, %g1;                          \
-       jmpl    %g1 + %g0, %g0;                         \
-       nop;
-
 #define TRAP_ARG(routine, arg)                         \
        ba,pt   %xcc, etrap;                            \
         rd     %pc, %g7;                               \
 #define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
 #define        LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
 #define LINUX_64BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table64)
+#define GETCC_TRAP TRAP(getcc)
+#define SETCC_TRAP TRAP(setcc)
 /* FIXME: Write these actually */      
 #define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
 #define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
 #define BREAKPOINT_TRAP TRAP(breakpoint_trap)
-#define GETCC_TRAP TRAP(getcc)
-#define SETCC_TRAP TRAP(setcc)
 #define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
 
 #define TRAP_IRQ(routine, level)                       \
index c0348eef1c52b9f329c67001cf7b0d242ea33a15..1d6c1cace33c861625e8eabd7ace796e66665446 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioctls.h,v 1.3 1997/06/14 17:35:08 davem Exp $ */
+/* $Id: ioctls.h,v 1.4 1997/06/23 07:26:03 davem Exp $ */
 #ifndef _ASM_SPARC64_IOCTLS_H
 #define _ASM_SPARC64_IOCTLS_H
 
@@ -64,8 +64,8 @@
 /* 119 is the non-posix getpgrp tty ioctl */
 #define __TIOCCDTR        _IO('t', 120) /* SunOS Specific */
 #define __TIOCSDTR        _IO('t', 121) /* SunOS Specific */
-#define __TIOCCBRK        _IO('t', 122) /* SunOS Specific */
-#define __TIOCSBRK        _IO('t', 123) /* SunOS Specific */
+#define TIOCCBRK        _IO('t', 122)
+#define TIOCSBRK        _IO('t', 123)
 #define __TIOCLGET        _IOW('t', 124, int) /* SunOS Specific */
 #define __TIOCLSET        _IOW('t', 125, int) /* SunOS Specific */
 #define __TIOCLBIC        _IOW('t', 126, int) /* SunOS Specific */
index 008f68bc1edc14514b69cb89caf57b985e863a8d..1c2a92c4b8dca53184fd3d2932dc915a373bab08 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.11 1997/06/13 14:03:04 davem Exp $ */
+/* $Id: mmu_context.h,v 1.16 1997/07/05 09:54:46 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -24,34 +24,7 @@ extern unsigned long tlb_context_cache;
 #define CTX_VERSION_MASK       ((~0UL) << CTX_VERSION_SHIFT)
 #define CTX_FIRST_VERSION      ((1UL << CTX_VERSION_SHIFT) + 1UL)
 
-extern __inline__ void get_new_mmu_context(struct mm_struct *mm,
-                                          unsigned long ctx)
-{
-       if((ctx & ~(CTX_VERSION_MASK)) == 0) {
-               unsigned long flags;
-               int entry;
-
-               save_and_cli(flags);
-               __asm__ __volatile__("stxa      %%g0, [%0] %1\n\t"
-                                    "stxa      %%g0, [%0] %2"
-                                    : /* No outputs */
-                                    : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU),
-                                      "i" (ASI_DMMU));
-               for(entry = 0; entry < 62; entry++) {
-                       spitfire_put_dtlb_data(entry, 0x0UL);
-                       spitfire_put_itlb_data(entry, 0x0UL);
-               }
-               membar("#Sync");
-               __asm__ __volatile__("flush %g4");
-               restore_flags(flags);
-
-               ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
-               if(ctx == 1) /* _not_ zero! */
-                       ctx = CTX_FIRST_VERSION;
-       }
-       tlb_context_cache = ctx + 1;
-       mm->context = ctx;
-}
+extern void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx);
 
 extern __inline__ void get_mmu_context(struct task_struct *tsk)
 {
@@ -71,7 +44,7 @@ extern __inline__ void get_mmu_context(struct task_struct *tsk)
        } else
                tsk->tss.ctx = 0;
        spitfire_set_secondary_context(tsk->tss.ctx);
-       __asm__ __volatile__("flush %g4");
+       __asm__ __volatile__("flush %g6");
        paddr = __pa(mm->pgd);
        __asm__ __volatile__("
                rdpr            %%pstate, %%o4
index 17a6ff611ed9d041209586ec63721f4e985ba395..d39d3d4942de6e684a3f9b044d2aa7b81ade472e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.9 1997/06/14 21:28:09 davem Exp $ */
+/* $Id: page.h,v 1.14 1997/06/26 22:32:03 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
 
 #ifndef __ASSEMBLY__
 
-#define clear_page(page)                                       \
-       __asm__ __volatile__(   "mov    %%o7, %%g3\n\t"         \
-                               "call   __bzero_1page\n\t"      \
-                               " mov   %0, %%g2\n\t"           \
-                               : /* No outputs */              \
-                               : "r" (page)                    \
-                               : "g1", "g2", "g3")
+#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
 
-#define copy_page(to,from)     memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+extern void copy_page(unsigned long to, unsigned long from);
 
-#define STRICT_MM_TYPECHECKS
+/* GROSS, defining this makes gcc pass these types as aggregates,
+ * and thus on the stack, turn this crap off... -DaveM
+ */
+
+/* #define STRICT_MM_TYPECHECKS */
 
 #ifdef STRICT_MM_TYPECHECKS
 /* These are used to make use of C type-checking.. */
@@ -96,7 +94,9 @@ typedef unsigned long iopgprot_t;
 #define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 #ifndef __ASSEMBLY__
-#define PAGE_OFFSET            0xFFFFF80000000000UL
+/* Do prdele, look what happens to be in %g4... */
+register unsigned long page_offset asm("g4");
+#define PAGE_OFFSET            page_offset
 #else
 #define PAGE_OFFSET            0xFFFFF80000000000
 #endif
index 772121a2643775b1aaa663498427a489107494a1..5cbd9a3c54e85bbdcae109732277dcd3369471be 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.37 1997/06/13 14:03:06 davem Exp $
+/* $Id: pgtable.h,v 1.49 1997/06/30 09:24:12 jj Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -51,7 +51,7 @@
 #define PTRS_PER_PAGE  (1UL << (PAGE_SHIFT-3))
 
 /* NOTE: TLB miss handlers depend heavily upon where this is. */
-#define VMALLOC_START          0xFFFFFc0000000000UL
+#define VMALLOC_START          0x0000000800000000UL
 #define VMALLOC_VMADDR(x)      ((unsigned long)(x))
 
 #endif /* !(__ASSEMBLY__) */
 #define _PAGE_G                0x0000000000000001      /* Global                             */
 
 /* Here are the SpitFire software bits we use in the TTE's. */
-#define _PAGE_PRESENT  0x0000000000001000      /* Present Page (ie. not swapped out) */
 #define _PAGE_MODIFIED 0x0000000000000800      /* Modified Page (ie. dirty)          */
 #define _PAGE_ACCESSED 0x0000000000000400      /* Accessed Page (ie. referenced)     */
 #define _PAGE_READ     0x0000000000000200      /* Readable SW Bit                    */
 #define _PAGE_WRITE    0x0000000000000100      /* Writable SW Bit                    */
+#define _PAGE_PRESENT  0x0000000000000080      /* Present Page (ie. not swapped out) */
 
 #define _PAGE_CACHE    (_PAGE_CP | _PAGE_CV)
 
@@ -146,8 +146,7 @@ extern pte_t *__bad_pte(void);
  * hit for all __pa()/__va() operations.
  */
 extern unsigned long phys_base;
-
-#define ZERO_PAGE      (PAGE_OFFSET + phys_base)
+#define ZERO_PAGE      ((unsigned long)__va(phys_base))
 
 /* This is for making TLB miss faster to process. */
 extern unsigned long null_pmd_table;
@@ -159,156 +158,47 @@ extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size);
 
 /* Cache and TLB flush operations. */
 
-extern __inline__ void flush_cache_all(void)
-{
-       unsigned long addr;
-
-       flushw_all();
-       for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
-               spitfire_put_icache_tag(addr, 0x0UL);
-}
-
-extern __inline__ void flush_cache_mm(struct mm_struct *mm)
-{
-       if(mm->context != NO_CONTEXT) {
-               unsigned long addr;
-
-               flushw_user();
-               for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
-                       spitfire_put_icache_tag(addr, 0x0UL);
-       }
-}
-
-extern __inline__ void flush_cache_range(struct mm_struct *mm, unsigned long start,
-                                        unsigned long end)
-{
-       if(mm->context != NO_CONTEXT) {
-               unsigned long addr;
+#define flush_cache_all()      \
+do {   unsigned long va;       \
+       flushw_all();           \
+       for(va = 0;             \
+           va<(PAGE_SIZE<<1);  \
+           va += 32)           \
+spitfire_put_icache_tag(va,0x0);\
+} while(0)
 
-               flushw_user();
-               for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
-                       spitfire_put_icache_tag(addr, 0x0UL);
-       }
-}
-
-extern __inline__ void flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
-       struct mm_struct *mm = vma->vm_mm;
-
-       if(mm->context != NO_CONTEXT) {
-               unsigned long addr;
-
-               flushw_user();
-               for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
-                       spitfire_put_icache_tag(addr, 0x0UL);
-       }
-}
+#define flush_cache_mm(mm)                     do { } while(0)
+#define flush_cache_range(mm, start, end)      do { } while(0)
+#define flush_cache_page(vma, page)            do { } while(0)
 
 /* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
 #define flush_page_to_ram(page)                do { } while (0)
 
-extern __inline__ void flush_tlb_all(void)
-{
-       unsigned long flags;
-       int entry;
-
-       /* Invalidate all non-locked TTE's in both the dtlb and itlb. */
-       save_and_cli(flags);
-       __asm__ __volatile__("stxa      %%g0, [%0] %1\n\t"
-                            "stxa      %%g0, [%0] %2"
-                            : /* No outputs */
-                            : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU), "i" (ASI_DMMU));
-       for(entry = 0; entry < 62; entry++) {
-               spitfire_put_dtlb_data(entry, 0x0UL);
-               spitfire_put_itlb_data(entry, 0x0UL);
-       }
-       membar("#Sync");
-       flushi(PAGE_OFFSET);
-       restore_flags(flags);
-}
+extern void flush_tlb_all(void);
 
+extern void __flush_tlb_mm(unsigned long context);
 extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
 {
-       if(mm->context != NO_CONTEXT) {
-               __asm__ __volatile__("
-       /* flush_tlb_mm() */
-       rdpr            %%pil, %%g1
-       mov             %1, %%g7
-       wrpr            %%g0, 15, %%pil
-       ldxa            [%%g7] %2, %%g2
-       cmp             %%g2, %0
-       be,pt           %%icc, 1f
-        mov            0x50, %%g3
-       stxa            %0, [%%g7] %2
-1:
-       stxa            %%g0, [%%g3] %3
-       stxa            %%g0, [%%g3] %4
-       be,pt           %%icc, 1f
-        nop
-       stxa            %%g2, [%%g7] %2
-1:
-       flush           %%g4
-       wrpr            %%g1, 0x0, %%pil
-"      : /* no outputs */
-       : "r" (mm->context & 0x1fff), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
-         "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP)
-       : "g1", "g2", "g3", "g7", "cc");
-       }
+       if(mm->context != NO_CONTEXT)
+               __flush_tlb_mm(mm->context & 0x1fff);
 }
 
+extern void __flush_tlb_range(unsigned long context, unsigned long start,
+                             unsigned long end);
 extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
                                       unsigned long end)
 {
-       if(mm->context != NO_CONTEXT) {
-               unsigned long old_ctx = spitfire_get_secondary_context();
-               unsigned long new_ctx = (mm->context & 0x1fff);
-               unsigned long flags;
-
-               start &= PAGE_MASK;
-               save_and_cli(flags);
-               if(new_ctx != old_ctx)
-                       spitfire_set_secondary_context(new_ctx);
-               while(start < end) {
-                       spitfire_flush_dtlb_secondary_page(start);
-                       spitfire_flush_itlb_secondary_page(start);
-                       start += PAGE_SIZE;
-               }
-               if(new_ctx != old_ctx)
-                       spitfire_set_secondary_context(old_ctx);
-               __asm__ __volatile__("flush %g4");
-               restore_flags(flags);
-       }
+       if(mm->context != NO_CONTEXT)
+               __flush_tlb_range(mm->context & 0x1fff, start, end);
 }
 
+extern void __flush_tlb_page(unsigned long context, unsigned long page);
 extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
        struct mm_struct *mm = vma->vm_mm;
 
-       if(mm->context != NO_CONTEXT) {
-       __asm__ __volatile__("
-       /* flush_tlb_page() */
-       rdpr            %%pil, %%g1
-       mov             %1, %%g7
-       wrpr            %%g0, 15, %%pil
-       ldxa            [%%g7] %2, %%g2
-       cmp             %%g2, %0
-       be,pt           %%icc, 1f
-        or             %5, 0x10, %%g3
-       stxa            %0, [%%g7] %2
-1:
-       stxa            %%g0, [%%g3] %3
-       stxa            %%g0, [%%g3] %4
-       be,pt           %%icc, 1f
-        nop
-       stxa            %%g2, [%%g7] %2
-1:
-       flush           %%g4
-       wrpr            %%g1, 0x0, %%pil
-"      : /* no outputs */
-       : "r" (mm->context & 0x1fff), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
-         "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP), "r" (page & PAGE_MASK)
-       : "g1", "g2", "g3", "g7", "cc");
-       }
+       if(mm->context != NO_CONTEXT)
+               __flush_tlb_page(mm->context & 0x1fff, page & PAGE_MASK);
 }
 
 extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
@@ -393,24 +283,6 @@ extern inline pte_t pte_mkyoung(pte_t pte)
                return __pte(pte_val(pte) | (_PAGE_ACCESSED));
 }
 
-extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir)
-{
-       register unsigned long paddr asm("o5");
-
-       paddr = __pa(pgdir);
-
-       if(tsk == current) {
-               __asm__ __volatile__ ("
-                       rdpr            %%pstate, %%o4
-                       wrpr            %%o4, %1, %%pstate
-                       mov             %0, %%g7
-                       wrpr            %%o4, 0x0, %%pstate
-               " : /* No outputs */
-                 : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE)
-                 : "o4");
-       }
-}
-
 /* to find an entry in a page-table-directory. */
 extern inline pgd_t *pgd_offset(struct mm_struct *mm, unsigned long address)
 { return mm->pgd + ((address >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1)); }
@@ -428,11 +300,16 @@ extern inline pte_t *pte_offset(pmd_t *dir, unsigned long address)
 
 extern __inline__ void __init_pmd(pmd_t *pmdp)
 {
-       extern void __bfill64(void *, unsigned long);
+       extern void __bfill64(void *, unsigned long *);
        
-       __bfill64((void *)pmdp, null_pte_table);
+       __bfill64((void *)pmdp, &null_pte_table);
 }
 
+/* Turning this off makes things much faster, but eliminates some
+ * sanity checking as well.
+ */
+/* #define PGTABLE_SANITY_CHECKS */
+
 /* Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on supervisor
  * bits if any.
@@ -455,11 +332,13 @@ extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
                }
                free_page((unsigned long) page);
        }
+#ifdef PGTABLE_SANITY_CHECKS
        if (pmd_bad(*pmd)) {
                printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
                pmd_set(pmd, BAD_PTE);
                return NULL;
        }
+#endif
        return (pte_t *) pmd_page(*pmd) + address;
 }
 
@@ -482,11 +361,13 @@ extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
                }
                free_page((unsigned long) page);
        }
+#ifdef PGTABLE_SANITY_CHECKS
        if (pgd_bad(*pgd)) {
                printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
                pgd_set(pgd, BAD_PMD);
                return NULL;
        }
+#endif
        return (pmd_t *) pgd_page(*pgd) + address;
 }
 
@@ -508,11 +389,13 @@ extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
                }
                free_page((unsigned long) page);
        }
+#ifdef PGTABLE_SANITY_CHECKS
        if (pmd_bad(*pmd)) {
                printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
                pmd_set(pmd, BAD_PTE);
                return NULL;
        }
+#endif
        return (pte_t *) pmd_page(*pmd) + address;
 }
 
@@ -535,11 +418,13 @@ extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
                }
                free_page((unsigned long) page);
        }
+#ifdef PGTABLE_SANITY_CHECKS
        if (pgd_bad(*pgd)) {
                printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
                pgd_set(pgd, BAD_PMD);
                return NULL;
        }
+#endif
        return (pmd_t *) pgd_page(*pgd) + address;
 }
 
@@ -548,16 +433,33 @@ extern inline void pgd_free(pgd_t * pgd)
 
 extern inline pgd_t * pgd_alloc(void)
 {
-       extern void __bfill64(void *, unsigned long);
+       extern void __bfill64(void *, unsigned long *);
        pgd_t *pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
        
        if (pgd)
-               __bfill64((void *)pgd, null_pmd_table);
+               __bfill64((void *)pgd, &null_pmd_table);
        return pgd;
 }
 
 extern pgd_t swapper_pg_dir[1024];
 
+extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir)
+{
+       if(pgdir != swapper_pg_dir && tsk == current) {
+               register unsigned long paddr asm("o5");
+
+               paddr = __pa(pgdir);
+               __asm__ __volatile__ ("
+                       rdpr            %%pstate, %%o4
+                       wrpr            %%o4, %1, %%pstate
+                       mov             %0, %%g7
+                       wrpr            %%o4, 0x0, %%pstate
+               " : /* No outputs */
+                 : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE)
+                 : "o4");
+       }
+}
+
 /* Routines for getting a dvma scsi buffer. */
 struct mmu_sglist {
        char *addr;
@@ -575,61 +477,15 @@ extern void  mmu_get_scsi_sgl(struct mmu_sglist *, int, struct linux_sbus *sbus)
 #define mmu_lockarea(vaddr, len)               (vaddr)
 #define mmu_unlockarea(vaddr, len)             do { } while(0)
 
+extern void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address,
+                              pte_t pte);
+
 extern inline void update_mmu_cache(struct vm_area_struct * vma,
        unsigned long address, pte_t pte)
 {
        /* Find and fix bad virutal cache aliases. */
-       if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
-               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_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);
-               }
-       }
+       if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+               fixup_dcache_alias(vma, address, pte);
 }
 
 /* Make a non-present pseudo-TTE. */
@@ -649,7 +505,9 @@ sun4u_get_pte (unsigned long addr)
        pgd_t *pgdp;
        pmd_t *pmdp;
        pte_t *ptep;
-       
+
+       if (addr >= PAGE_OFFSET)
+               return addr & _PAGE_PADDR;
        pgdp = pgd_offset_k (addr);
        pmdp = pmd_offset (pgdp, addr);
        ptep = pte_offset (pmdp, addr);
@@ -668,6 +526,9 @@ __get_iospace (unsigned long addr)
        return ((sun4u_get_pte (addr) & 0xf0000000) >> 28);
 }
 
+extern void * module_map (unsigned long size);
+extern void module_unmap (void *addr);
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC64_PGTABLE_H) */
index 3cd62b8afd5e320310422f4bc1a2cfcf78af9628..019bbf6007232c11f017f3cbcd4ab773b1237d1a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.29 1997/06/16 04:45:05 davem Exp $
+/* $Id: processor.h,v 1.32 1997/07/01 21:59:38 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
 
 /* The Sparc processor specific thread struct. */
 struct thread_struct {
-       /* Floating point regs */
-       /* Please check asm_offsets, so that not to much precious space
-          is wasted by this alignment and move the float_regs wherever
-          is better in this structure. Remember every byte of alignment
-          is multiplied by 512 to get the amount of wasted kernel memory. */
-       unsigned int    float_regs[64] __attribute__ ((aligned (64)));
-       unsigned long   fsr;
-       
-       /* Context switch saved kernel state. */
-       unsigned long ksp, kpc, wstate, cwp, ctx;
+/*DC1*/        unsigned long ksp __attribute__ ((aligned(16)));
+       unsigned long kpc;
+/*DC2*/        unsigned long wstate;
+       unsigned int cwp;
+       unsigned int ctx;
+
+/*DC3*/        unsigned int flags;
+       unsigned int new_signal;
+       unsigned long current_ds;
+/*DC4*/        unsigned long w_saved;
+       struct pt_regs *kregs;
 
-       /* Storage for windows when user stack is bogus. */
        struct reg_window reg_window[NSWINS] __attribute__ ((aligned (16)));
        unsigned long rwbuf_stkptrs[NSWINS] __attribute__ ((aligned (8)));
-       unsigned long w_saved;
        
-       /* Arch-specific task state flags, see below. */
-       unsigned long flags;
-
-       /* For signal handling */
        unsigned long sig_address __attribute__ ((aligned (8)));
        unsigned long sig_desc;
-
        struct sigstack sstk_info;
-       unsigned long current_ds;
-       unsigned long new_signal;
-       
-       struct pt_regs *kregs;
-       
        struct exec core_exec;     /* just what it says. */
 };
 
@@ -75,30 +64,18 @@ struct thread_struct {
                    PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #define INIT_TSS  {                                                    \
-/* FPU regs */   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     \
-                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     \
-                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     \
-                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },  \
-/* FPU status */                                                       \
-   0,                                                                  \
 /* ksp, kpc, wstate, cwp, secctx */                                    \
    0,   0,   0,             0,   0,                                            \
+/* flags,              new_signal, current_ds, */                      \
+   SPARC_FLAG_KTHREAD, 0,          USER_DS,                            \
+/* w_saved, kregs, */                                                  \
+   0,       0,                                                         \
 /* reg_window */                                                       \
-{ { { 0, }, { 0, } }, },                                               \
+   { { { 0, }, { 0, } }, },                                            \
 /* rwbuf_stkptrs */                                                    \
-{ 0, 0, 0, 0, 0, 0, 0, 0, },                                           \
-/* w_saved */                                                          \
-   0,                                                                  \
-/* flags */                                                            \
-   SPARC_FLAG_KTHREAD,                                                 \
-/* sig_address, sig_desc */                                            \
-   0,           0,                                                     \
-/* ex,     sstk_info, current_ds, */                                   \
-   { 0, 0, }, USER_DS,                                                 \
-/* new_signal, kregs */                                                        \
-  0,           0,                                                      \
-/* core_exec */                                                                \
-{ 0, },                                                                        \
+   { 0, 0, 0, 0, 0, 0, 0, 0, },                                                \
+/* sig_address, sig_desc, sstk_info, core_exec */                      \
+   0,           0,        { 0, 0, }, { 0, },                           \
 }
 
 #ifndef __ASSEMBLY__
@@ -112,11 +89,12 @@ extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t)
 /* Do necessary setup to start up a newly executed thread. */
 #define start_thread(regs, pc, sp) \
 do { \
-       regs->tstate = (regs->tstate & (TSTATE_CWP)) | TSTATE_IE; \
+       regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_IE|TSTATE_PEF); \
        regs->tpc = ((pc & (~3)) - 4); \
        regs->tnpc = regs->tpc + 4; \
        regs->y = 0; \
        current->tss.flags &= ~SPARC_FLAG_32BIT; \
+       current->tss.wstate = (1 << 3); \
        __asm__ __volatile__( \
        "stx            %%g0, [%0 + %2 + 0x00]\n\t" \
        "stx            %%g0, [%0 + %2 + 0x08]\n\t" \
@@ -147,11 +125,12 @@ do { \
        pc &= 0x00000000ffffffffUL; \
        sp &= 0x00000000ffffffffUL; \
 \
-       regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_IE | TSTATE_AM); \
+       regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_IE|TSTATE_AM|TSTATE_PEF); \
        regs->tpc = ((pc & (~3)) - 4); \
        regs->tnpc = regs->tpc + 4; \
        regs->y = 0; \
        current->tss.flags |= SPARC_FLAG_32BIT; \
+       current->tss.wstate = (2 << 3); \
        zero = 0; \
        __asm__ __volatile__( \
        "stx            %%g0, [%0 + %2 + 0x00]\n\t" \
index b971514d6b599d872b3bef1cac55cfa4e48d9075..22e9da3d609116d9a7f432a16d20d6082b10ec14 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: psrcompat.h,v 1.3 1997/06/05 06:22:54 davem Exp $ */
+/* $Id: psrcompat.h,v 1.4 1997/06/20 11:54:39 davem Exp $ */
 #ifndef _SPARC64_PSRCOMPAT_H
 #define _SPARC64_PSRCOMPAT_H
 
 
 extern inline unsigned int tstate_to_psr(unsigned long tstate)
 {
-       unsigned int psr;
        unsigned long vers;
 
-       /* These fields are in the same place. */
-       psr  = (tstate & (TSTATE_CWP | TSTATE_PEF));
-
-       /* This is what the user would have always seen. */
-       psr |= PSR_S;
-
-       /* Slam in the 32-bit condition codes. */
-       psr |= ((tstate & TSTATE_ICC) >> 12);
-
-       /* This is completely arbitrary. */
        __asm__ __volatile__("rdpr      %%ver, %0" : "=r" (vers));
-       psr |= ((vers << 8) >> 32) & PSR_IMPL;
-       psr |= ((vers << 24) >> 36) & PSR_VERS;
-
-       return psr;
+       return ((tstate & TSTATE_CWP)                   |
+               PSR_S                                   |
+               ((tstate & TSTATE_ICC) >> 12)           |
+               (((vers << 8) >> 32) & PSR_IMPL)        |
+               (((vers << 24) >> 36) & PSR_VERS));
 }
 
 extern inline unsigned long psr_to_tstate_icc(unsigned int psr)
 {
-       unsigned long tstate;
-
-       tstate = ((unsigned long)(psr & PSR_ICC)) << 12;
-
-       return tstate;
+       return ((unsigned long)(psr & PSR_ICC)) << 12;
 }
 
 #endif /* !(_SPARC64_PSRCOMPAT_H) */
index 2233ee7f069bb0728cff60fe8f093796f58715ab..a1e1414d62d5491e309d9f0e00bd7c885d63d182 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pstate.h,v 1.4 1997/05/29 12:45:02 jj Exp $ */
+/* $Id: pstate.h,v 1.6 1997/06/25 07:39:45 jj Exp $ */
 #ifndef _SPARC64_PSTATE_H
 #define _SPARC64_PSTATE_H
 
@@ -14,6 +14,9 @@
 #define PSTATE_CLE     0x0000000000000200      /* Current Little Endian.       */
 #define PSTATE_TLE     0x0000000000000100      /* Trap Little Endian.          */
 #define PSTATE_MM      0x00000000000000c0      /* Memory Model.                */
+#define PSTATE_TSO     0x0000000000000000      /* MM: Total Store Order        */
+#define PSTATE_PSO     0x0000000000000040      /* MM: Partial Store Order      */
+#define PSTATE_RMO     0x0000000000000080      /* MM: Relaxed Memory Order     */
 #define PSTATE_RED     0x0000000000000020      /* Reset Error Debug State.     */
 #define PSTATE_PEF     0x0000000000000010      /* Floating Point Enable.       */
 #define PSTATE_AM      0x0000000000000008      /* Address Mask.                */
@@ -47,6 +50,9 @@
 #define TSTATE_CLE     0x0000000000020000      /* Current Little Endian.       */
 #define TSTATE_TLE     0x0000000000010000      /* Trap Little Endian.          */
 #define TSTATE_MM      0x000000000000c000      /* Memory Model.                */
+#define TSTATE_TSO     0x0000000000000000      /* MM: Total Store Order        */
+#define TSTATE_PSO     0x0000000000004000      /* MM: Partial Store Order      */
+#define TSTATE_RMO     0x0000000000008000      /* MM: Relaxed Memory Order     */
 #define TSTATE_RED     0x0000000000002000      /* Reset Error Debug State.     */
 #define TSTATE_PEF     0x0000000000001000      /* Floating Point Enable.       */
 #define TSTATE_AM      0x0000000000000800      /* Address Mask.                */
index 5da6f6dd179325a56d6f52b04e582ccaf43fbfb5..a4784d41e5126681b32649589f7a178e64ea7974 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ptrace.h,v 1.8 1997/05/27 19:30:27 jj Exp $ */
+/* $Id: ptrace.h,v 1.12 1997/06/24 16:30:35 davem Exp $ */
 #ifndef _SPARC64_PTRACE_H
 #define _SPARC64_PTRACE_H
 
@@ -15,7 +15,8 @@ struct pt_regs {
        unsigned long tstate;
        unsigned long tpc;
        unsigned long tnpc;
-       unsigned long y;
+       unsigned int y;
+       unsigned int fprs;
 };
 
 struct pt_regs32 {
@@ -137,6 +138,7 @@ extern void show_regs(struct pt_regs *);
 #define PT_V9_TPC    0x88
 #define PT_V9_TNPC   0x90
 #define PT_V9_Y      0x98
+#define PT_V9_FPRS   0x9c
 #define PT_TSTATE      PT_V9_TSTATE
 #define PT_TPC         PT_V9_TPC
 #define PT_TNPC                PT_V9_TNPC
@@ -265,6 +267,28 @@ extern void show_regs(struct pt_regs *);
 #define PTRACE_GETFPAREGS         20
 #define PTRACE_SETFPAREGS         21
 
+/* There are for debugging 64-bit processes, either from a 32 or 64 bit
+ * parent.  Thus their compliments are for debugging 32-bit processes only.
+ */
+
+#define PTRACE_GETREGS64         22
+#define PTRACE_SETREGS64         23
+/* PTRACE_SYSCALL is 24 */
+#define PTRACE_GETFPREGS64       25
+#define PTRACE_SETFPREGS64       26
+
 #define PTRACE_GETUCODE           29  /* stupid bsd-ism */
 
+/* These are for 32-bit processes debugging 64-bit ones.
+ * Here addr and addr2 are passed in %g2 and %g3 respectively.
+ */
+#define PTRACE_PEEKTEXT64         (30 + PTRACE_PEEKTEXT)
+#define PTRACE_POKETEXT64         (30 + PTRACE_POKETEXT)
+#define PTRACE_PEEKDATA64         (30 + PTRACE_PEEKDATA)
+#define PTRACE_POKEDATA64         (30 + PTRACE_POKEDATA)
+#define PTRACE_READDATA64         (30 + PTRACE_READDATA)
+#define PTRACE_WRITEDATA64        (30 + PTRACE_WRITEDATA)
+#define PTRACE_READTEXT64         (30 + PTRACE_READTEXT)
+#define PTRACE_WRITETEXT64        (30 + PTRACE_WRITETEXT)
+
 #endif /* !(_SPARC64_PTRACE_H) */
index 716b8f8c6887276dda76f308294337876bb13810..ea3fc6e9c43d5190f33e1cabcf697492019fcbca 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: reg.h,v 1.1 1996/12/26 14:22:34 davem Exp $
+/* $Id: reg.h,v 1.2 1997/06/24 23:19:55 davem Exp $
  * linux/asm-sparc64/reg.h
  * Layout of the registers as expected by gdb on the Sparc
  * we should replace the user.h definitions with those in
@@ -76,4 +76,33 @@ struct fpu {
         struct fp_status f_fpstatus;
 };
 
+struct regs64 {
+        unsigned long r_g1; 
+        unsigned long r_g2;
+        unsigned long r_g3;
+        unsigned long r_g4;
+        unsigned long r_g5;
+        unsigned long r_g6;
+        unsigned long r_g7;
+        unsigned long r_o0;
+        unsigned long r_o1;
+        unsigned long r_o2;
+        unsigned long r_o3;
+        unsigned long r_o4;
+        unsigned long r_o5;
+        unsigned long r_o6;
+        unsigned long r_o7;
+        unsigned long tstate;
+        unsigned long tpc;
+        unsigned long tnpc;
+        unsigned int  y;
+        unsigned int  fprs;
+};
+
+struct fp_status64 {
+        unsigned long regs[32];
+        unsigned long fsr;
+};
+
+
 #endif /* __SPARC64_REG_H */
index 2e072c0c88090de60b6b66e2a99d1ef153285d7a..3fba2f834cce597194d151e5443ca22007b53498 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sigcontext.h,v 1.6 1997/06/16 00:29:25 richard Exp $ */
+/* $Id: sigcontext.h,v 1.8 1997/06/20 11:54:41 davem Exp $ */
 #ifndef __SPARC64_SIGCONTEXT_H
 #define __SPARC64_SIGCONTEXT_H
 
@@ -66,17 +66,6 @@ typedef struct {
        int                     si_mask;
 } __siginfo32_t;
 
-typedef struct {
-       unsigned int si_float_regs [32];
-       unsigned int si_fsr;
-       unsigned int si_fpqdepth;
-       struct {
-               unsigned int *insn_addr;
-               unsigned int insn;
-       } si_fpqueue [16];
-} __siginfo_fpu32_t;
-
-
 typedef struct {
        struct     pt_regs si_regs;
        int si_mask;
@@ -85,6 +74,7 @@ typedef struct {
 typedef struct {
        unsigned   int si_float_regs [64];
        unsigned   long si_fsr;
+       unsigned   long si_gsr;
        unsigned   int si_fpqdepth;
        struct {
                unsigned int *insn_addr;
index b420d80bb9f7861786236a9986bb788648a692d0..fd45c2e065543457015824f915169aae8b852571 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.5 1997/05/18 04:16:57 davem Exp $
+/* $Id: string.h,v 1.6 1997/06/24 17:29:14 jj Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
 
 #ifdef __KERNEL__
 
+#include <asm/asi.h>
+
 extern void __memmove(void *,const void *,__kernel_size_t);
 extern __kernel_size_t __memcpy(void *,const void *,__kernel_size_t);
+extern __kernel_size_t __memcpy_short(void *,const void *,__kernel_size_t,long,long);
+extern __kernel_size_t __memcpy_entry(void *,const void *,__kernel_size_t,long,long);
+extern __kernel_size_t __memcpy_16plus(void *,const void *,__kernel_size_t,long,long);
+extern __kernel_size_t __memcpy_384plus(void *,const void *,__kernel_size_t,long,long);
 extern __kernel_size_t __memset(void *,int,__kernel_size_t);
 
 #ifndef EXPORT_SYMTAB
@@ -35,32 +41,31 @@ extern __kernel_size_t __memset(void *,int,__kernel_size_t);
 
 extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
-       extern void __copy_1page(void *, const void *);
-
        if(n) {
                if(n <= 32) {
                        __builtin_memcpy(to, from, n);
+#if 0                  
+               } else if (n < 384) {
+                       __memcpy_16plus(to, from, n, ASI_BLK_P, ASI_BLK_P);
                } else {
-#if 0
-                       switch(n) {
-                       case 8192:
-                               __copy_1page(to, from);
-                               break;
-                       default:
-#endif
-                               __memcpy(to, from, n);
-#if 0
-                               break;
-                       }
-#endif
+                       __memcpy_384plus(to, from, n, ASI_BLK_P, ASI_BLK_P);
                }
+#else
+               } else {
+                       __memcpy(to, from, n);
+               }
+#endif         
        }
        return to;
 }
 
 extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
+#if 0
+       __memcpy_entry(to, from, n, ASI_BLK_P, ASI_BLK_P);
+#else
        __memcpy(to, from, n);
+#endif
        return to;
 }
 
@@ -74,15 +79,13 @@ extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_si
 
 extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count)
 {
-       extern void *bzero_1page(void *);
+       extern void *__bzero_1page(void *);
        extern __kernel_size_t __bzero(void *, __kernel_size_t);
 
        if(!c) {
-#if 0
-               if(count == 8192)
-                       bzero_1page(s);
+               if (count == 8192)
+                       __bzero_1page(s);
                else
-#endif
                        __bzero(s, count);
        } else {
                __memset(s, c, count);
index c428fdcd9c46709b7e80c212142ac6a295b29d50..6e7c42e55e346ba20cb25e81ae9a2731d7d1f436 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.23 1997/06/16 06:17:06 davem Exp $ */
+/* $Id: system.h,v 1.26 1997/06/28 10:04:03 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -95,45 +95,15 @@ extern __inline__ void flushw_user(void)
 {
        __asm__ __volatile__("
                rdpr            %%otherwin, %%g1
-               brz,pt          %%g1, 2f
+               brz,pt          %%g1, 1f
+                mov            %%o7, %%g3
+               call            __flushw_user
                 clr            %%g2
-1:
-               save            %%sp, %0, %%sp
-               rdpr            %%otherwin, %%g1
-               brnz,pt         %%g1, 1b
-                add            %%g2, 1, %%g2
-1:
-               subcc           %%g2, 1, %%g2
-               bne,pt          %%xcc, 1b
-                restore        %%g0, %%g0, %%g0
-2:
-       " : : "i" (-REGWIN_SZ)
-         : "g1", "g2", "cc");
+1:"    : : : "g1", "g2", "g3");
 }
 
 #define flush_user_windows flushw_user
 
-#ifdef __SMP__
-
-#include <asm/fpumacro.h>
-
-#define SWITCH_ENTER(prev)                                             \
-       if((prev)->flags & PF_USEDFPU) {                                \
-               fprs_write(FPRS_FEF);                                   \
-               fpsave((unsigned long *) &(prev)->tss.float_regs[0],    \
-                      &(prev)->tss.fsr);                               \
-               (prev)->flags &= ~PF_USEDFPU;                           \
-               (prev)->tss.kregs->tstate &= ~TSTATE_PEF;               \
-       }
-
-#define SWITCH_DO_LAZY_FPU(next)
-#else
-#define SWITCH_ENTER(prev)
-#define SWITCH_DO_LAZY_FPU(next)                       \
-       if(last_task_used_math != (next))               \
-               (next)->tss.kregs->tstate &= ~TSTATE_PEF
-#endif
-
        /* See what happens when you design the chip correctly?
         * NOTE NOTE NOTE this is extremely non-trivial what I
         * am doing here.  GCC needs only one register to stuff
@@ -146,13 +116,13 @@ extern __inline__ void flushw_user(void)
 do {                                                                                   \
        __label__ switch_continue;                                                      \
        register unsigned long task_pc asm("o7");                                       \
-       SWITCH_ENTER(prev)                                                              \
-       SWITCH_DO_LAZY_FPU(next);                                                       \
+       (prev)->tss.kregs->fprs = 0;                                                    \
        task_pc = ((unsigned long) &&switch_continue) - 0x8;                            \
        __asm__ __volatile__(                                                           \
        "rdpr   %%pstate, %%g2\n\t"                                                     \
-       "wrpr   %%g2, 0x2, %%pstate\n\t"                                                \
+       "wrpr   %%g2, 0x3, %%pstate\n\t"                                                \
        "flushw\n\t"                                                                    \
+/*XXX*/        "wr     %%g0, 0, %%fprs\n\t"                                                    \
        "stx    %%i6, [%%sp + 2047 + 0x70]\n\t"                                         \
        "stx    %%i7, [%%sp + 2047 + 0x78]\n\t"                                         \
        "rdpr   %%wstate, %%o5\n\t"                                                     \
@@ -160,19 +130,20 @@ do {                                                                                      \
        "stx    %%o5, [%%g6 + %2]\n\t"                                                  \
        "rdpr   %%cwp, %%o5\n\t"                                                        \
        "stx    %%o7, [%%g6 + %4]\n\t"                                                  \
-       "stx    %%o5, [%%g6 + %5]\n\t"                                                  \
+       "st     %%o5, [%%g6 + %5]\n\t"                                                  \
        "mov    %0, %%g6\n\t"                                                           \
-       "ldx    [%0 + %5], %%g1\n\t"                                                    \
-       "wr     %0, 0x0, %%pic\n\t"                                                     \
+       "ld     [%0 + %5], %%g1\n\t"                                                    \
        "wrpr   %%g1, %%cwp\n\t"                                                        \
        "ldx    [%%g6 + %2], %%o5\n\t"                                                  \
        "ldx    [%%g6 + %3], %%o6\n\t"                                                  \
        "ldx    [%%g6 + %4], %%o7\n\t"                                                  \
+       "mov    %%g6, %0\n\t"                                                           \
        "wrpr   %%o5, 0x0, %%wstate\n\t"                                                \
        "ldx    [%%sp + 2047 + 0x70], %%i6\n\t"                                         \
        "ldx    [%%sp + 2047 + 0x78], %%i7\n\t"                                         \
+       "wrpr   %%g0, 0x96, %%pstate\n\t"                                               \
        "jmpl   %%o7 + 0x8, %%g0\n\t"                                                   \
-       " wrpr  %%g2, 0x0, %%pstate\n\t"                                                \
+       " mov   %0, %%g6\n\t"                                                           \
        : /* No outputs */                                                              \
        : "r" (next), "r" (task_pc),                                                    \
          "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),          \
index 460ccc11c1d4607fb5076386ca28579f8951aeab..54dee9bc60e0a9508b156feb514e9fbd1e787ae2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.14 1997/06/13 14:03:11 davem Exp $ */
+/* $Id: uaccess.h,v 1.19 1997/06/30 10:31:46 jj Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -40,7 +40,7 @@ do {                                          \
                current->tss.ctx = (current->mm->context & 0x1fff); \
        }                                       \
        spitfire_set_secondary_context(current->tss.ctx); \
-       __asm__ __volatile__("flush %g4");      \
+       __asm__ __volatile__("flush %g6");      \
 } while(0)
 
 #define __user_ok(addr,size) 1
@@ -255,8 +255,47 @@ __asm__ __volatile__(                                                      \
 
 extern int __get_user_bad(void);
 
-extern __kernel_size_t __copy_to_user(void *to, void *from, __kernel_size_t size);
-extern __kernel_size_t __copy_from_user(void *to, void *from, __kernel_size_t size);
+extern __kernel_size_t __memcpy_short(void *to, const void *from, __kernel_size_t size, long asi_src, long asi_dst);
+extern __kernel_size_t __memcpy_entry(void *to, const void *from, __kernel_size_t size, long asi_src, long asi_dst);
+extern __kernel_size_t __memcpy_16plus(void *to, const void *from, __kernel_size_t size, long asi_src, long asi_dst);
+extern __kernel_size_t __memcpy_386plus(void *to, const void *from, __kernel_size_t size, long asi_src, long asi_dst);
+
+#if 0
+extern __inline__ __kernel_size_t __copy_to_user(void *to, void *from, __kernel_size_t size)
+{
+       if (__builtin_constant_p(size)) {
+               if (!size) return 0;
+               if (size < 16)
+                       return __memcpy_short(to,(const void *)from,size,ASI_BLK_P,ASI_BLK_S);
+               else if (size < 384)
+                       return __memcpy_16plus(to,(const void *)from,size,ASI_BLK_P,ASI_BLK_S);
+               else
+                       return __memcpy_386plus(to,(const void *)from,size,ASI_BLK_P,ASI_BLK_S);
+       } else {
+               if (!size) return 0;
+               return __memcpy_entry(to,(const void *)from,size,ASI_BLK_P,ASI_BLK_S);
+       }
+}
+
+extern __inline__ __kernel_size_t __copy_from_user(void *to, void *from, __kernel_size_t size)
+{
+       if (__builtin_constant_p(size)) {
+               if (!size) return 0;
+               if (size < 16)
+                       return __memcpy_short(to,(const void *)from,size,ASI_BLK_S,ASI_BLK_P);
+               else if (size < 384)
+                       return __memcpy_16plus(to,(const void *)from,size,ASI_BLK_S,ASI_BLK_P);
+               else
+                       return __memcpy_386plus(to,(const void *)from,size,ASI_BLK_S,ASI_BLK_P);
+       } else {
+               if (!size) return 0;
+               return __memcpy_entry(to,(const void *)from,size,ASI_BLK_S,ASI_BLK_P);
+       }
+}
+#else
+extern __kernel_size_t __copy_from_user(void *to, const void *from, __kernel_size_t size);
+extern __kernel_size_t __copy_to_user(void *to, const void *from, __kernel_size_t size);
+#endif
 
 #define copy_to_user(to,from,n) \
        __copy_to_user((void *)(to), \
@@ -288,21 +327,11 @@ if (__copy_from_user(to,from,n)) \
 
 extern __inline__ __kernel_size_t __clear_user(void *addr, __kernel_size_t size)
 {
-  __kernel_size_t ret;
-  __asm__ __volatile__ ("
-       .section __ex_table,#alloc
-       .align 8
-       .xword 1f,3
-       .previous
-1:
-       wr %%g0, %3, %%asi
-       mov %2, %%o1
-       call __bzero_noasi
-        mov %1, %%o0
-       mov %%o0, %0
-       " : "=r" (ret) : "r" (addr), "r" (size), "i" (ASI_S) :
-       "cc", "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
-  return ret;
+       extern __kernel_size_t __bzero_noasi(void *addr, __kernel_size_t size);
+       
+       
+       __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "i" (ASI_S));
+       return __bzero_noasi(addr, size);
 }
 
 #define clear_user(addr,n) \
diff --git a/include/asm-sparc64/uctx.h b/include/asm-sparc64/uctx.h
new file mode 100644 (file)
index 0000000..6eaf16e
--- /dev/null
@@ -0,0 +1,71 @@
+/* $Id: uctx.h,v 1.1 1997/06/18 16:51:58 davem Exp $
+ * uctx.h: Sparc64 {set,get}context() register state layouts.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_UCTX_H
+#define __SPARC64_UCTX_H
+
+#define MC_TSTATE      0
+#define MC_PC          1
+#define MC_NPC         2
+#define MC_Y           3
+#define MC_G1          4
+#define MC_G2          5
+#define MC_G3          6
+#define MC_G4          7
+#define MC_G5          8
+#define MC_G6          9
+#define MC_G7          10
+#define MC_O0          11
+#define MC_O1          12
+#define MC_O2          13
+#define MC_O3          14
+#define MC_O4          15
+#define MC_O5          16
+#define MC_O6          17
+#define MC_O7          18
+#define MC_NGREG       19
+
+typedef unsigned long mc_greg_t;
+typedef mc_greg_t mc_gregset_t[MC_NGREG];
+
+#define MC_MAXFPQ      16
+struct mc_fq {
+       unsigned long   *mcfq_addr;
+       unsigned int    mcfq_insn;
+};
+
+struct mc_fpu {
+       union {
+               unsigned int    sregs[32];
+               unsigned long   dregs[32];
+               long double     qregs[16];
+       } mcfpu_fregs;
+       unsigned long   mcfpu_fsr;
+       unsigned long   mcfpu_fprs;
+       unsigned long   mcfpu_gsr;
+       struct mc_fq    *mcfpu_fq;
+       unsigned char   mcfpu_qcnt;
+       unsigned char   mcfpu_qentsz;
+       unsigned char   mcfpu_enab;
+};
+typedef struct mc_fpu mc_fpu_t;
+
+typedef struct {
+       mc_gregset_t    mc_gregs;
+       mc_greg_t       mc_fp;
+       mc_greg_t       mc_i7;
+       mc_fpu_t        mc_fpregs;
+} mcontext_t;
+
+struct ucontext {
+       struct ucontext         *uc_link;
+       unsigned long           uc_flags;
+       sigset_t                uc_sigmask;
+       mcontext_t              uc_mcontext;
+};
+typedef struct ucontext ucontext_t;
+
+#endif /* __SPARC64_UCTX_H */
index cd82abb060f92e5a90e617107206ddb9134f9e03..b88085668a1d691fc26eb623a1de05fa5cbe704d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: vaddrs.h,v 1.6 1997/04/04 00:50:31 davem Exp $ */
+/* $Id: vaddrs.h,v 1.8 1997/06/27 14:55:13 jj Exp $ */
 #ifndef _SPARC64_VADDRS_H
 #define _SPARC64_VADDRS_H
 
  * mappings for devices and is the speedup improvements of not loading
  * a pointer and then the value in the assembly code
  */
-#define  IOBASE_VADDR   0xfffffd0000000000ULL  /* Base for mapping pages */
-#define  IOBASE_LEN     0x0000008000000000ULL  /* Length of the IO area */
-#define  IOBASE_END     0xfffffd8000000000ULL
-#define  DVMA_VADDR     0xfffffd8000000000ULL  /* Base area of the DVMA on suns */
-#define  DVMA_LEN       0x0000004000000000ULL  /* Size of the DVMA address space */
-#define  DVMA_END       0xfffffdc000000000ULL
+#define  IOBASE_VADDR   0x0000006000000000ULL  /* Base for mapping pages */
+#define  IOBASE_LEN     0x0000001000000000ULL  /* Length of the IO area */
+#define  IOBASE_END     0x0000007000000000ULL
+#define  DVMA_VADDR     0x0000007000000000ULL  /* Base area of the DVMA on suns */
+#define  DVMA_LEN       0x0000001000000000ULL  /* Size of the DVMA address space */
+#define  DVMA_END       0x0000008000000000ULL
+#define  MODULES_VADDR 0x0000000001000000ULL  /* Where to map modules */
+#define  MODULES_LEN   0x000000007f000000ULL
+#define  MODULES_END   0x0000000080000000ULL
 
 #endif /* !(_SPARC_VADDRS_H) */
 
index ee593013be29d1764c6c9728c3e7bc4b0d0dab0d..1a8e027cc2fa7d63ff0cca8e3147e191503773e7 100644 (file)
@@ -50,6 +50,7 @@ extern int open_inode(struct inode * inode, int mode);
 extern int init_elf_binfmt(void);
 extern int init_elf32_binfmt(void);
 extern int init_aout_binfmt(void);
+extern int init_aout32_binfmt(void);
 extern int init_script_binfmt(void);
 extern int init_java_binfmt(void);
 extern int init_em86_binfmt(void);
index e9ef418f7d516ba4d86cf12c74e9ba929558bc59..99ed0e347ee392dc6078e4c54386b386ad934112 100644 (file)
@@ -4,6 +4,8 @@
  * Data structure and defines shared between console.c, vga.c and tga.c
  */
 
+#include <linux/config.h>
+
 #define NPAR 16
 
 struct vc_data {
@@ -17,12 +19,17 @@ struct vc_data {
        unsigned char   vc_halfcolor;           /* Colour for half intensity mode */
        unsigned long   vc_origin;              /* Used for EGA/VGA fast scroll */
        unsigned long   vc_scr_end;             /* Used for EGA/VGA fast scroll */
-       unsigned long   vc_pos;
        unsigned long   vc_x,vc_y;
        unsigned long   vc_top,vc_bottom;
        unsigned long   vc_state;
        unsigned long   vc_npar,vc_par[NPAR];
+#ifdef CONFIG_FB_CONSOLE
+       unsigned short  *vc_video_mem_start;    /* Start of video RAM           */
+       unsigned short  *vc_pos;
+#else
+       unsigned long   vc_pos;
        unsigned long   vc_video_mem_start;     /* Start of video RAM           */
+#endif
        unsigned long   vc_video_mem_end;       /* End of video RAM (sort of)   */
        unsigned long   vc_saved_x;
        unsigned long   vc_saved_y;
index 64f78b233aa71d42ddb843f77e79eb7134a3def3..a180bb94d1f9d4ba8ff76d3d26253e84dd2c52b9 100644 (file)
 #define D_MAXLEN 1024
 
 /* public flags for d_add() */
-#define D_NORMAL     0
-#define D_BASKET     1 /* put into basket (deleted/unref'd files) */
-#define D_DUPLICATE  2 /* allow duplicate entries */
-#define D_NOCHECKDUP 4 /* no not check for duplicates */
-
-/* public flags for d_flag */
-#define D_PRELOADED 8
+#define D_NORMAL         0
+#define D_BASKET         1 /* put into basket (deleted/unref'd files) */
+#define D_DUPLICATE      2 /* allow duplicate entries */
+#define D_NOCHECKDUP     4 /* no not check for duplicates */
+#define D_NEGATIVE       8 /* negative entry */
+#define D_PRELOADED     16
+#define D_DIR           32 /* directory entry - look out for allocation issues */
+#define D_HASHED        64
+#define D_ZOMBIE       128
+#define D_INC_DDIR     512
 
 /* public flags for d_del() */
 #define D_REMOVE         0
 #define IS_ROOT(x) ((x) == (x)->d_parent)
 
 /* "quick string" -- I introduced this to shorten the parameter list
- * of many routines. Think of it as a (str,stlen) pair.
+ * of many routines. Think of it as a (str,stlen,hash) pair.
  * Storing the len instead of doing strlen() very often is performance
  * critical.
  */
 struct qstr {
-       char * name;
-       int len;
+       const unsigned char * name;
+       int len, hash;
 };
 
+/* Name hashing routines. Initial hash value */
+#define init_name_hash()               0
+
+/* partial hash update function. Assume roughly 4 bits per character */
+static inline unsigned long partial_name_hash(unsigned char c, unsigned long prevhash)
+{
+       prevhash = (prevhash << 4) | (prevhash >> (8*sizeof(unsigned long)-4));
+       return prevhash ^ c;
+}
+
+/* Finally: cut down the number of bits to a int value (and try to avoid losing bits) */
+static inline unsigned long end_name_hash(unsigned long hash)
+{
+       if (sizeof(hash) > sizeof(unsigned int))
+               hash += hash >> 4*sizeof(hash);
+       return (unsigned int) hash;
+}
+
 struct dentry {
-       union {
-               struct inode  * d_inode;  /* Where the name belongs to */
-               unsigned long d_ino;      /* for preliminary entries */
-       } u;
-       struct dentry * d_parent; /* parent directory */
-       struct dentry * d_next;   /* hardlink aliasname / empty list */
-       struct dentry * d_prev;   /* hardlink aliasname */
+       unsigned int d_flag;
+       unsigned int d_count;
+       struct inode  * d_inode;        /* Where the name belongs to */
+       struct dentry * d_parent;       /* parent directory */
+       struct dentry * d_mounts;       /* mount information */
+       struct dentry * d_covers;
+       struct dentry * d_next;         /* hardlink aliasname / empty list */
+       struct dentry * d_prev;         /* hardlink aliasname */
        struct dentry * d_hash_next;
        struct dentry * d_hash_prev;
        struct dentry * d_basket_next;
        struct dentry * d_basket_prev;
        struct qstr d_name;
-       unsigned int d_flag;
 };
 
 extern struct dentry * the_root;
 
+/*
+ * These are the low-level FS interfaces to the dcache..
+ */
+extern void d_instantiate(struct dentry *, struct inode *, int);
+extern void d_delete(struct dentry *);
+
+
 /* Note that all these routines must be called with vfs_lock() held */
 
 /* get inode, if necessary retrieve it with iget() */
 extern blocking struct inode * d_inode(struct dentry ** changing_entry);
 
-/* allocate proper space for the len */
-extern struct dentry * d_alloc(struct dentry * parent, int len, int isdir);
+/* allocate/de-allocate */
+extern void d_free(struct dentry *);
+extern struct dentry * d_alloc(struct dentry * parent, struct qstr *name, int isdir);
 
-/* only used once at mount_root() */
+/* only used at mount-time */
 extern blocking
-struct dentry * d_alloc_root(struct inode * root_inode);
+struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * old_root);
 
-/* d_inode is connected with inode, and d_name is copied from ininame.
- * either of them may be NULL, but when ininame is NULL, dname must be
- * set by the caller prior to calling this. */
+/*
+ * This adds the entry to the hash queues and initializes "d_inode".
+ * The entry was actually filled in earlier during "d_alloc()"
+ */
 extern blocking
-void d_add(struct dentry * entry, struct inode * inode,
-          struct qstr * ininame, int flags);
+void d_add(struct dentry * entry, struct inode * inode, int flags);
 
 /* combination of d_alloc() and d_add(), less lookup overhead */
 extern blocking 
@@ -85,17 +114,32 @@ void d_del(struct dentry * entry, int flags);
 
 /* used for rename() and baskets */
 extern blocking 
-void d_move(struct dentry * entry, struct inode * newdir,
-           struct qstr * newname, struct qstr * newapp);
+void d_move(struct dentry * entry, struct dentry * newparent, struct qstr * newname);
 
 /* appendix may either be NULL or be used for transname suffixes */
-extern struct dentry * d_lookup(struct inode * dir, struct qstr * name,
-                               struct qstr * appendix);
+extern struct dentry * d_lookup(struct dentry * dir, struct qstr * name);
 
 /* write full pathname into buffer and return length */
-extern int d_path(struct dentry * entry, struct inode * chroot, char * buf);
+extern int d_path(struct dentry * entry, struct dentry * chroot, char * buf);
 
 extern struct dentry * d_basket(struct dentry * dir_entry);
 
 extern int d_isbasket(struct dentry * entry);
+
+/*
+ * Whee..
+ */
+static inline void dput(struct dentry *dentry)
+{
+       if (dentry)
+               dentry->d_count--;
+}
+
+static inline struct dentry * dget(struct dentry *dentry)
+{
+       if (dentry)
+               dentry->d_count++;
+       return dentry;
+}
+
 #endif
index 9c66cfc29470b73eb0b031a1ebc18610b9bb9ee8..f3087fb44aa232f2f0049360f20eefe259bc2ec4 100644 (file)
@@ -492,17 +492,15 @@ extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
 
 /* namei.c */
 extern void ext2_release (struct inode *, struct file *);
-extern int ext2_lookup (struct inode *,const char *, int, struct inode **);
-extern int ext2_create (struct inode *,const char *, int, int,
-                       struct inode **);
-extern int ext2_mkdir (struct inode *, const char *, int, int);
-extern int ext2_rmdir (struct inode *, const char *, int);
-extern int ext2_unlink (struct inode *, const char *, int);
-extern int ext2_symlink (struct inode *, const char *, int, const char *);
-extern int ext2_link (struct inode *, struct inode *, const char *, int);
-extern int ext2_mknod (struct inode *, const char *, int, int, int);
-extern int ext2_rename (struct inode *, const char *, int,
-                       struct inode *, const char *, int);
+extern int ext2_lookup (struct inode *,struct qstr *, struct inode **);
+extern int ext2_create (struct inode *,struct dentry *,int);
+extern int ext2_mkdir (struct inode *,struct dentry *,int);
+extern int ext2_rmdir (struct inode *,struct dentry *);
+extern int ext2_unlink (struct inode *,struct dentry *);
+extern int ext2_symlink (struct inode *,struct dentry *,const char *);
+extern int ext2_link (struct inode *, struct inode *, struct dentry *);
+extern int ext2_mknod (struct inode *, struct dentry *, int, int);
+extern int ext2_rename (struct inode *, struct dentry *,struct inode *, struct dentry *);
 
 /* super.c */
 extern void ext2_error (struct super_block *, const char *, const char *, ...)
index ddc349d3ea1db195bf0360dd13b3df8541da8132..724b62b7ace06ee7b91d56223e07dd3470064f49 100644 (file)
@@ -24,6 +24,8 @@
  */
 #define blocking /*routine may schedule()*/
 
+#include <linux/dalloc.h>
+
 /*
  * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
  * that later. Anyway, now the file code is no longer dependent
@@ -105,13 +107,6 @@ extern int max_files, nr_files;
 #define MS_MGC_VAL 0xC0ED0000  /* magic flag number to indicate "new" flags */
 #define MS_MGC_MSK 0xffff0000  /* magic flag number mask */
 
-/*
- * Public flags for namei()
- */
-#define NAM_PLAIN              0 /* Retrieve last component of pathname as is. */
-#define NAM_FOLLOW_LINK                2 /* If last component of path is a symlink, follow it */
-#define NAM_FOLLOW_TRAILSLASH  4 /* Follow last symlink only if trailed by slash. */
-
 /*
  * Note that read-only etc flags are inode-specific: setting some file-system
  * flags just means all the inodes inherit those flags by default. It might be
@@ -342,12 +337,9 @@ struct inode {
        struct inode            *i_basket_prev;
        struct dentry           *i_dentry;
 
-       short                   i_ddir_count;
-       short                   i_dent_count;
        unsigned short          i_status;
        unsigned short          i_reuse_count;
 
-       struct inode            *i_mount;
        unsigned int            i_flags;
        unsigned char           i_lock;
        unsigned char           i_dirt;
@@ -503,8 +495,7 @@ struct super_block {
        unsigned long           s_flags;
        unsigned long           s_magic;
        unsigned long           s_time;
-       struct inode            *s_covered;
-       struct inode            *s_mounted;
+       struct dentry           *s_root;
        struct wait_queue       *s_wait;
 
        struct inode            *s_ibasket;
@@ -553,16 +544,17 @@ struct file_operations {
 
 struct inode_operations {
        struct file_operations * default_file_ops;
-       int (*create) (struct inode *,const char *,int,int,struct inode **);
-       int (*lookup) (struct inode *,const char *,int,struct inode **);
-       int (*link) (struct inode *,struct inode *,const char *,int);
-       int (*unlink) (struct inode *,const char *,int);
-       int (*symlink) (struct inode *,const char *,int,const char *);
-       int (*mkdir) (struct inode *,const char *,int,int);
-       int (*rmdir) (struct inode *,const char *,int);
-       int (*mknod) (struct inode *,const char *,int,int,int);
-       int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int);
+       int (*create) (struct inode *,struct dentry *,int);
+       int (*lookup) (struct inode *,struct qstr *name,struct inode **);
+       int (*link) (struct inode *,struct inode *,struct dentry *);
+       int (*unlink) (struct inode *,struct dentry *);
+       int (*symlink) (struct inode *,struct dentry *,const char *);
+       int (*mkdir) (struct inode *,struct dentry *,int);
+       int (*rmdir) (struct inode *,struct dentry *);
+       int (*mknod) (struct inode *,struct dentry *,int,int);
+       int (*rename) (struct inode *,struct dentry *,struct inode *,struct dentry *);
        int (*readlink) (struct inode *,char *,int);
+       struct dentry * (*follow_link) (struct inode *, struct dentry *);
        int (*readpage) (struct inode *, struct page *);
        int (*writepage) (struct inode *, struct page *);
        int (*bmap) (struct inode *,int);
@@ -640,7 +632,7 @@ extern struct file_operations rdwr_pipe_fops;
 extern struct file_system_type *get_fs_type(const char *name);
 
 extern int fs_may_mount(kdev_t dev);
-extern int fs_may_umount(kdev_t dev, struct inode * mount_root);
+extern int fs_may_umount(kdev_t dev, struct dentry * root);
 extern int fs_may_remount_ro(kdev_t dev);
 
 extern struct file *inuse_filps;
@@ -689,15 +681,32 @@ extern int fsync_dev(kdev_t dev);
 extern void sync_supers(kdev_t dev);
 extern int bmap(struct inode * inode,int block);
 extern int notify_change(struct inode *, struct iattr *);
-extern int namei(int retr_mode, const char *pathname, struct inode **res_inode);
 extern int permission(struct inode * inode,int mask);
 extern int get_write_access(struct inode *inode);
 extern void put_write_access(struct inode *inode);
 extern int open_namei(const char * pathname, int flag, int mode,
-       struct inode ** res_inode, struct inode * base);
+       struct inode ** res_inode, struct dentry * base);
 extern int do_mknod(const char * filename, int mode, dev_t dev);
 extern int do_pipe(int *);
 
+/*
+ * Kernel pointers have redundant information, so we can use a
+ * scheme where we can return either an error code or a dentry
+ * pointer with the same return value.
+ *
+ * This should be a per-architecture thing, to allow different
+ * error and pointer decisions.
+ */
+#define ERR_PTR(err)   ((void *)((long)(err)))
+#define PTR_ERR(ptr)   ((long)(ptr))
+#define IS_ERR(ptr)    ((unsigned long)(ptr) > (unsigned long)(-1000))
+
+extern struct dentry * lookup_dentry(const char *, struct dentry *, int);
+extern int __namei(const char *, struct inode **, int);
+
+#define namei(pathname, inode_p)       __namei(pathname, inode_p, 1)
+#define lnamei(pathname, inode_p)      __namei(pathname, inode_p, 0)
+
 #include <asm/semaphore.h>
 
 /* Intended for short locks of the global data structures in inode.c.
@@ -728,51 +737,24 @@ extern inline void vfs_unlock(void)
 extern void _get_inode(struct inode * inode);
 extern blocking void __iput(struct inode * inode);
 
-/* This must not be called if the inode is not in use (i.e. given
- * back with iput(). The atomic inc assumes that the inode is
- * already in use, and just has to be incremented higher. 
- * Please do not directly manipulate i_count any more.
- * Use iget, iinc and iput.
- * You may test i_count for zero if you are aware that it
- * might change under you.
- */
-extern inline void iinc(struct inode * inode)
-{
-       atomic_inc(&inode->i_count);
-}
-
-/* The same, but the inode may not be in use. This must be called
- * with vfslock() held, and be asure that the inode argument is
- * valid (i.e. not out of cache). So the vfs_lock() must span the
- * retrieval method of the inode.
- */
-extern inline void iinc_zero(struct inode * inode)
-{
-       if(!atomic_read(&inode->i_count)) {
-               atomic_inc(&inode->i_count);
-               _get_inode(inode);
-       } else
-               atomic_inc(&inode->i_count);
-}
-
 extern blocking void _iput(struct inode * inode);
 extern inline blocking void iput(struct inode * inode)
 {
-       if(inode) {
+       if (inode) {
                extern void wake_up_interruptible(struct wait_queue **q);
 
-               if(inode->i_pipe)
+               if (inode->i_pipe)
                        wake_up_interruptible(&inode->u.pipe_i.wait);
 
                /* It does not matter if somebody re-increments it in between,
                 * only the _last_ user needs to call _iput().
                 */
-               if(atomic_dec_and_test(&inode->i_count) && inode->i_ddir_count <= 0)
+               if (atomic_dec_and_test(&inode->i_count))
                        _iput(inode);
        }
 }
 
-extern blocking struct inode * __iget(struct super_block * sb, unsigned long nr, int crsmnt);
+extern blocking struct inode * iget(struct super_block * sb, unsigned long nr);
 extern blocking void _clear_inode(struct inode * inode, int external, int verbose);
 extern blocking inline void clear_inode(struct inode * inode)
 {
@@ -795,16 +777,6 @@ extern inline blocking struct inode * get_empty_inode(void)
  */
 blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino);
 
-extern blocking int _free_ibasket(struct super_block * sb);
-extern inline blocking int free_ibasket(struct super_block * sb)
-{
-       int res;
-       vfs_lock();
-       res = _free_ibasket(sb);
-       vfs_unlock();
-       return res;
-}
-
 extern void insert_inode_hash(struct inode *);
 extern blocking struct inode * get_pipe_inode(void);
 extern int get_unused_fd(void);
@@ -872,12 +844,6 @@ extern int dcache_lookup(struct inode *, const char *, int, unsigned long *);
 extern int inode_change_ok(struct inode *, struct iattr *);
 extern void inode_setattr(struct inode *, struct iattr *);
 
-extern inline blocking 
-struct inode * iget(struct super_block * sb, unsigned long nr)
-{
-       return __iget(sb, nr, 1);
-}
-
 /* kludge to get SCSI modules working */
 #include <linux/minix_fs.h>
 #include <linux/minix_fs_sb.h>
diff --git a/include/linux/ghash.h b/include/linux/ghash.h
new file mode 100644 (file)
index 0000000..278f6c2
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * include/linux/ghash.h -- generic hashing with fuzzy retrieval
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ *
+ * The algorithms implemented here seem to be a completely new invention,
+ * and I'll publish the fundamentals in a paper.
+ */
+
+#ifndef _GHASH_H
+#define _GHASH_H
+/* HASHSIZE _must_ be a power of two!!! */
+
+
+#define DEF_HASH_FUZZY_STRUCTS(NAME,HASHSIZE,TYPE) \
+\
+struct NAME##_table {\
+       TYPE * hashtable[HASHSIZE];\
+       TYPE * sorted_list;\
+       int nr_entries;\
+};\
+\
+struct NAME##_ptrs {\
+       TYPE * next_hash;\
+       TYPE * prev_hash;\
+       TYPE * next_sorted;\
+       TYPE * prev_sorted;\
+};
+
+#define DEF_HASH_FUZZY(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
+\
+LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+       int ix = HASHFN(elem->KEY);\
+       TYPE ** base = &tbl->hashtable[ix];\
+       TYPE * ptr = *base;\
+       TYPE * prev = NULL;\
+\
+       tbl->nr_entries++;\
+       while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
+               base = &ptr->PTRS.next_hash;\
+               prev = ptr;\
+               ptr = *base;\
+       }\
+       elem->PTRS.next_hash = ptr;\
+       elem->PTRS.prev_hash = prev;\
+       if(ptr) {\
+               ptr->PTRS.prev_hash = elem;\
+       }\
+       *base = elem;\
+\
+       ptr = prev;\
+       if(!ptr) {\
+               ptr = tbl->sorted_list;\
+               prev = NULL;\
+       } else {\
+               prev = ptr->PTRS.prev_sorted;\
+       }\
+       while(ptr) {\
+               TYPE * next = ptr->PTRS.next_hash;\
+               if(next && KEYCMP(next->KEY, elem->KEY)) {\
+                       prev = ptr;\
+                       ptr = next;\
+               } else if(KEYCMP(ptr->KEY, elem->KEY)) {\
+                       prev = ptr;\
+                       ptr = ptr->PTRS.next_sorted;\
+               } else\
+                       break;\
+       }\
+       elem->PTRS.next_sorted = ptr;\
+       elem->PTRS.prev_sorted = prev;\
+       if(ptr) {\
+               ptr->PTRS.prev_sorted = elem;\
+       }\
+       if(prev) {\
+               prev->PTRS.next_sorted = elem;\
+       } else {\
+               tbl->sorted_list = elem;\
+       }\
+}\
+\
+LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+       TYPE * next = elem->PTRS.next_hash;\
+       TYPE * prev = elem->PTRS.prev_hash;\
+\
+       tbl->nr_entries--;\
+       if(next)\
+               next->PTRS.prev_hash = prev;\
+       if(prev)\
+               prev->PTRS.next_hash = next;\
+       else {\
+               int ix = HASHFN(elem->KEY);\
+               tbl->hashtable[ix] = next;\
+       }\
+\
+       next = elem->PTRS.next_sorted;\
+       prev = elem->PTRS.prev_sorted;\
+       if(next)\
+               next->PTRS.prev_sorted = prev;\
+       if(prev)\
+               prev->PTRS.next_sorted = next;\
+       else\
+               tbl->sorted_list = next;\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+       int ix = hashfn(pos);\
+       TYPE * ptr = tbl->hashtable[ix];\
+       while(ptr && KEYCMP(ptr->KEY, pos))\
+               ptr = ptr->PTRS.next_hash;\
+       if(ptr && !KEYEQ(ptr->KEY, pos))\
+               ptr = NULL;\
+       return ptr;\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash_fuzzy(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+       int ix;\
+       int offset;\
+       TYPE * ptr;\
+       TYPE * next;\
+\
+       ptr = tbl->sorted_list;\
+       if(!ptr || KEYCMP(pos, ptr->KEY))\
+               return NULL;\
+       ix = HASHFN(pos);\
+       offset = HASHSIZE;\
+       do {\
+               offset >>= 1;\
+               next = tbl->hashtable[(ix+offset) & ((HASHSIZE)-1)];\
+               if(next && (KEYCMP(next->KEY, pos) || KEYEQ(next->KEY, pos))\
+                  && KEYCMP(ptr->KEY, next->KEY))\
+                       ptr = next;\
+       } while(offset);\
+\
+       for(;;) {\
+               next = ptr->PTRS.next_hash;\
+               if(next) {\
+                       if(KEYCMP(next->KEY, pos)) {\
+                               ptr = next;\
+                               continue;\
+                       }\
+               }\
+               next = ptr->PTRS.next_sorted;\
+               if(next && KEYCMP(next->KEY, pos)) {\
+                       ptr = next;\
+                       continue;\
+               }\
+               return ptr;\
+       }\
+       return NULL;\
+}
+
+#define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \
+\
+struct NAME##_table {\
+       TYPE * hashtable[HASHSIZE];\
+       int nr_entries;\
+};\
+\
+struct NAME##_ptrs {\
+       TYPE * next_hash;\
+       TYPE * prev_hash;\
+};
+
+#define DEF_HASH(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
+\
+LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+       int ix = HASHFN(elem->KEY);\
+       TYPE ** base = &tbl->hashtable[ix];\
+       TYPE * ptr = *base;\
+       TYPE * prev = NULL;\
+\
+       tbl->nr_entries++;\
+       while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
+               base = &ptr->PTRS.next_hash;\
+               prev = ptr;\
+               ptr = *base;\
+       }\
+       elem->PTRS.next_hash = ptr;\
+       elem->PTRS.prev_hash = prev;\
+       if(ptr) {\
+               ptr->PTRS.prev_hash = elem;\
+       }\
+       *base = elem;\
+}\
+\
+LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+       TYPE * next = elem->PTRS.next_hash;\
+       TYPE * prev = elem->PTRS.prev_hash;\
+\
+       tbl->nr_entries--;\
+       if(next)\
+               next->PTRS.prev_hash = prev;\
+       if(prev)\
+               prev->PTRS.next_hash = next;\
+       else {\
+               int ix = HASHFN(elem->KEY);\
+               tbl->hashtable[ix] = next;\
+       }\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+       int ix = hashfn(pos);\
+       TYPE * ptr = tbl->hashtable[ix];\
+       while(ptr && KEYCMP(ptr->KEY, pos))\
+               ptr = ptr->PTRS.next_hash;\
+       if(ptr && !KEYEQ(ptr->KEY, pos))\
+               ptr = NULL;\
+       return ptr;\
+}
+
+#endif
index 14762045e8feca32f5f59849bea71135af7ec5af..d95e99211da87d6dcd750c1010f38692259b6188 100644 (file)
@@ -312,7 +312,8 @@ extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_
 extern void proc_statfs(struct super_block *, struct statfs *, int);
 extern void proc_read_inode(struct inode *);
 extern void proc_write_inode(struct inode *);
-extern int proc_match(int, const char *, struct proc_dir_entry *);
+
+extern int proc_match(int, const char *,struct proc_dir_entry *);
 
 /*
  * These are generic /proc routines that use the internal
@@ -322,7 +323,7 @@ extern int proc_match(int, const char *, struct proc_dir_entry *);
  * of the /proc/<pid> subdirectories.
  */
 extern int proc_readdir(struct inode *, struct file *, void *, filldir_t);
-extern int proc_lookup(struct inode *, const char *, int, struct inode **);
+extern int proc_lookup(struct inode *, struct qstr *, struct inode **);
 
 struct openpromfs_dev {
        struct openpromfs_dev *next;
@@ -334,7 +335,7 @@ struct openpromfs_dev {
 };
 extern struct inode_operations *
 proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
-                      int (*lookup)(struct inode *, const char *, int, struct inode **),
+                      int (*lookup)(struct inode *, struct qstr *, struct inode **),
                       void (*use)(struct inode *, int),
                       struct openpromfs_dev ***);
 extern void proc_openprom_deregister(void);
@@ -362,9 +363,6 @@ extern struct inode_operations proc_ringbuf_inode_operations;
 #endif
 extern struct inode_operations proc_omirr_inode_operations;
 
-/* Not sure whether this belongs here */
-int proc_arbitrary_lookup(struct inode * dir, const char * name,
-                         int len, struct inode ** result);
 #endif
 
 /*
index 2ca68dbaa3a589293838df56704408f9aa69e9f7..cd82c95c3ac8a4187e093ec6a728d2b1b82779ff 100644 (file)
@@ -8,8 +8,9 @@
 #define        ROSE_KERNEL_H
 
 #define PF_ROSE                AF_ROSE
-#define ROSE_MTU       128
+#define ROSE_MTU       251
 
+#define        ROSE_DEFER      1
 #define ROSE_T1                2
 #define        ROSE_T2         3
 #define        ROSE_T3         4
 #define        ROSE_QBITINCL   6
 #define        ROSE_HOLDBACK   7
 
+#define        SIOCRSGCAUSE            (SIOCPROTOPRIVATE+0)
+#define        SIOCRSSCAUSE            (SIOCPROTOPRIVATE+1)
 #define        SIOCRSL2CALL            (SIOCPROTOPRIVATE+2)
+#define        SIOCRSACCEPT            (SIOCPROTOPRIVATE+3)
+#define        SIOCRSCLRRT             (SIOCPROTOPRIVATE+4)
+
+#define        ROSE_DTE_ORIGINATED     0x00
+#define        ROSE_NUMBER_BUSY        0x01
+#define        ROSE_INVALID_FACILITY   0x03
+#define        ROSE_NETWORK_CONGESTION 0x05
+#define        ROSE_OUT_OF_ORDER       0x09
+#define        ROSE_ACCESS_BARRED      0x0B
+#define        ROSE_NOT_OBTAINABLE     0x0D
+#define        ROSE_REMOTE_PROCEDURE   0x11
+#define        ROSE_LOCAL_PROCEDURE    0x13
+#define        ROSE_SHIP_ABSENT        0x39
 
 typedef struct {
        char            rose_addr[5];
@@ -40,4 +56,9 @@ struct rose_route_struct {
        ax25_address    digipeaters[AX25_MAX_DIGIS];
 };
 
+struct rose_cause_struct {
+       unsigned char   cause;
+       unsigned char   diagnostic;
+};
+
 #endif
index 9346ab2a77fe8d36feec272c3cb4d171f60d1351..361498eadb4ffe6388495393ed18d67a4cc9dda5 100644 (file)
@@ -130,7 +130,7 @@ struct files_struct {
 struct fs_struct {
        int count;
        int umask;
-       struct inode * root, * pwd;
+       struct dentry * root, * pwd;
 };
 
 #define INIT_FS { \
index 058e35588ccda69fb14a96e531c782dff31fdd54..3779429b45c849a034085e1e52ad3ee672ca1c32 100644 (file)
@@ -23,11 +23,11 @@ extern unsigned long get_video_size_row(unsigned int console);
 #define get_video_num_columns(dummy) video_num_columns
 #define get_video_num_lines(dummy) video_num_lines
 #define get_video_size_row(dummy) video_size_row
-#endif
-
 extern unsigned long video_num_columns;
 extern unsigned long video_num_lines;
 extern unsigned long video_size_row;
+#endif
+
 extern unsigned char video_type;
 extern unsigned long video_mem_base;
 extern unsigned long video_mem_term;
@@ -73,6 +73,8 @@ extern void putconsxy(int currcons, char *p);
 
 /* how to access screen memory */
 
+#include <linux/config.h>
+
 #if defined(CONFIG_TGA_CONSOLE)
 
 extern int tga_blitc(unsigned int, unsigned long);
diff --git a/include/linux/simp.h b/include/linux/simp.h
new file mode 100644 (file)
index 0000000..e9cb6e5
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * include/linux/simp.h  -- simple allocator for cached objects
+ *
+ * This is meant as a faster and simpler (not full-featured) replacement
+ * for SLAB, thus the name "simp" :-)
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ */
+
+#ifndef SIMP_H
+#define SIMP_H
+
+/* used for constructors / destructors */
+typedef void (*structor)(void *);
+
+/* create an object cache */
+/* positive clearable_offset means the next two pointers at that offset
+ * can be internally used for freelist pointers when the object is
+ * deallocated / not in use;
+ * if there is no space inside the element that can be reused for
+ * this purpose, supply -1. Using positive offsets is essential for
+ * saving space with very small-sized objects.
+ *
+ * Note for big-sized objects in the range of whole pages, use
+ * the fast Linux page allocator instead, directly.
+ */
+extern struct simp * simp_create(char * name, long size, long clearable_offset,
+                                structor first_ctor, 
+                                structor again_ctor, 
+                                structor dtor);
+
+/* alloc / dealloc routines */
+extern void * simp_alloc(struct simp * simp);
+extern void simp_free(void * objp);
+
+/* garbage collection */
+extern long simp_garbage(void);
+
+#endif
index 21a01f013c2e063c30a7ce8b30b4576eb723aac3..0e3c0831d076e0dae02255c2aa2cff290a0a8046 100644 (file)
@@ -56,7 +56,7 @@ extern void *kmem_cache_alloc(kmem_cache_t *, int);
 extern void kmem_cache_free(kmem_cache_t *, void *);
 
 extern void *kmalloc(size_t, int);
-extern void kfree(void *);
+extern void kfree(const void *);
 extern void kfree_s(void *, size_t);
 
 extern int kmem_cache_reap(int, int, int);
index cab84d21299b7ecd39aee3bf8b2444e0f597ccc7..2d9bb6e196c575aa2110fc78ae2745a7187247d9 100644 (file)
@@ -90,13 +90,19 @@ extern struct screen_info screen_info;
 
 struct tty_flip_buffer {
        struct tq_struct tqueue;
-       unsigned char   char_buf[2*TTY_FLIPBUF_SIZE];
-       char            flag_buf[2*TTY_FLIPBUF_SIZE];
+       struct semaphore pty_sem;
        char            *char_buf_ptr;
        unsigned char   *flag_buf_ptr;
        int             count;
        int             buf_num;
+       unsigned char   char_buf[2*TTY_FLIPBUF_SIZE];
+       char            flag_buf[2*TTY_FLIPBUF_SIZE];
+       unsigned char   slop[4]; /* N.B. bug overwrites buffer by 1 */
 };
+/*
+ * The pty uses char_buf and flag_buf as a contiguous buffer
+ */
+#define PTY_BUF_SIZE   4*TTY_FLIPBUF_SIZE
 
 /*
  * When a break, frame error, or parity error happens, these codes are
@@ -198,7 +204,7 @@ struct tty_flip_buffer {
  * most often used by a windowing system, which will set the correct
  * size each time the window is created or resized anyway.
  * IMPORTANT: since this structure is dynamically allocated, it must
- * be no larger than 4096 bytes.  Changing TTY_BUF_SIZE will change
+ * be no larger than 4096 bytes.  Changing TTY_FLIPBUF_SIZE will change
  * the size of this structure, and it needs to be done with care.
  *                                             - TYT, 9/14/92
  */
index 6af8e9a5bc6d2e74aefe9d357346ca5075f8f29c..0435e970106197de240287708e58e4ffb75b2fb7 100644 (file)
@@ -13,6 +13,7 @@
 #define        SIOCX25SFACILITIES      (SIOCPROTOPRIVATE + 3)
 #define        SIOCX25GCALLUSERDATA    (SIOCPROTOPRIVATE + 4)
 #define        SIOCX25SCALLUSERDATA    (SIOCPROTOPRIVATE + 5)
+#define        SIOCX25GCAUSEDIAG       (SIOCPROTOPRIVATE + 6)
 
 /*
  *     Values for {get,set}sockopt.
 #define        X25_PS2048              11
 #define        X25_PS4096              12
 
-/*
- *     X.25 Reset error and diagnostic codes.
- */
-#define        X25_ERR_RESET           100     /* Call Reset                   */
-#define        X25_ERR_ROUT            101     /* Out of Order                 */
-#define        X25_ERR_RRPE            102     /* Remote Procedure Error       */
-#define        X25_ERR_RLPE            103     /* Local Procedure Error        */
-#define        X25_ERR_RNCG            104     /* Network Congestion           */
-#define        X25_ERR_RRDO            105     /* Remote DTE Operational       */
-#define        X25_ERR_RNOP            106     /* Network Operational          */
-#define        X25_ERR_RINV            107     /* Invalid Call                 */
-#define        X25_ERR_RNOO            108     /* Network Out of Order         */
-
-/*
- *     X.25 Clear error and diagnostic codes.
- */
-#define        X25_ERR_CLEAR           110     /* Call Cleared                 */
-#define        X25_ERR_CBUSY           111     /* Number Busy                  */
-#define        X25_ERR_COUT            112     /* Out of Order                 */
-#define        X25_ERR_CRPE            113     /* Remote Procedure Error       */
-#define        X25_ERR_CRRC            114     /* Collect Call Refused         */
-#define        X25_ERR_CINV            115     /* Invalid Call                 */
-#define        X25_ERR_CNFS            116     /* Invalid Fast Select          */
-#define        X25_ERR_CSA             117     /* Ship Absent                  */
-#define        X25_ERR_CIFR            118     /* Invalid Facility Request     */
-#define        X25_ERR_CAB             119     /* Access Barred                */
-#define        X25_ERR_CLPE            120     /* Local Procedure Error        */
-#define        X25_ERR_CNCG            121     /* Network Congestion           */
-#define        X25_ERR_CNOB            122     /* Not Obtainable               */
-#define        X25_ERR_CROO            123     /* RPOA Out of Order            */
-
 /*
  * An X.121 address, it is held as ASCII text, null terminated, up to 15
  * digits and a null terminator.
  */
 typedef struct {
-       char x25_addr[16];
+       char            x25_addr[16];
 } x25_address;
 
 /*
@@ -114,4 +84,12 @@ struct x25_calluserdata {
        unsigned char   cuddata[128];
 };
 
+/*
+ *     Call clearing Cause and Diagnostic structure.
+ */
+struct x25_causediag {
+       unsigned char   cause;
+       unsigned char   diagnostic;
+};
+
 #endif
index 9e6f0df1118cf2591dca0552b90567224bfc153a..fd25e9f7f70c141bc93c44473b386711b4f35555 100644 (file)
@@ -9,10 +9,8 @@
 #include <linux/config.h>
 #include <linux/ax25.h>
 
-#define AX25_SLOWHZ                    10      /* Run timing at 1/10 second - gives us better resolution for 56kbit links */
-
-#define        AX25_T1CLAMPLO                  (1 * AX25_SLOWHZ)       /* If defined, clamp at 1 second **/
-#define        AX25_T1CLAMPHI                  (30 * AX25_SLOWHZ)      /* If defined, clamp at 30 seconds **/
+#define        AX25_T1CLAMPLO                  1
+#define        AX25_T1CLAMPHI                  (30 * HZ)
 
 #define        AX25_BPQ_HEADER_LEN             16
 #define        AX25_KISS_HEADER_LEN            1
@@ -125,14 +123,14 @@ enum {
 #define        AX25_DEF_CONMODE        2                       /* Connected mode allowed */
 #define        AX25_DEF_WINDOW         2                       /* Window=2 */
 #define        AX25_DEF_EWINDOW        32                      /* Module-128 Window=32 */
-#define        AX25_DEF_T1             (10 * AX25_SLOWHZ)      /* T1=10s */
-#define        AX25_DEF_T2             (3 * AX25_SLOWHZ)       /* T2=3s  */
-#define        AX25_DEF_T3             (300 * AX25_SLOWHZ)     /* T3=300s */
+#define        AX25_DEF_T1             (10 * HZ)               /* T1=10s */
+#define        AX25_DEF_T2             (3 * HZ)                /* T2=3s  */
+#define        AX25_DEF_T3             (300 * HZ)              /* T3=300s */
 #define        AX25_DEF_N2             10                      /* N2=10 */
-#define AX25_DEF_IDLE          (0 * 60 * AX25_SLOWHZ)  /* Idle=None */
+#define AX25_DEF_IDLE          (0 * 60 * HZ)           /* Idle=None */
 #define AX25_DEF_PACLEN                256                     /* Paclen=256 */
 #define        AX25_DEF_PROTOCOL       AX25_PROTO_STD_SIMPLEX  /* Standard AX.25 */
-#define AX25_DEF_DS_TIMEOUT    (3 * 60 * AX25_SLOWHZ)  /* DAMA timeout 3 minutes */
+#define AX25_DEF_DS_TIMEOUT    (3 * 60 * HZ)           /* DAMA timeout 3 minutes */
 
 typedef struct ax25_uid_assoc {
        struct ax25_uid_assoc   *next;
@@ -186,8 +184,8 @@ typedef struct ax25_cb {
        unsigned short          vs, vr, va;
        unsigned char           condition, backoff;
        unsigned char           n2, n2count;
-       unsigned short          t1, t2, t3, idle, rtt;
-       unsigned short          t1timer, t2timer, t3timer, idletimer;
+       struct timer_list       t1timer, t2timer, t3timer, idletimer;
+       unsigned long           t1, t2, t3, idle, rtt;
        unsigned short          paclen, fragno, fraglen;
        struct sk_buff_head     write_queue;
        struct sk_buff_head     reseq_queue;
@@ -251,20 +249,22 @@ extern void ax25_ds_set_timer(ax25_dev *);
 extern void ax25_ds_del_timer(ax25_dev *);
 extern void ax25_ds_timer(ax25_cb *);
 extern void ax25_ds_t1_timeout(ax25_cb *);
+extern void ax25_ds_heartbeat_expiry(ax25_cb *);
+extern void ax25_ds_t3timer_expiry(ax25_cb *);
+extern void ax25_ds_idletimer_expiry(ax25_cb *);
 
 #include <net/ax25call.h>
 
 /* ax25_iface.c */
 extern int  ax25_protocol_register(unsigned int, int (*)(struct sk_buff *, ax25_cb *));
 extern void ax25_protocol_release(unsigned int);
-extern int  ax25_linkfail_register(void (*)(ax25_address *, struct device *));
-extern void ax25_linkfail_release(void (*)(ax25_address *, struct device *));
+extern int  ax25_linkfail_register(void (*)(ax25_cb *, int));
+extern void ax25_linkfail_release(void (*)(ax25_cb *, int));
 extern int  ax25_listen_register(ax25_address *, struct device *);
 extern void ax25_listen_release(ax25_address *, struct device *);
 extern int  (*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *);
 extern int  ax25_listen_mine(ax25_address *, struct device *);
-extern void ax25_link_failed(ax25_address *, struct device *);
-extern int  ax25_link_up(ax25_address *, ax25_address *, ax25_digi *, struct device *);
+extern void ax25_link_failed(ax25_cb *, int);
 extern int  ax25_protocol_is_registered(unsigned int);
 
 /* ax25_in.c */
@@ -276,7 +276,7 @@ extern int  ax25_encapsulate(struct sk_buff *, struct device *, unsigned short,
 extern int  ax25_rebuild_header(struct sk_buff *);
 
 /* ax25_out.c */
-extern int  ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct device *);
+extern ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct device *);
 extern void ax25_output(ax25_cb *, int, struct sk_buff *);
 extern void ax25_kick(ax25_cb *);
 extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
@@ -288,9 +288,8 @@ extern void ax25_rt_device_down(struct device *);
 extern int  ax25_rt_ioctl(unsigned int, void *);
 extern int  ax25_rt_get_info(char *, char **, off_t, int, int);
 extern int  ax25_rt_autobind(ax25_cb *, ax25_address *);
-extern void ax25_rt_build_path(ax25_cb *, ax25_address *, struct device *);
-extern struct sk_buff *ax25_dg_build_path(struct sk_buff *, ax25_address *, struct device *);
-extern char ax25_ip_mode_get(ax25_address *, struct device *);
+extern ax25_route *ax25_rt_find_route(ax25_address *, struct device *);
+extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *);
 extern void ax25_rt_free(void);
 
 /* ax25_std_in.c */
@@ -304,7 +303,11 @@ extern void ax25_std_enquiry_response(ax25_cb *);
 extern void ax25_std_timeout_response(ax25_cb *);
 
 /* ax25_std_timer.c */
-extern void ax25_std_timer(ax25_cb *);
+extern void ax25_std_heartbeat_expiry(ax25_cb *);
+extern void ax25_std_t1timer_expiry(ax25_cb *);
+extern void ax25_std_t2timer_expiry(ax25_cb *);
+extern void ax25_std_t3timer_expiry(ax25_cb *);
+extern void ax25_std_idletimer_expiry(ax25_cb *);
 
 /* ax25_subr.c */
 extern void ax25_clear_queues(ax25_cb *);
@@ -314,11 +317,23 @@ extern int  ax25_validate_nr(ax25_cb *, unsigned short);
 extern int  ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *);
 extern void ax25_send_control(ax25_cb *, int, int, int);
 extern void ax25_return_dm(struct device *, ax25_address *, ax25_address *, ax25_digi *);
-extern unsigned short ax25_calculate_t1(ax25_cb *);
+extern void ax25_calculate_t1(ax25_cb *);
 extern void ax25_calculate_rtt(ax25_cb *);
+extern void ax25_disconnect(ax25_cb *, int);
 
 /* ax25_timer.c */
-extern void ax25_set_timer(ax25_cb *);
+extern void ax25_start_heartbeat(ax25_cb *);
+extern void ax25_start_t1timer(ax25_cb *);
+extern void ax25_start_t2timer(ax25_cb *);
+extern void ax25_start_t3timer(ax25_cb *);
+extern void ax25_start_idletimer(ax25_cb *);
+extern void ax25_stop_heartbeat(ax25_cb *);
+extern void ax25_stop_t1timer(ax25_cb *);
+extern void ax25_stop_t2timer(ax25_cb *);
+extern void ax25_stop_t3timer(ax25_cb *);
+extern void ax25_stop_idletimer(ax25_cb *);
+extern int  ax25_t1timer_running(ax25_cb *);
+extern unsigned long ax25_display_timer(struct timer_list *);
 
 /* ax25_uid.c */
 extern int  ax25_uid_policy;
index f06583cee778486eb16e7600df32dab90683f2d0..7cc9b3452abb3e4b562ab35db9141acf23c2bb57 100644 (file)
@@ -2,8 +2,6 @@
 #define _LAPB_H 
 #include <linux/lapb.h>
 
-#define LAPB_SLOWHZ    10              /* Run timing at 1/10 second */
-
 #define        LAPB_HEADER_LEN 20              /* LAPB over Ethernet + a bit more */
 
 #define        LAPB_ACK_PENDING_CONDITION      0x01
@@ -58,10 +56,10 @@ enum {
 };
 
 #define        LAPB_DEFAULT_MODE               (LAPB_STANDARD | LAPB_SLP | LAPB_DTE)
-#define        LAPB_DEFAULT_WINDOW             7                       /* Window=7 */
-#define        LAPB_DEFAULT_T1                 (5 * LAPB_SLOWHZ)       /* T1=5s    */
-#define        LAPB_DEFAULT_T2                 (1 * LAPB_SLOWHZ)       /* T2=1s    */
-#define        LAPB_DEFAULT_N2                 20                      /* N2=20    */
+#define        LAPB_DEFAULT_WINDOW             7               /* Window=7 */
+#define        LAPB_DEFAULT_T1                 (5 * HZ)        /* T1=5s    */
+#define        LAPB_DEFAULT_T2                 (1 * HZ)        /* T2=1s    */
+#define        LAPB_DEFAULT_N2                 20              /* N2=20    */
 
 #define        LAPB_SMODULUS   8
 #define        LAPB_EMODULUS   128
@@ -91,14 +89,12 @@ typedef struct lapb_cb {
        unsigned char           condition;
        unsigned short          n2, n2count;
        unsigned short          t1, t2;
-       unsigned short          t1timer, t2timer;
+       struct timer_list       t1timer, t2timer;
 
        /* Internal control information */
-       struct sk_buff_head     input_queue;
        struct sk_buff_head     write_queue;
        struct sk_buff_head     ack_queue;
        unsigned char           window;
-       struct timer_list       timer;
        struct lapb_register_struct callbacks;
 
        /* FRMR control information */
@@ -136,7 +132,11 @@ extern void lapb_send_control(lapb_cb *, int, int, int);
 extern void lapb_transmit_frmr(lapb_cb *);
 
 /* lapb_timer.c */
-extern void lapb_set_timer(lapb_cb *);
+extern void lapb_start_t1timer(lapb_cb *);
+extern void lapb_start_t2timer(lapb_cb *);
+extern void lapb_stop_t1timer(lapb_cb *);
+extern void lapb_stop_t2timer(lapb_cb *);
+extern int  lapb_t1timer_running(lapb_cb *);
 
 /*
  * Debug levels.
index 8a255660aab2505f4a97fb0a042899677d72ef21..cc9fc842c0ac71b168a99f719916dd76af270627 100644 (file)
@@ -8,8 +8,6 @@
 #define _NETROM_H 
 #include <linux/netrom.h>
 
-#define        NR_SLOWHZ                       10      /* Run timing at 1/10 second */
-
 #define        NR_NETWORK_LEN                  15
 #define        NR_TRANSPORT_LEN                5
 
@@ -40,17 +38,17 @@ enum {
 #define        NR_COND_PEER_RX_BUSY            0x04
 #define        NR_COND_OWN_RX_BUSY             0x08
 
-#define NR_DEFAULT_T1                  (120 * NR_SLOWHZ)       /* Outstanding frames - 120 seconds */
-#define NR_DEFAULT_T2                  (5   * NR_SLOWHZ)       /* Response delay     - 5 seconds */
-#define NR_DEFAULT_N2                  3                       /* Number of Retries - 3 */
-#define        NR_DEFAULT_T4                   (180 * NR_SLOWHZ)       /* Busy Delay - 180 seconds */
-#define        NR_DEFAULT_IDLE                 (20* 60 * NR_SLOWHZ)    /* No Activuty Timeout - 900 seconds*/
-#define        NR_DEFAULT_WINDOW               4                       /* Default Window Size - 4 */
-#define        NR_DEFAULT_OBS                  6                       /* Default Obsolescence Count - 6 */
-#define        NR_DEFAULT_QUAL                 10                      /* Default Neighbour Quality - 10 */
-#define        NR_DEFAULT_TTL                  16                      /* Default Time To Live - 16 */
-#define        NR_DEFAULT_ROUTING              1                       /* Is routing enabled ? */
-#define        NR_DEFAULT_FAILS                2                       /* Link fails until route fails */
+#define NR_DEFAULT_T1                  (120 * HZ)      /* Outstanding frames - 120 seconds */
+#define NR_DEFAULT_T2                  (5   * HZ)      /* Response delay     - 5 seconds */
+#define NR_DEFAULT_N2                  3               /* Number of Retries - 3 */
+#define        NR_DEFAULT_T4                   (180 * HZ)      /* Busy Delay - 180 seconds */
+#define        NR_DEFAULT_IDLE                 (0 * 60 * HZ)   /* No Activity Timeout - none */
+#define        NR_DEFAULT_WINDOW               4               /* Default Window Size - 4 */
+#define        NR_DEFAULT_OBS                  6               /* Default Obsolescence Count - 6 */
+#define        NR_DEFAULT_QUAL                 10              /* Default Neighbour Quality - 10 */
+#define        NR_DEFAULT_TTL                  16              /* Default Time To Live - 16 */
+#define        NR_DEFAULT_ROUTING              1               /* Is routing enabled ? */
+#define        NR_DEFAULT_FAILS                2               /* Link fails until route fails */
 
 #define NR_MODULUS                     256
 #define NR_MAX_WINDOW_SIZE             127                     /* Maximum Window Allowable - 127 */
@@ -64,9 +62,12 @@ typedef struct {
        unsigned char           state, condition, bpqext, window;
        unsigned short          vs, vr, va, vl;
        unsigned char           n2, n2count;
-       unsigned short          t1, t2, t4, idle;
-       unsigned short          t1timer, t2timer, t4timer, idletimer;
+       unsigned long           t1, t2, t4, idle;
        unsigned short          fraglen;
+       struct timer_list       t1timer;
+       struct timer_list       t2timer;
+       struct timer_list       t4timer;
+       struct timer_list       idletimer;
        struct sk_buff_head     ack_queue;
        struct sk_buff_head     reseq_queue;
        struct sk_buff_head     frag_queue;
@@ -77,6 +78,7 @@ struct nr_neigh {
        struct nr_neigh *next;
        ax25_address    callsign;
        ax25_digi       *digipeat;
+       ax25_cb         *ax25;
        struct device   *dev;
        unsigned char   quality;
        unsigned char   locked;
@@ -138,7 +140,7 @@ extern void nr_rt_device_down(struct device *);
 extern struct device *nr_dev_first(void);
 extern struct device *nr_dev_get(ax25_address *);
 extern int  nr_rt_ioctl(unsigned int, void *);
-extern void nr_link_failed(ax25_address *, struct device *);
+extern void nr_link_failed(ax25_cb *, int);
 extern int  nr_route_frame(struct sk_buff *, ax25_cb *);
 extern int  nr_nodes_get_info(char *, char **, off_t, int, int);
 extern int  nr_neigh_get_info(char *, char **, off_t, int, int);
@@ -152,9 +154,20 @@ extern int  nr_validate_nr(struct sock *, unsigned short);
 extern int  nr_in_rx_window(struct sock *, unsigned short);
 extern void nr_write_internal(struct sock *, int);
 extern void nr_transmit_dm(struct sk_buff *);
+extern void nr_disconnect(struct sock *, int);
 
 /* nr_timer.c */
-extern void nr_set_timer(struct sock *);
+extern void nr_start_heartbeat(struct sock *);
+extern void nr_start_t1timer(struct sock *);
+extern void nr_start_t2timer(struct sock *);
+extern void nr_start_t4timer(struct sock *);
+extern void nr_start_idletimer(struct sock *);
+extern void nr_stop_heartbeat(struct sock *);
+extern void nr_stop_t1timer(struct sock *);
+extern void nr_stop_t2timer(struct sock *);
+extern void nr_stop_t4timer(struct sock *);
+extern void nr_stop_idletimer(struct sock *);
+extern int  nr_t1timer_running(struct sock *);
 
 /* sysctl_net_netrom.c */
 extern void nr_register_sysctl(void);
index 1e60cfa8fc6184261c9a8731f9afdd92bc43906e..86f6a6721f72f4dde3723c3a4c7b8dbf98b9b5a4 100644 (file)
@@ -8,8 +8,6 @@
 #define _ROSE_H 
 #include <linux/rose.h>
 
-#define        ROSE_SLOWHZ                     10      /* Run timing at 1/10 second */
-
 #define        ROSE_ADDR_LEN                   5
 
 #define        ROSE_MIN_LEN                    3
@@ -45,22 +43,23 @@ enum {
        ROSE_STATE_1,                   /* Awaiting Call Accepted */
        ROSE_STATE_2,                   /* Awaiting Clear Confirmation */
        ROSE_STATE_3,                   /* Data Transfer */
-       ROSE_STATE_4                    /* Awaiting Reset Confirmation */
+       ROSE_STATE_4,                   /* Awaiting Reset Confirmation */
+       ROSE_STATE_5                    /* Deferred Call Acceptance */
 };
 
-#define ROSE_DEFAULT_T0                        (180 * ROSE_SLOWHZ)     /* Default T10 T20 value */
-#define ROSE_DEFAULT_T1                        (200 * ROSE_SLOWHZ)     /* Default T11 T21 value */
-#define ROSE_DEFAULT_T2                        (180 * ROSE_SLOWHZ)     /* Default T12 T22 value */
-#define        ROSE_DEFAULT_T3                 (180 * ROSE_SLOWHZ)     /* Default T13 T23 value */
-#define        ROSE_DEFAULT_HB                 (5 * ROSE_SLOWHZ)       /* Default Holdback value */
-#define        ROSE_DEFAULT_IDLE               (20 * 60 * ROSE_SLOWHZ) /* Default No Activity value */
-#define        ROSE_DEFAULT_ROUTING            1                       /* Default routing flag */
-#define        ROSE_DEFAULT_FAIL_TIMEOUT       (120 * ROSE_SLOWHZ)     /* Time until link considered usable */
-#define        ROSE_DEFAULT_MAXVC              50                      /* Maximum number of VCs per neighbour */
-#define        ROSE_DEFAULT_WINDOW_SIZE        3                       /* Default window size */
+#define ROSE_DEFAULT_T0                        (180 * HZ)      /* Default T10 T20 value */
+#define ROSE_DEFAULT_T1                        (200 * HZ)      /* Default T11 T21 value */
+#define ROSE_DEFAULT_T2                        (180 * HZ)      /* Default T12 T22 value */
+#define        ROSE_DEFAULT_T3                 (180 * HZ)      /* Default T13 T23 value */
+#define        ROSE_DEFAULT_HB                 (5 * HZ)        /* Default Holdback value */
+#define        ROSE_DEFAULT_IDLE               (0 * 60 * HZ)   /* No Activity Timeout - none */
+#define        ROSE_DEFAULT_ROUTING            1               /* Default routing flag */
+#define        ROSE_DEFAULT_FAIL_TIMEOUT       (120 * HZ)      /* Time until link considered usable */
+#define        ROSE_DEFAULT_MAXVC              50              /* Maximum number of VCs per neighbour */
+#define        ROSE_DEFAULT_WINDOW_SIZE        3               /* Default window size */
 
 #define ROSE_MODULUS                   8
-#define        ROSE_MAX_PACKET_SIZE            256                     /* Maximum packet size */
+#define        ROSE_MAX_PACKET_SIZE            251             /* Maximum packet size */
 
 #define        ROSE_COND_ACK_PENDING           0x01
 #define        ROSE_COND_PEER_RX_BUSY          0x02
@@ -81,14 +80,16 @@ struct rose_neigh {
        struct rose_neigh       *next;
        ax25_address            callsign;
        ax25_digi               *digipeat;
+       ax25_cb                 *ax25;
        struct device           *dev;
        unsigned short          count;
+       unsigned short          use;
        unsigned int            number;
        char                    restarted;
        char                    dce_mode;
        struct sk_buff_head     queue;
-       unsigned short          t0timer, ftimer;
-       struct timer_list       timer;
+       struct timer_list       t0timer;
+       struct timer_list       ftimer;
 };
 
 struct rose_node {
@@ -124,11 +125,13 @@ typedef struct {
        struct rose_neigh       *neighbour;
        struct device           *device;
        unsigned int            lci, rand;
-       unsigned char           state, condition, qbitincl;
+       unsigned char           state, condition, qbitincl, defer;
+       unsigned char           cause, diagnostic;
        unsigned short          vs, vr, va, vl;
-       unsigned short          timer;
-       unsigned short          t1, t2, t3, hb, idle;
+       unsigned long           t1, t2, t3, hb, idle;
        unsigned short          fraglen;
+       struct timer_list       timer;
+       struct timer_list       idletimer;
        struct sk_buff_head     frag_queue;
        struct sock             *sk;            /* Backlink to socket */
 } rose_cb;
@@ -164,12 +167,17 @@ extern int  rose_init(struct device *);
 extern int  rose_process_rx_frame(struct sock *, struct sk_buff *);
 
 /* rose_link.c */
-extern void rose_link_set_timer(struct rose_neigh *);
+extern void rose_start_ftimer(struct rose_neigh *);
+extern void rose_start_t0timer(struct rose_neigh *);
+extern void rose_stop_ftimer(struct rose_neigh *);
+extern void rose_stop_t0timer(struct rose_neigh *);
+extern int  rose_ftimer_running(struct rose_neigh *);
+extern int  rose_t0timer_running(struct rose_neigh *);
 extern void rose_link_rx_restart(struct sk_buff *, struct rose_neigh *, unsigned short);
 extern void rose_transmit_restart_request(struct rose_neigh *);
 extern void rose_transmit_restart_confirmation(struct rose_neigh *);
 extern void rose_transmit_diagnostic(struct rose_neigh *, unsigned char);
-extern void rose_transmit_clear_request(struct rose_neigh *, unsigned int, unsigned char);
+extern void rose_transmit_clear_request(struct rose_neigh *, unsigned int, unsigned char, unsigned char);
 extern void rose_transmit_link(struct sk_buff *, struct rose_neigh *);
 
 /* rose_out.c */
@@ -185,9 +193,9 @@ extern struct device *rose_dev_first(void);
 extern struct device *rose_dev_get(rose_address *);
 extern struct rose_route *rose_route_free_lci(unsigned int, struct rose_neigh *);
 extern struct device *rose_ax25_dev_get(char *);
-extern struct rose_neigh *rose_get_neigh(rose_address *);
+extern struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *, unsigned char *);
 extern int  rose_rt_ioctl(unsigned int, void *);
-extern void rose_link_failed(ax25_address *, struct device *);
+extern void rose_link_failed(ax25_cb *, int);
 extern int  rose_route_frame(struct sk_buff *, ax25_cb *);
 extern int  rose_nodes_get_info(char *, char **, off_t, int, int);
 extern int  rose_neigh_get_info(char *, char **, off_t, int, int);
@@ -201,9 +209,18 @@ extern void rose_write_internal(struct sock *, int);
 extern int  rose_decode(struct sk_buff *, int *, int *, int *, int *, int *);
 extern int  rose_parse_facilities(struct sk_buff *, struct rose_facilities *);
 extern int  rose_create_facilities(unsigned char *, rose_cb *);
+extern void rose_disconnect(struct sock *, int, int, int);
 
 /* rose_timer.c */
-extern void rose_set_timer(struct sock *);
+extern void rose_start_heartbeat(struct sock *);
+extern void rose_start_t1timer(struct sock *);
+extern void rose_start_t2timer(struct sock *);
+extern void rose_start_t3timer(struct sock *);
+extern void rose_start_hbtimer(struct sock *);
+extern void rose_start_idletimer(struct sock *);
+extern void rose_stop_heartbeat(struct sock *);
+extern void rose_stop_timer(struct sock *);
+extern void rose_stop_idletimer(struct sock *);
 
 /* sysctl_net_rose.c */
 extern void rose_register_sysctl(void);
index cb1ae8bee6c0dc0a632da9706739cc27a523868d..7b58ad4e30e878fc28cd47cc9483dd8501a79920 100644 (file)
@@ -8,8 +8,6 @@
 #define _X25_H 
 #include <linux/x25.h>
 
-#define        X25_SLOWHZ                      1       /* Run timing at 1 Hz */
-
 #define        X25_ADDR_LEN                    16
 
 #define        X25_MAX_L2_LEN                  18      /* 802.2 LLC */
@@ -67,11 +65,11 @@ enum {
        X25_LINK_STATE_3
 };
 
-#define X25_DEFAULT_T20                (180 * X25_SLOWHZ)      /* Default T20 value */
-#define X25_DEFAULT_T21                (200 * X25_SLOWHZ)      /* Default T21 value */
-#define X25_DEFAULT_T22                (180 * X25_SLOWHZ)      /* Default T22 value */
-#define        X25_DEFAULT_T23         (180 * X25_SLOWHZ)      /* Default T23 value */
-#define        X25_DEFAULT_T2          (3   * X25_SLOWHZ)      /* Default ack holdback value */
+#define X25_DEFAULT_T20                (180 * HZ)              /* Default T20 value */
+#define X25_DEFAULT_T21                (200 * HZ)              /* Default T21 value */
+#define X25_DEFAULT_T22                (180 * HZ)              /* Default T22 value */
+#define        X25_DEFAULT_T23         (180 * HZ)              /* Default T23 value */
+#define        X25_DEFAULT_T2          (3   * HZ)              /* Default ack holdback value */
 
 #define        X25_DEFAULT_WINDOW_SIZE 2                       /* Default Window Size  */
 #define        X25_DEFAULT_PACKET_SIZE X25_PS128               /* Default Packet Size */
@@ -113,8 +111,8 @@ struct x25_neigh {
        unsigned int            state;
        unsigned int            extended;
        struct sk_buff_head     queue;
-       unsigned short          t20, t20timer;
-       struct timer_list       timer;
+       unsigned long           t20;
+       struct timer_list       t20timer;
 };
 
 typedef struct {
@@ -123,13 +121,14 @@ typedef struct {
        unsigned int            lci;
        unsigned char           state, condition, qbitincl, intflag;
        unsigned short          vs, vr, va, vl;
-       unsigned short          timer;
-       unsigned short          t2, t21, t22, t23;
+       unsigned long           t2, t21, t22, t23;
        unsigned short          fraglen;
        struct sk_buff_head     fragment_queue;
        struct sk_buff_head     interrupt_in_queue;
        struct sk_buff_head     interrupt_out_queue;
        struct sock             *sk;            /* Backlink to socket */
+       struct timer_list       timer;
+       struct x25_causediag    causediag;
        struct x25_facilities   facilities;
        struct x25_calluserdata calluserdata;
 } x25_cb;
@@ -143,8 +142,8 @@ extern int  sysctl_x25_ack_holdback_timeout;
 
 extern int  x25_addr_ntoa(unsigned char *, x25_address *, x25_address *);
 extern int  x25_addr_aton(unsigned char *, x25_address *, x25_address *);
-extern unsigned int x25_new_lci(void);
-extern struct sock *x25_find_socket(unsigned int);
+extern unsigned int x25_new_lci(struct x25_neigh *);
+extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
 extern void x25_destroy_socket(struct sock *);
 extern int  x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int);
 
@@ -199,9 +198,17 @@ extern void x25_clear_queues(struct sock *);
 extern int  x25_validate_nr(struct sock *, unsigned short);
 extern void x25_write_internal(struct sock *, int);
 extern int  x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *);
+extern void x25_disconnect(struct sock *, int, unsigned char, unsigned char);
 
 /* x25_timer.c */
-extern void x25_set_timer(struct sock *);
+extern void x25_start_heartbeat(struct sock *);
+extern void x25_start_t2timer(struct sock *);
+extern void x25_start_t21timer(struct sock *);
+extern void x25_start_t22timer(struct sock *);
+extern void x25_start_t23timer(struct sock *);
+extern void x25_stop_heartbeat(struct sock *);
+extern void x25_stop_timer(struct sock *);
+extern unsigned long x25_display_timer(struct sock *);
 
 /* sysctl_net_x25.c */
 extern void x25_register_sysctl(void);
index 18dd86698d47d0939cbe09746b8c8adb837a845c..bb1f0391d01c816e3d750f59decb1ad931abe6de 100644 (file)
@@ -404,8 +404,8 @@ static inline void __exit_fs(struct task_struct *tsk)
        if (fs) {
                tsk->fs = NULL;
                if (!--fs->count) {
-                       iput(fs->root);
-                       iput(fs->pwd);
+                       dput(fs->root);
+                       dput(fs->pwd);
                        kfree(fs);
                }
        }
index c3bcf7cca5afe36d06b16743d0bd267b75076371..97837db6571405272ba196fd160848df2eb69da2 100644 (file)
@@ -302,10 +302,8 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
                return -1;
        tsk->fs->count = 1;
        tsk->fs->umask = current->fs->umask;
-       if ((tsk->fs->root = current->fs->root))
-               atomic_inc(&tsk->fs->root->i_count);
-       if ((tsk->fs->pwd = current->fs->pwd))
-               atomic_inc(&tsk->fs->pwd->i_count);
+       tsk->fs->root = dget(current->fs->root);
+       tsk->fs->pwd = dget(current->fs->pwd);
        return 0;
 }
 
index 8bd9d269dd659026a097e683d290f9db9e428654..b5c2b4d0abb9b2b9fed2b2e484a3bda1c180f221 100644 (file)
@@ -141,9 +141,10 @@ EXPORT_SYMBOL(update_vm_cache);
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(putname);
 EXPORT_SYMBOL(__fput);
-EXPORT_SYMBOL(__iget);
+EXPORT_SYMBOL(iget);
 EXPORT_SYMBOL(_iput);
-EXPORT_SYMBOL(namei);
+EXPORT_SYMBOL(__namei);
+EXPORT_SYMBOL(lookup_dentry);
 EXPORT_SYMBOL(open_namei);
 EXPORT_SYMBOL(sys_close);
 EXPORT_SYMBOL(close_fp);
@@ -341,7 +342,6 @@ EXPORT_SYMBOL(set_writetime);
 EXPORT_SYMBOL(sys_tz);
 EXPORT_SYMBOL(__wait_on_super);
 EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(_free_ibasket);
 EXPORT_SYMBOL(_clear_inode);
 EXPORT_SYMBOL(refile_buffer);
 EXPORT_SYMBOL(nr_async_pages);
index 885539b5c69c0da2f101ecf2da3ca020631d056e..c584eb3ae8e7a81ec283b0729737ff1a7f39aef0 100644 (file)
@@ -79,7 +79,8 @@ get_mod_name(const char *user_name, char **buf)
        unsigned long page;
        long retval;
 
-       if ((unsigned long)user_name >= TASK_SIZE)
+       if ((unsigned long)user_name >= TASK_SIZE
+           && get_fs () != KERNEL_DS)
                return -EFAULT;
 
        page = __get_free_page(GFP_KERNEL);
@@ -134,7 +135,7 @@ sys_create_module(const char *name_user, size_t size)
                error = -EEXIST;
                goto err1;
        }
-       if ((mod = (struct module *)vmalloc(size)) == NULL) {
+       if ((mod = (struct module *)module_map(size)) == NULL) {
                error = -ENOMEM;
                goto err1;
        }
@@ -685,6 +686,7 @@ sys_get_kernel_syms(struct kernel_sym *table)
 {
        struct module *mod;
        int i;
+       struct kernel_sym ksym;
 
        lock_kernel();
        for (mod = module_list, i = 0; mod; mod = mod->next) {
@@ -695,8 +697,10 @@ sys_get_kernel_syms(struct kernel_sym *table)
        if (table == NULL)
                goto out;
 
+       /* So that we don't give the user our stack content */
+       memset (&ksym, 0, sizeof (ksym));
+
        for (mod = module_list, i = 0; mod; mod = mod->next) {
-               struct kernel_sym ksym;
                struct module_symbol *msym;
                unsigned int j;
 
@@ -790,7 +794,7 @@ free_module(struct module *mod)
 
        /* And free the memory.  */
 
-       vfree(mod);
+       module_unmap(mod);
 }
 
 /*
index e4bdcfc1ad33c5cf9e42e6770974cee1a4d4d9ac..a5f5c68f546779dea538cc9c20678bf2ca9d5e6a 100644 (file)
@@ -103,6 +103,7 @@ struct inode_operations proc_sys_inode_operations =
        NULL,           /* mknod */
        NULL,           /* rename */
        NULL,           /* readlink */
+       NULL,           /* follow_link */
        NULL,           /* readpage */
        NULL,           /* writepage */
        NULL,           /* bmap */
index 761f7e4e661ffdfcf87cdb61a7968097164c0723..4386adcb82439ada4cb39e7ec65d7f31bd4fe0c4 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -311,6 +311,8 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
        if (correct_wcount)
                file->f_inode->i_writecount++;
        merge_segments(mm, vma->vm_start, vma->vm_end);
+       
+       addr = vma->vm_start;
 
        /* merge_segments might have merged our vma, so we can't use it any more */
        mm->total_vm += len >> PAGE_SHIFT;
index b79c7165695cfad83e8bd352a2fcdd4a44b2086c..7bd9755c74655270d677c245c807001b17cf547a 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1615,7 +1615,7 @@ kmalloc(size_t size, int flags)
 }
 
 void
-kfree(void *objp)
+kfree(const void *objp)
 {
        struct page *page;
        int     nr;
index 4a6addce1b9155114f7626de347c2b608cc881f7..eae481821becb60140965b8da92c834f2f50ad80 100644 (file)
@@ -334,7 +334,7 @@ asmlinkage int sys_swapoff(const char * specialfile)
        lock_kernel();
        if (!suser())
                goto out;
-       err = namei(NAM_FOLLOW_LINK, specialfile, &inode);
+       err = namei(specialfile, &inode);
        if (err)
                goto out;
        prev = -1;
@@ -488,13 +488,10 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
        } else {
                p->prio = --least_priority;
        }
-       error = namei(NAM_FOLLOW_LINK, specialfile, &swap_inode);
+       error = namei(specialfile, &swap_inode);
        if (error)
                goto bad_swap_2;
        p->swap_file = swap_inode;
-       error = -EBUSY;
-       if (atomic_read(&swap_inode->i_count) != 1)
-               goto bad_swap_2;
        error = -EINVAL;
 
        if (S_ISBLK(swap_inode->i_mode)) {
index 71afe1aea1347a94a4e5289bc09f51c0f9705dfd..d0270d58677ae1a3fa14b907a318b1678fbc025d 100644 (file)
@@ -68,7 +68,7 @@ static inline void free_area_pmd(pgd_t * dir, unsigned long address, unsigned lo
        }
 }
 
-static void free_area_pages(unsigned long address, unsigned long size)
+void vmfree_area_pages(unsigned long address, unsigned long size)
 {
        pgd_t * dir;
        unsigned long end = address + size;
@@ -125,7 +125,7 @@ static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned lo
        return 0;
 }
 
-static int alloc_area_pages(unsigned long address, unsigned long size)
+int vmalloc_area_pages(unsigned long address, unsigned long size)
 {
        pgd_t * dir;
        unsigned long end = address + size;
@@ -181,7 +181,7 @@ void vfree(void * addr)
        for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
                if (tmp->addr == addr) {
                        *p = tmp->next;
-                       free_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
+                       vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
                        kfree(tmp);
                        return;
                }
@@ -201,7 +201,7 @@ void * vmalloc(unsigned long size)
        if (!area)
                return NULL;
        addr = area->addr;
-       if (alloc_area_pages(VMALLOC_VMADDR(addr), size)) {
+       if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size)) {
                vfree(addr);
                return NULL;
        }
index 09924ff8939eabb76f96a6786e97cc999a5233f0..53382aacb923bb712e43347b8ecda2a5e43fcb07 100644 (file)
@@ -113,9 +113,6 @@ else
   endif
 endif
 
-# We must attach netsyms.o to socket.o, as otherwise there is nothing
-# to pull the object file from the archive.
-
 SOCK         := socket.o
 ifeq ($(CONFIG_NET),y)
 ifeq ($(CONFIG_MODULES),y)
index a88ccfc5aa805e9c696d92094eee27673fc216dd..1cd7f5331561cdc604a941a8c4fe03479756015d 100644 (file)
@@ -6,19 +6,19 @@ Code Section          Bug Report Contact
 802 [other     ]       alan@lxorguk.ukuu.org.uk        
     [token ring        ]       pnorton@cts.com
 appletalk              alan@lxorguk.ukuu.org.uk and netatalk@umich.edu
-ax25                   jsn@cs.nott.ac.uk
+ax25                   g4klx@g4klx.demon.co.uk
 core                   alan@lxorguk.ukuu.org.uk
 decnet                 SteveW@ACM.org
 ethernet               alan@lxorguk.ukuu.org.uk
 ipv4                   davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
 ipv6                   davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
 ipx                    alan@lxorguk.ukuu.org.uk,greg@caldera.com
-lapb                   jsn@cs.nott.ac.uk
-netrom                 jsn@cs.nott.ac.uk
-rose                   jsn@cs.nott.ac.uk
+lapb                   g4klx@g4klx.demon.co.uk
+netrom                 g4klx@g4klx.demon.co.uk
+rose                   g4klx@g4klx.demon.co.uk
 wanrouter              genek@compuserve.com and dm@sangoma.com
 unix                   alan@lxorguk.ukuu.org.uk
-x25                    jsn@cs.nott.ac.uk
+x25                    g4klx@g4klx.demon.co.uk
 
 
        If in doubt contact me <alan@lxorguk.ukuu.org.uk> first.
index 37b679600f9b6b754df67fc77606c013f8657fdd..8e5992747e10af23fb7f831a70be72afe8799109 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -92,6 +92,7 @@
  *     AX.25 036       Jonathan(G4KLX)         Major restructuring.
  *                     Joerg(DL1BKE)           Fixed DAMA Slave.
  *                     Jonathan(G4KLX)         Fix widlcard listen parameter setting.
+ *     AX.25 037       Jonathan(G4KLX)         New timer architecture.
  */
 
 #include <linux/config.h>
@@ -161,8 +162,7 @@ static void ax25_remove_socket(ax25_cb *ax25)
        ax25_cb *s;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        if ((s = ax25_list) == ax25) {
                ax25_list = s->next;
@@ -196,16 +196,8 @@ static void ax25_kill_by_device(struct device *dev)
 
        for (s = ax25_list; s != NULL; s = s->next) {
                if (s->ax25_dev == ax25_dev) {
-                       s->state    = AX25_STATE_0;
                        s->ax25_dev = NULL;
-                       if (s->sk != NULL) {
-                               s->sk->state     = TCP_CLOSE;
-                               s->sk->err       = ENETUNREACH;
-                               s->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!s->sk->dead)
-                                       s->sk->state_change(s->sk);
-                               s->sk->dead  = 1;
-                       }
+                       ax25_disconnect(s, ENETUNREACH);
                }
        }
 }
@@ -308,7 +300,7 @@ struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, in
  *     Find an AX.25 control block given both ends. It will only pick up
  *     floating AX.25 control blocks or non Raw socket bound control blocks.
  */
-ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev)
+ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev)
 {
        ax25_cb *s;
        unsigned long flags;
@@ -319,11 +311,16 @@ ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi
        for (s = ax25_list; s != NULL; s = s->next) {
                if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET)
                        continue;
-               if (ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) {
-                       if (digi != NULL) {
-                               if (s->digipeat == NULL && digi->ndigi != 0)
+               if (s->ax25_dev == NULL)
+                       continue;
+               if (ax25cmp(&s->source_addr, src_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) {
+                       if (digi != NULL && digi->ndigi != 0) {
+                               if (s->digipeat == NULL)
                                        continue;
-                               if (s->digipeat != NULL && ax25digicmp(s->digipeat, digi) != 0)
+                               if (ax25digicmp(s->digipeat, digi) != 0)
+                                       continue;
+                       } else {
+                               if (s->digipeat != NULL && s->digipeat->ndigi != 0)
                                        continue;
                        }
                        restore_flags(flags);
@@ -402,10 +399,13 @@ void ax25_destroy_socket(ax25_cb *ax25)   /* Not static as it's used by the timer
        struct sk_buff *skb;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
-       del_timer(&ax25->timer);
+       ax25_stop_heartbeat(ax25);
+       ax25_stop_t1timer(ax25);
+       ax25_stop_t2timer(ax25);
+       ax25_stop_t3timer(ax25);
+       ax25_stop_idletimer(ax25);
 
        ax25_remove_socket(ax25);
        ax25_clear_queues(ax25);        /* Flush the queues */
@@ -414,7 +414,7 @@ void ax25_destroy_socket(ax25_cb *ax25)     /* Not static as it's used by the timer
                while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) {
                        if (skb->sk != ax25->sk) {                      /* A pending connection */
                                skb->sk->dead = 1;      /* Queue the unaccepted socket for death */
-                               ax25_set_timer(skb->sk->protinfo.ax25);
+                               ax25_start_heartbeat(skb->sk->protinfo.ax25);
                                skb->sk->protinfo.ax25->state = AX25_STATE_0;
                        }
 
@@ -451,13 +451,9 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
        struct ax25_ctl_struct ax25_ctl;
        ax25_dev *ax25_dev;
        ax25_cb *ax25;
-       unsigned long flags;
-       int err;
-
-       if ((err = verify_area(VERIFY_READ, arg, sizeof(ax25_ctl))) != 0)
-               return err;
 
-       copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl));
+       if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
+               return -EFAULT;
 
        if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
                return -ENODEV;
@@ -467,22 +463,12 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
 
        switch (ax25_ctl.cmd) {
                case AX25_KILL:
-                       ax25_clear_queues(ax25);
                        ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-                       ax25->state = AX25_STATE_0;
 #ifdef CONFIG_AX25_DAMA_SLAVE
                        if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
                                ax25_dama_off(ax25);
 #endif
-                       if (ax25->sk != NULL) {
-                               ax25->sk->state     = TCP_CLOSE;
-                               ax25->sk->err       = ENETRESET;
-                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!ax25->sk->dead)
-                                       ax25->sk->state_change(ax25->sk);
-                               ax25->sk->dead  = 1;
-                       }
-                       ax25_set_timer(ax25);
+                       ax25_disconnect(ax25, ENETRESET);
                        break;
 
                case AX25_WINDOW:
@@ -499,22 +485,14 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
                case AX25_T1:
                        if (ax25_ctl.arg < 1)
                                return -EINVAL;
-                       ax25->rtt = (ax25_ctl.arg * AX25_SLOWHZ) / 2;
-                       ax25->t1 = ax25_ctl.arg * AX25_SLOWHZ;
-                       save_flags(flags); cli();
-                       if (ax25->t1timer > ax25->t1)
-                               ax25->t1timer = ax25->t1;
-                       restore_flags(flags);
+                       ax25->rtt = (ax25_ctl.arg * HZ) / 2;
+                       ax25->t1  = ax25_ctl.arg * HZ;
                        break;
 
                case AX25_T2:
                        if (ax25_ctl.arg < 1)
                                return -EINVAL;
-                       save_flags(flags); cli();
-                       ax25->t2 = ax25_ctl.arg * AX25_SLOWHZ;
-                       if (ax25->t2timer > ax25->t2)
-                               ax25->t2timer = ax25->t2;
-                       restore_flags(flags);
+                       ax25->t2 = ax25_ctl.arg * HZ;
                        break;
 
                case AX25_N2:
@@ -527,21 +505,13 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
                case AX25_T3:
                        if (ax25_ctl.arg < 0)
                                return -EINVAL;
-                       save_flags(flags); cli();
-                       ax25->t3 = ax25_ctl.arg * AX25_SLOWHZ;
-                       if (ax25->t3timer != 0)
-                               ax25->t3timer = ax25->t3;
-                       restore_flags(flags);
+                       ax25->t3 = ax25_ctl.arg * HZ;
                        break;
 
                case AX25_IDLE:
                        if (ax25_ctl.arg < 0)
                                return -EINVAL;
-                       save_flags(flags); cli();
-                       ax25->idle = ax25_ctl.arg * AX25_SLOWHZ * 60;
-                       if (ax25->idletimer != 0)
-                               ax25->idletimer = ax25->idle;
-                       restore_flags(flags);
+                       ax25->idle = ax25_ctl.arg * 60 * HZ;
                        break;
 
                case AX25_PACLEN:
@@ -622,6 +592,10 @@ ax25_cb *ax25_create_cb(void)
        skb_queue_head_init(&ax25->reseq_queue);
 
        init_timer(&ax25->timer);
+       init_timer(&ax25->t1timer);
+       init_timer(&ax25->t2timer);
+       init_timer(&ax25->t3timer);
+       init_timer(&ax25->idletimer);
 
        ax25_fillin_cb(ax25, NULL);
 
@@ -664,13 +638,14 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
                case AX25_T1:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.ax25->rtt = (opt * AX25_SLOWHZ) / 2;
+                       sk->protinfo.ax25->rtt = (opt * HZ) / 2;
+                       sk->protinfo.ax25->t1  = opt * HZ;
                        return 0;
 
                case AX25_T2:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.ax25->t2 = opt * AX25_SLOWHZ;
+                       sk->protinfo.ax25->t2 = opt * HZ;
                        return 0;
 
                case AX25_N2:
@@ -682,13 +657,13 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
                case AX25_T3:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.ax25->t3 = opt * AX25_SLOWHZ;
+                       sk->protinfo.ax25->t3 = opt * HZ;
                        return 0;
 
                case AX25_IDLE:
                        if (opt < 0)
                                return -EINVAL;
-                       sk->protinfo.ax25->idle = opt * AX25_SLOWHZ * 60;
+                       sk->protinfo.ax25->idle = opt * 60 * HZ;
                        return 0;
 
                case AX25_BACKOFF:
@@ -738,11 +713,11 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
                        break;
 
                case AX25_T1:
-                       val = (sk->protinfo.ax25->t1 * 2) / AX25_SLOWHZ;
+                       val = sk->protinfo.ax25->t1 / HZ;
                        break;
 
                case AX25_T2:
-                       val = sk->protinfo.ax25->t2 / AX25_SLOWHZ;
+                       val = sk->protinfo.ax25->t2 / HZ;
                        break;
 
                case AX25_N2:
@@ -750,11 +725,11 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
                        break;
 
                case AX25_T3:
-                       val = sk->protinfo.ax25->t3 / AX25_SLOWHZ;
+                       val = sk->protinfo.ax25->t3 / HZ;
                        break;
 
                case AX25_IDLE:
-                       val = sk->protinfo.ax25->idle / (AX25_SLOWHZ * 60);
+                       val = sk->protinfo.ax25->idle / (60 * HZ);
                        break;
 
                case AX25_BACKOFF:
@@ -963,22 +938,14 @@ static int ax25_release(struct socket *sock, struct socket *peer)
        if (sk->type == SOCK_SEQPACKET) {
                switch (sk->protinfo.ax25->state) {
                        case AX25_STATE_0:
-                               sk->state       = TCP_CLOSE;
-                               sk->shutdown   |= SEND_SHUTDOWN;
-                               sk->state_change(sk);
-                               sk->dead        = 1;
+                               ax25_disconnect(sk->protinfo.ax25, 0);
                                ax25_destroy_socket(sk->protinfo.ax25);
                                break;
 
                        case AX25_STATE_1:
                        case AX25_STATE_2:
-                               ax25_clear_queues(sk->protinfo.ax25);
                                ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-                               sk->protinfo.ax25->state = AX25_STATE_0;
-                               sk->state                = TCP_CLOSE;
-                               sk->shutdown            |= SEND_SHUTDOWN;
-                               sk->state_change(sk);
-                               sk->dead                 = 1;
+                               ax25_disconnect(sk->protinfo.ax25, 0);
                                ax25_destroy_socket(sk->protinfo.ax25);
                                break;
 
@@ -990,31 +957,34 @@ static int ax25_release(struct socket *sock, struct socket *peer)
                                        case AX25_PROTO_STD_SIMPLEX:
                                        case AX25_PROTO_STD_DUPLEX:
                                                ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-                                               sk->protinfo.ax25->t3timer = 0;
+                                               ax25_stop_t2timer(sk->protinfo.ax25);
+                                               ax25_stop_t3timer(sk->protinfo.ax25);
+                                               ax25_stop_idletimer(sk->protinfo.ax25);
                                                break;
 #ifdef AX25_CONFIG_DAMA_SLAVE
                                        case AX25_PROTO_DAMA_SLAVE:
-                                               sk->protinfo.ax25->t3timer = 0;
+                                               ax25_stop_t3timer(sk->protinfo.ax25);
                                                break;
 #endif
                                }
-                               sk->protinfo.ax25->t1timer = sk->protinfo.ax25->t1 = ax25_calculate_t1(sk->protinfo.ax25);
-                               sk->protinfo.ax25->state   = AX25_STATE_2;
-                               sk->state                  = TCP_CLOSE;
-                               sk->shutdown              |= SEND_SHUTDOWN;
+                               ax25_calculate_t1(sk->protinfo.ax25);
+                               ax25_start_t1timer(sk->protinfo.ax25);
+                               sk->protinfo.ax25->state = AX25_STATE_2;
+                               sk->state                = TCP_CLOSE;
+                               sk->shutdown            |= SEND_SHUTDOWN;
                                sk->state_change(sk);
-                               sk->dead                   = 1;
-                               sk->destroy                = 1;
+                               sk->dead                 = 1;
+                               sk->destroy              = 1;
                                break;
 
                        default:
                                break;
                }
        } else {
-               sk->state       = TCP_CLOSE;
-               sk->shutdown   |= SEND_SHUTDOWN;
+               sk->state     = TCP_CLOSE;
+               sk->shutdown |= SEND_SHUTDOWN;
                sk->state_change(sk);
-               sk->dead        = 1;
+               sk->dead      = 1;
                ax25_destroy_socket(sk->protinfo.ax25);
        }
 
@@ -1092,8 +1062,9 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
 {
        struct sock *sk = sock->sk;
-       struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
-       int err;
+       struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
+       ax25_digi *digi = NULL;
+       int ct = 0, err;
 
        if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
                sock->state = SS_CONNECTED;
@@ -1114,36 +1085,36 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
                return -EINVAL;
 
-       if (addr->sax25_family != AF_AX25)
+       if (fsa->fsa_ax25.sax25_family != AF_AX25)
                return -EINVAL;
 
+       if (sk->protinfo.ax25->digipeat != NULL) {
+               kfree(sk->protinfo.ax25->digipeat);
+               sk->protinfo.ax25->digipeat = NULL;
+       }
+
        /*
         *      Handle digi-peaters to be used.
         */
-       if (addr_len == sizeof(struct full_sockaddr_ax25) && addr->sax25_ndigis != 0) {
-               int ct           = 0;
-               struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)addr;
-
+       if (addr_len == sizeof(struct full_sockaddr_ax25) && fsa->fsa_ax25.sax25_ndigis != 0) {
                /* Valid number of digipeaters ? */
-               if (addr->sax25_ndigis < 1 || addr->sax25_ndigis > AX25_MAX_DIGIS)
+               if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS)
                        return -EINVAL;
 
-               if (sk->protinfo.ax25->digipeat == NULL) {
-                       if ((sk->protinfo.ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL)
-                               return -ENOBUFS;
-               }
+               if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL)
+                       return -ENOBUFS;
 
-               sk->protinfo.ax25->digipeat->ndigi      = addr->sax25_ndigis;
-               sk->protinfo.ax25->digipeat->lastrepeat = -1;
+               digi->ndigi      = fsa->fsa_ax25.sax25_ndigis;
+               digi->lastrepeat = -1;
 
-               while (ct < addr->sax25_ndigis) {
+               while (ct < fsa->fsa_ax25.sax25_ndigis) {
                        if ((fsa->fsa_digipeater[ct].ax25_call[6] & AX25_HBIT) && sk->protinfo.ax25->iamdigi) {
-                               sk->protinfo.ax25->digipeat->repeated[ct] = 1;
-                               sk->protinfo.ax25->digipeat->lastrepeat   = ct;
+                               digi->repeated[ct] = 1;
+                               digi->lastrepeat   = ct;
                        } else {
-                               sk->protinfo.ax25->digipeat->repeated[ct] = 0;
+                               digi->repeated[ct] = 0;
                        }
-                       sk->protinfo.ax25->digipeat->calls[ct] = fsa->fsa_digipeater[ct];
+                       digi->calls[ct] = fsa->fsa_digipeater[ct];
                        ct++;
                }
        }
@@ -1154,7 +1125,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
         *      been filled in, error if it hasn't.
         */
        if (sk->zapped) {
-               if ((err = ax25_rt_autobind(sk->protinfo.ax25, &addr->sax25_call)) < 0)
+               if ((err = ax25_rt_autobind(sk->protinfo.ax25, &fsa->fsa_ax25.sax25_call)) < 0)
                        return err;
                ax25_fillin_cb(sk->protinfo.ax25, sk->protinfo.ax25->ax25_dev);
                ax25_insert_socket(sk->protinfo.ax25);
@@ -1163,10 +1134,13 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
                        return -EHOSTUNREACH;
        }
 
-       if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &addr->sax25_call, NULL, sk->protinfo.ax25->ax25_dev->dev) != NULL)
+       if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, sk->protinfo.ax25->ax25_dev->dev) != NULL) {
+               if (digi != NULL) kfree(digi);
                return -EADDRINUSE;                     /* Already such a connection */
+       }
 
-       sk->protinfo.ax25->dest_addr = addr->sax25_call;
+       sk->protinfo.ax25->dest_addr = fsa->fsa_ax25.sax25_call;
+       sk->protinfo.ax25->digipeat  = digi;
 
        /* First the easy one */
        if (sk->type != SOCK_SEQPACKET) {
@@ -1198,7 +1172,8 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        }
 
        sk->protinfo.ax25->state = AX25_STATE_1;
-       ax25_set_timer(sk->protinfo.ax25);              /* Start going SABM SABM until a UA or a give up and DM */
+
+       ax25_start_heartbeat(sk->protinfo.ax25);
 
        /* Now the loop */
        if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -1532,38 +1507,35 @@ static int ax25_shutdown(struct socket *sk, int how)
 static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
-       struct ax25_info_struct ax25_info;
-       int err;
-       long amount = 0;
 
        switch (cmd) {
-               case TIOCOUTQ:
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0)
-                               return err;
+               case TIOCOUTQ: {
+                       long amount;
                        amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
                        if (amount < 0)
                                amount = 0;
-                       put_user(amount, (int *)arg);
+                       if (put_user(amount, (int *)arg))
+                               return -EFAULT;
                        return 0;
+               }
 
                case TIOCINQ: {
                        struct sk_buff *skb;
+                       long amount = 0L;
                        /* These two are safe on a single CPU system as only user tasks fiddle here */
                        if ((skb = skb_peek(&sk->receive_queue)) != NULL)
                                amount = skb->len;
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0)
-                               return err;
-                       put_user(amount, (int *)arg);
+                       if (put_user(amount, (int *)arg))
+                               return -EFAULT;
                        return 0;
                }
 
                case SIOCGSTAMP:
                        if (sk != NULL) {
-                               if (sk->stamp.tv_sec==0)
+                               if (sk->stamp.tv_sec == 0)
                                        return -ENOENT;
-                               if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0)
-                                       return err;
-                               copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval));
+                               if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+                                       return -EFAULT;
                                return 0;
                        }
                        return -EINVAL;
@@ -1572,22 +1544,22 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                case SIOCAX25DELUID:    /* Delete a uid from the uid/call map table */
                case SIOCAX25GETUID: {
                        struct sockaddr_ax25 sax25;
-                       if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(struct sockaddr_ax25))) != 0)
-                               return err;
-                       copy_from_user(&sax25, (void *)arg, sizeof(sax25));
+                       if (copy_from_user(&sax25, (void *)arg, sizeof(sax25)))
+                               return -EFAULT;
                        return ax25_uid_ioctl(cmd, &sax25);
                }
 
-               case SIOCAX25NOUID:     /* Set the default policy (default/bar) */
-                       if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(unsigned long))) != 0)
-                               return err;
+               case SIOCAX25NOUID: {   /* Set the default policy (default/bar) */
+                       long amount;
                        if (!suser())
                                return -EPERM;
-                       get_user(amount, (long *)arg);
+                       if (get_user(amount, (long *)arg))
+                               return -EFAULT;
                        if (amount > AX25_NOUID_BLOCK)
                                return -EINVAL;
                        ax25_uid_policy = amount;
                        return 0;
+               }
 
                case SIOCADDRT:
                case SIOCDELRT:
@@ -1601,33 +1573,33 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                                return -EPERM;
                        return ax25_ctl_ioctl(cmd, (void *)arg);
 
-               case SIOCAX25GETINFO:
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(ax25_info))) != 0)
-                               return err;
-                       ax25_info.t1        = sk->protinfo.ax25->t1;
-                       ax25_info.t2        = sk->protinfo.ax25->t2;
-                       ax25_info.t3        = sk->protinfo.ax25->t3;
-                       ax25_info.idle      = sk->protinfo.ax25->idle;
+               case SIOCAX25GETINFO: {
+                       struct ax25_info_struct ax25_info;
+                       ax25_info.t1        = sk->protinfo.ax25->t1   / HZ;
+                       ax25_info.t2        = sk->protinfo.ax25->t2   / HZ;
+                       ax25_info.t3        = sk->protinfo.ax25->t3   / HZ;
+                       ax25_info.idle      = sk->protinfo.ax25->idle / (60 * HZ);
                        ax25_info.n2        = sk->protinfo.ax25->n2;
-                       ax25_info.t1timer   = sk->protinfo.ax25->t1timer;
-                       ax25_info.t2timer   = sk->protinfo.ax25->t2timer;
-                       ax25_info.t3timer   = sk->protinfo.ax25->t3timer;
-                       ax25_info.idletimer = sk->protinfo.ax25->idletimer;
+                       ax25_info.t1timer   = ax25_display_timer(&sk->protinfo.ax25->t1timer)   / HZ;
+                       ax25_info.t2timer   = ax25_display_timer(&sk->protinfo.ax25->t2timer)   / HZ;
+                       ax25_info.t3timer   = ax25_display_timer(&sk->protinfo.ax25->t3timer)   / HZ;
+                       ax25_info.idletimer = ax25_display_timer(&sk->protinfo.ax25->idletimer) / (60 * HZ);
                        ax25_info.n2count   = sk->protinfo.ax25->n2count;
                        ax25_info.state     = sk->protinfo.ax25->state;
                        ax25_info.rcv_q     = atomic_read(&sk->rmem_alloc);
                        ax25_info.snd_q     = atomic_read(&sk->wmem_alloc);
-                       copy_to_user((void *)arg, &ax25_info, sizeof(ax25_info));
+                       if (copy_to_user((void *)arg, &ax25_info, sizeof(ax25_info)))
+                               return -EFAULT;
                        return 0;
+               }
 
                case SIOCAX25ADDFWD:
                case SIOCAX25DELFWD: {
                        struct ax25_fwd_struct ax25_fwd;
                        if (!suser())
                                return -EPERM;
-                       if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_fwd))) != 0)
-                               return err;
-                       copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd));
+                       if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd)))
+                               return -EFAULT;
                        return ax25_fwd_ioctl(cmd, &ax25_fwd);
                }
 
@@ -1655,13 +1627,14 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i
 {
        ax25_cb *ax25;
        const char *devname;
+       char callbuf[15];
        int len = 0;
        off_t pos = 0;
        off_t begin = 0;
 
        cli();
 
-       len += sprintf(buffer, "dest_addr src_addr  dev  st  vs  vr  va    t1     t2     t3      idle   n2  rtt wnd paclen   Snd-Q Rcv-Q\n");
+       len += sprintf(buffer, "dest_addr src_addr   dev  st  vs  vr  va    t1     t2     t3      idle   n2  rtt wnd paclen   Snd-Q Rcv-Q\n");
 
        for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {
                if (ax25->ax25_dev == NULL)
@@ -1671,20 +1644,28 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i
 
                len += sprintf(buffer + len, "%-9s ",
                        ax2asc(&ax25->dest_addr));
-               len += sprintf(buffer + len, "%-9s %-4s %2d %3d %3d %3d %3d/%03d %2d/%02d %3d/%03d %3d/%03d %2d/%02d %3d %3d  %5d",
-                       ax2asc(&ax25->source_addr), devname,
+
+               sprintf(callbuf, "%s%c", ax2asc(&ax25->source_addr),
+                                        (ax25->iamdigi) ? '*' : ' ');
+
+               len += sprintf(buffer + len, "%-10s %-4s %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3lu %3d  %5d",
+                       callbuf,
+                       devname,
                        ax25->state,
-                       ax25->vs, ax25->vr, ax25->va,
-                       ax25->t1timer / AX25_SLOWHZ,
-                       ax25->t1      / AX25_SLOWHZ,
-                       ax25->t2timer / AX25_SLOWHZ,
-                       ax25->t2      / AX25_SLOWHZ,
-                       ax25->t3timer / AX25_SLOWHZ,
-                       ax25->t3      / AX25_SLOWHZ,
-                       ax25->idletimer / (AX25_SLOWHZ * 60),
-                       ax25->idle      / (AX25_SLOWHZ * 60),
-                       ax25->n2count, ax25->n2,
-                       ax25->rtt     / AX25_SLOWHZ,
+                       ax25->vs,
+                       ax25->vr,
+                       ax25->va,
+                       ax25_display_timer(&ax25->t1timer) / HZ,
+                       ax25->t1 / HZ,
+                       ax25_display_timer(&ax25->t2timer) / HZ,
+                       ax25->t2 / HZ,
+                       ax25_display_timer(&ax25->t3timer) / HZ,
+                       ax25->t3 / HZ,
+                       ax25_display_timer(&ax25->idletimer) / (60 * HZ), 
+                       ax25->idle / (60 * HZ),
+                       ax25->n2count,
+                       ax25->n2,
+                       ax25->rtt / HZ,
                        ax25->window,
                        ax25->paclen);
 
@@ -1764,7 +1745,7 @@ static struct notifier_block ax25_dev_notifier = {
 EXPORT_SYMBOL(ax25_encapsulate);
 EXPORT_SYMBOL(ax25_rebuild_header);
 EXPORT_SYMBOL(ax25_findbyuid);
-EXPORT_SYMBOL(ax25_link_up);
+EXPORT_SYMBOL(ax25_find_cb);
 EXPORT_SYMBOL(ax25_linkfail_register);
 EXPORT_SYMBOL(ax25_linkfail_release);
 EXPORT_SYMBOL(ax25_listen_register);
@@ -1777,6 +1758,7 @@ EXPORT_SYMBOL(ax25cmp);
 EXPORT_SYMBOL(ax2asc);
 EXPORT_SYMBOL(asc2ax);
 EXPORT_SYMBOL(null_ax25_address);
+EXPORT_SYMBOL(ax25_display_timer);
 
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_ax25_route = {
@@ -1815,7 +1797,7 @@ __initfunc(void ax25_proto_init(struct net_proto *pro))
        proc_net_register(&proc_ax25_calls);
 #endif
 
-       printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.36 for Linux NET3.038 (Linux 2.1)\n");
+       printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET3.038 (Linux 2.1)\n");
 }
 
 #ifdef MODULE
index 77bfabe73257a5e45b2b9e9406ca7049a2c8bd4a..5daf92fa5c16eea0e0c51cb8e815f37c9725a309 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -165,27 +165,23 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
 
        if (len < 14) return NULL;
 
-       if (flags != NULL) {
-               *flags = 0;
+       *flags = 0;
 
-               if (buf[6] & AX25_CBIT)
-                       *flags = AX25_COMMAND;
-               if (buf[13] & AX25_CBIT)
-                       *flags = AX25_RESPONSE;
-       }
+       if (buf[6] & AX25_CBIT)
+               *flags = AX25_COMMAND;
+       if (buf[13] & AX25_CBIT)
+               *flags = AX25_RESPONSE;
 
        if (dama != NULL) 
                *dama = ~buf[13] & AX25_DAMA_FLAG;
 
        /* Copy to, from */
-       if (dest != NULL) 
-               memcpy(dest, buf + 0, AX25_ADDR_LEN);
-
-       if (src != NULL)  
-               memcpy(src,  buf + 7, AX25_ADDR_LEN);
+       memcpy(dest, buf + 0, AX25_ADDR_LEN);
+       memcpy(src,  buf + 7, AX25_ADDR_LEN);
 
        buf += 2 * AX25_ADDR_LEN;
        len -= 2 * AX25_ADDR_LEN;
+
        digi->lastrepeat = -1;
        digi->ndigi      = 0;
 
@@ -193,15 +189,14 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
                if (d >= AX25_MAX_DIGIS)  return NULL;  /* Max of 6 digis */
                if (len < 7) return NULL;       /* Short packet */
 
-               if (digi != NULL) {
-                       memcpy(&digi->calls[d], buf, AX25_ADDR_LEN);
-                       digi->ndigi = d + 1;
-                       if (buf[6] & AX25_HBIT) {
-                               digi->repeated[d] = 1;
-                               digi->lastrepeat  = d;
-                       } else {
-                               digi->repeated[d] = 0;
-                       }
+               memcpy(&digi->calls[d], buf, AX25_ADDR_LEN);
+               digi->ndigi = d + 1;
+
+               if (buf[6] & AX25_HBIT) {
+                       digi->repeated[d] = 1;
+                       digi->lastrepeat  = d;
+               } else {
+                       digi->repeated[d] = 0;
                }
 
                buf += AX25_ADDR_LEN;
@@ -285,15 +280,15 @@ int ax25_addr_size(ax25_digi *dp)
  */
 void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
 {
-       int ct = 0;
+       int ct;
 
        out->ndigi      = in->ndigi;
        out->lastrepeat = in->ndigi - in->lastrepeat - 2;
 
        /* Invert the digipeaters */
+       for (ct = 0; ct < in->ndigi; ct++) {
+               out->calls[ct] = in->calls[in->ndigi - ct - 1];
 
-       while (ct < in->ndigi) {
-               out->calls[ct]    = in->calls[in->ndigi - ct - 1];
                if (ct <= out->lastrepeat) {
                        out->calls[ct].ax25_call[6] |= AX25_HBIT;
                        out->repeated[ct]            = 1;
@@ -301,7 +296,6 @@ void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
                        out->calls[ct].ax25_call[6] &= ~AX25_HBIT;
                        out->repeated[ct]            = 0;
                }
-               ct++;
        }
 }
 
index 6468faf773489babf9091432829eecedfce16301..3f4f46ad4dc3426342e0d3055f80bf68637be940 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
index 1394c9ab78f24cdedc93064881e9a2fa99a32765..6b5e68236add8298bf8858d2dd2364892abc0e1d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -18,6 +18,7 @@
  *     History
  *     AX.25 036       Jonathan(G4KLX) Cloned from ax25_in.c
  *                     Joerg(DL1BKE)   Fixed it.
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -64,9 +65,9 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
 
                case AX25_UA:
                        ax25_calculate_rtt(ax25);
-                       ax25->t1timer = 0;
-                       ax25->t3timer = ax25->t3;
-                       ax25->idletimer = ax25->idle;
+                       ax25_stop_t1timer(ax25);
+                       ax25_start_t3timer(ax25);
+                       ax25_start_idletimer(ax25);
                        ax25->vs      = 0;
                        ax25->va      = 0;
                        ax25->vr      = 0;
@@ -90,23 +91,11 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                        break;
 
                case AX25_DM:
-                       if (pf) {
-                               ax25_clear_queues(ax25);
-                               ax25->state = AX25_STATE_0;
-                               if (ax25->sk != NULL) {
-                                       ax25->sk->state     = TCP_CLOSE;
-                                       ax25->sk->err       = ECONNREFUSED;
-                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                       if (!ax25->sk->dead)
-                                               ax25->sk->state_change(ax25->sk);
-                                       ax25->sk->dead      = 1;
-                               }
-                       }
+                       if (pf) ax25_disconnect(ax25, ECONNREFUSED);
                        break;
 
                default:
-                       if (pf)
-                               ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
+                       if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
                        break;
        }
 
@@ -128,31 +117,15 @@ static int ax25_ds_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
 
                case AX25_DISC:
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-                       ax25->state = AX25_STATE_0;
                        ax25_dama_off(ax25);
-                       if (ax25->sk != NULL) {
-                               ax25->sk->state     = TCP_CLOSE;
-                               ax25->sk->err       = 0;
-                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!ax25->sk->dead)
-                                       ax25->sk->state_change(ax25->sk);
-                               ax25->sk->dead      = 1;
-                       }
+                       ax25_disconnect(ax25, 0);
                        break;
 
                case AX25_DM:
                case AX25_UA:
                        if (pf) {
-                               ax25->state = AX25_STATE_0;
                                ax25_dama_off(ax25);
-                               if (ax25->sk != NULL) {
-                                       ax25->sk->state     = TCP_CLOSE;
-                                       ax25->sk->err       = 0;
-                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                       if (!ax25->sk->dead)
-                                               ax25->sk->state_change(ax25->sk);
-                                       ax25->sk->dead      = 1;
-                               }
+                               ax25_disconnect(ax25, 0);
                        }
                        break;
 
@@ -187,10 +160,10 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                        ax25->modulus   = AX25_MODULUS;
                        ax25->window    = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       ax25_stop_t1timer(ax25);
+                       ax25_start_t3timer(ax25);
+                       ax25_start_idletimer(ax25);
                        ax25->condition = 0x00;
-                       ax25->t1timer   = 0;
-                       ax25->t3timer   = ax25->t3;
-                       ax25->idletimer = ax25->idle;
                        ax25->vs        = 0;
                        ax25->va        = 0;
                        ax25->vr        = 0;
@@ -199,34 +172,14 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                        break;
 
                case AX25_DISC:
-                       ax25_clear_queues(ax25);
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-                       ax25->t3timer = 0;
-                       ax25->state   = AX25_STATE_0;
                        ax25_dama_off(ax25);
-                       if (ax25->sk != NULL) {
-                               ax25->sk->state     = TCP_CLOSE;
-                               ax25->sk->err       = 0;
-                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!ax25->sk->dead)
-                                       ax25->sk->state_change(ax25->sk);
-                               ax25->sk->dead      = 1;
-                       }
+                       ax25_disconnect(ax25, 0);
                        break;
 
                case AX25_DM:
-                       ax25_clear_queues(ax25);
-                       ax25->t3timer = 0;
-                       ax25->state   = AX25_STATE_0;
                        ax25_dama_off(ax25);
-                       if (ax25->sk != NULL) {
-                               ax25->sk->state     = TCP_CLOSE;
-                               ax25->sk->err       = ECONNRESET;
-                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!ax25->sk->dead)
-                                       ax25->sk->state_change(ax25->sk);
-                               ax25->sk->dead      = 1;
-                       }
+                       ax25_disconnect(ax25, ECONNRESET);
                        break;
 
                case AX25_RR:
@@ -250,9 +203,9 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                        if (ax25_validate_nr(ax25, nr)) {
                                ax25_frames_acked(ax25, nr);
                                ax25_calculate_rtt(ax25);
+                               ax25_stop_t1timer(ax25);
+                               ax25_start_t3timer(ax25);
                                ax25->n2count = 0;
-                               ax25->t1timer = 0;
-                               ax25->t3timer = ax25->t3;
                                ax25_requeue_frames(ax25);
                                if (type == AX25_COMMAND && pf)
                                        ax25_ds_enquiry_response(ax25);
@@ -281,18 +234,15 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                        if (ns == ax25->vr) {
                                ax25->vr = (ax25->vr + 1) % AX25_MODULUS;
                                queued = ax25_rx_iframe(ax25, skb);
-                               if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+                               if (ax25->condition & AX25_COND_OWN_RX_BUSY)
                                        ax25->vr = ns;  /* ax25->vr - 1 */
-                                       if (pf) ax25_ds_enquiry_response(ax25);
-                                       break;
-                               }
                                ax25->condition &= ~AX25_COND_REJECT;
                                if (pf) {
                                        ax25_ds_enquiry_response(ax25);
                                } else {
                                        if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
-                                               ax25->t2timer = ax25->t2;
                                                ax25->condition |= AX25_COND_ACK_PENDING;
+                                               ax25_start_t2timer(ax25);
                                        }
                                }
                        } else {
index 6037f16b48c72af533e9c39e86a740e2f3a1a166..89ca64f3fbce42023aad0d63b049efb02fa456c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -19,6 +19,7 @@
  *     AX.25 036       Jonathan(G4KLX) Cloned from ax25_out.c and ax25_subr.c.
  *                     Joerg(DL1BKE)   Changed ax25_ds_enquiry_response(),
  *                                     fixed ax25_dama_on() and ax25_dama_off().
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -91,7 +92,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
        else
                ax25->n2count = 0;
 
-       ax25->t3timer = ax25->t3;
+       ax25_start_t3timer(ax25);
        ax25_ds_set_timer(ax25->ax25_dev);
 
        for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
@@ -114,7 +115,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
                if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 || skb_peek(&ax25o->ack_queue) != NULL)
                        ax25_ds_t1_timeout(ax25o);
 
-               ax25o->t3timer = ax25o->t3;
+               ax25_start_t3timer(ax25o);
        }
 }
 
@@ -122,9 +123,10 @@ void ax25_ds_establish_data_link(ax25_cb *ax25)
 {
        ax25->condition &= AX25_COND_DAMA_MODE;
        ax25->n2count    = 0;
-       ax25->t3timer    = ax25->t3;
-       ax25->t2timer    = 0;
-       ax25->t1timer    = ax25->t1 = ax25_calculate_t1(ax25);
+       ax25_calculate_t1(ax25);
+       ax25_start_t1timer(ax25);
+       ax25_stop_t2timer(ax25);
+       ax25_start_t3timer(ax25);
 }
 
 /*
index 847be57908b9f9cee8614e612ac9dc4c37016f57..841149996770106b3d96b7e937cdff1da0824b12 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -12,6 +12,7 @@
  *     History
  *     AX.25 036       Jonathan(G4KLX) Cloned from ax25_timer.c.
  *                     Joerg(DL1BKE)   Added DAMA Slave Timeout timer
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -93,41 +94,21 @@ static void ax25_ds_timeout(unsigned long arg)
                if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
                        continue;
 
-               ax25_link_failed(&ax25->dest_addr, ax25_dev->dev);
-               ax25_clear_queues(ax25);
                ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-               ax25->state = AX25_STATE_0;
-
-               if (ax25->sk != NULL) {
-                       SOCK_DEBUG(ax25->sk, "AX.25 DAMA Slave Timeout\n");
-                       ax25->sk->state     = TCP_CLOSE;
-                       ax25->sk->err       = ETIMEDOUT;
-                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                       if (!ax25->sk->dead)
-                               ax25->sk->state_change(ax25->sk);
-                       ax25->sk->dead      = 1;
-               }
-               
-               ax25_set_timer(ax25);   /* notify socket... */
+               ax25_disconnect(ax25, ETIMEDOUT);
        }
        
        ax25_dev_dama_off(ax25_dev);
 }
 
-/*
- *     AX.25 TIMER 
- *
- *     This routine is called every 100ms. Decrement timer by this
- *     amount - if expired then process the event.
- */
-void ax25_ds_timer(ax25_cb *ax25)
+void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
 {
        switch (ax25->state) {
+
                case AX25_STATE_0:
                        /* Magic here: If we listen() and a new link dies before it
                           is accepted() it isn't 'dead' so doesn't get removed. */
                        if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
-                               del_timer(&ax25->timer);
                                ax25_destroy_socket(ax25);
                                return;
                        }
@@ -144,71 +125,51 @@ void ax25_ds_timer(ax25_cb *ax25)
                                }
                        }
                        break;
-
-               default:
-                       break;
-       }
-       
-       /* dl1bke 960114: T3 works much like the IDLE timeout, but
-        *                gets reloaded with every frame for this
-        *                connection.
-        */
-
-       if (ax25->t3timer > 0 && --ax25->t3timer == 0) {
-               ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
-               ax25_clear_queues(ax25);
-               ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-
-               ax25->state = AX25_STATE_0;
-               ax25_dama_off(ax25);
-
-               if (ax25->sk != NULL) {
-                       SOCK_DEBUG(ax25->sk, "AX.25 T3 Timeout\n");
-                       ax25->sk->state     = TCP_CLOSE;
-                       ax25->sk->err       = ETIMEDOUT;
-                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                       if (!ax25->sk->dead)
-                               ax25->sk->state_change(ax25->sk);
-                       ax25->sk->dead      = 1;
-               }
-
-               ax25_set_timer(ax25);
-
-               return;
        }
 
-       /* dl1bke 960228: close the connection when IDLE expires.
-        *                unlike T3 this timer gets reloaded only on
-        *                I frames.
-        */
-
-       if (ax25->idletimer > 0 && --ax25->idletimer == 0) {
-               ax25_clear_queues(ax25);
-
-               ax25->n2count = 0;
-               ax25->t3timer = ax25->t3;
+       ax25_start_heartbeat(ax25);
+}
+       
+/* dl1bke 960114: T3 works much like the IDLE timeout, but
+ *                gets reloaded with every frame for this
+ *               connection.
+ */
+void ax25_ds_t3timer_expiry(ax25_cb *ax25)
+{
+       ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+       ax25_dama_off(ax25);
+       ax25_disconnect(ax25, ETIMEDOUT);
+}
 
-               /* state 1 or 2 should not happen, but... */
+/* dl1bke 960228: close the connection when IDLE expires.
+ *               unlike T3 this timer gets reloaded only on
+ *               I frames.
+ */
+void ax25_ds_idletimer_expiry(ax25_cb *ax25)
+{
+       ax25_clear_queues(ax25);
 
-               if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2)
-                       ax25->state = AX25_STATE_0;
-               else
-                       ax25->state = AX25_STATE_2;
+       ax25->n2count = 0;
 
-               ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+       /* state 1 or 2 should not happen, but... */
 
-               if (ax25->sk != NULL) {
-                       ax25->sk->state     = TCP_CLOSE;
-                       ax25->sk->err       = 0;
-                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                       if (!ax25->sk->dead)
-                               ax25->sk->state_change(ax25->sk);
-                       ax25->sk->dead      = 1;
-                       ax25->sk->destroy   = 1;
-               }
+       if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2)
+               ax25->state = AX25_STATE_0;
+       else
+               ax25->state = AX25_STATE_2;
+
+       ax25_calculate_t1(ax25);
+       ax25_start_t1timer(ax25);
+       ax25_start_t3timer(ax25);
+
+       if (ax25->sk != NULL) {
+               ax25->sk->state     = TCP_CLOSE;
+               ax25->sk->err       = 0;
+               ax25->sk->shutdown |= SEND_SHUTDOWN;
+               if (!ax25->sk->dead)
+                       ax25->sk->state_change(ax25->sk);
+               ax25->sk->dead      = 1;
        }
-
-       ax25_set_timer(ax25);
 }
 
 /* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
@@ -222,20 +183,12 @@ void ax25_ds_timer(ax25_cb *ax25)
 void ax25_ds_t1_timeout(ax25_cb *ax25)
 {      
        switch (ax25->state) {
+
                case AX25_STATE_1: 
                        if (ax25->n2count == ax25->n2) {
                                if (ax25->modulus == AX25_MODULUS) {
-                                       ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
-                                       ax25_clear_queues(ax25);
-                                       ax25->state = AX25_STATE_0;
-                                       if (ax25->sk != NULL) {
-                                               ax25->sk->state     = TCP_CLOSE;
-                                               ax25->sk->err       = ETIMEDOUT;
-                                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                               if (!ax25->sk->dead)
-                                                       ax25->sk->state_change(ax25->sk);
-                                               ax25->sk->dead      = 1;
-                                       }
+                                       ax25_disconnect(ax25, ETIMEDOUT);
+                                       return;
                                } else {
                                        ax25->modulus = AX25_MODULUS;
                                        ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
@@ -253,19 +206,9 @@ void ax25_ds_t1_timeout(ax25_cb *ax25)
 
                case AX25_STATE_2:
                        if (ax25->n2count == ax25->n2) {
-                               ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
-                               ax25_clear_queues(ax25);
-                               ax25->state = AX25_STATE_0;
                                ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-
-                               if (ax25->sk != NULL) {
-                                       ax25->sk->state     = TCP_CLOSE;
-                                       ax25->sk->err       = ETIMEDOUT;
-                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                       if (!ax25->sk->dead)
-                                               ax25->sk->state_change(ax25->sk);
-                                       ax25->sk->dead      = 1;
-                               }
+                               ax25_disconnect(ax25, ETIMEDOUT);
+                               return;
                        } else {
                                ax25->n2count++;
                        }
@@ -273,28 +216,17 @@ void ax25_ds_t1_timeout(ax25_cb *ax25)
 
                case AX25_STATE_3:
                        if (ax25->n2count == ax25->n2) {
-                               ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
-                               ax25_clear_queues(ax25);
                                ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
-                               ax25->state = AX25_STATE_0;
-                               if (ax25->sk != NULL) {
-                                       SOCK_DEBUG(ax25->sk, "AX.25 link Failure\n");
-                                       ax25->sk->state     = TCP_CLOSE;
-                                       ax25->sk->err       = ETIMEDOUT;
-                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                       if (!ax25->sk->dead)
-                                               ax25->sk->state_change(ax25->sk);
-                                       ax25->sk->dead      = 1;
-                               }
+                               ax25_disconnect(ax25, ETIMEDOUT);
+                               return;
                        } else {
                                ax25->n2count++;
                        }
                        break;
        }
 
-       ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
-
-       ax25_set_timer(ax25);
+       ax25_calculate_t1(ax25);
+       ax25_start_t1timer(ax25);
 }
 
 #endif
index d27a3af2367174ec1d2b90951acee3b645960387..7e6ad845c4e00e4fa2ec28c8b5619c5bb5a49298 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -44,7 +44,7 @@ static struct protocol_struct {
 
 static struct linkfail_struct {
        struct linkfail_struct *next;
-       void (*func)(ax25_address *, struct device *);
+       void (*func)(ax25_cb *, int);
 } *linkfail_list = NULL;
 
 static struct listen_struct {
@@ -114,7 +114,7 @@ void ax25_protocol_release(unsigned int pid)
        restore_flags(flags);
 }
 
-int ax25_linkfail_register(void (*func)(ax25_address *, struct device *))
+int ax25_linkfail_register(void (*func)(ax25_cb *, int))
 {
        struct linkfail_struct *linkfail;
        unsigned long flags;
@@ -135,7 +135,7 @@ int ax25_linkfail_register(void (*func)(ax25_address *, struct device *))
        return 1;
 }
 
-void ax25_linkfail_release(void (*func)(ax25_address *, struct device *))
+void ax25_linkfail_release(void (*func)(ax25_cb *, int))
 {
        struct linkfail_struct *s, *linkfail = linkfail_list;
        unsigned long flags;
@@ -248,21 +248,12 @@ int ax25_listen_mine(ax25_address *callsign, struct device *dev)
        return 0;
 }
 
-void ax25_link_failed(ax25_address *callsign, struct device *dev)
+void ax25_link_failed(ax25_cb *ax25, int reason)
 {
        struct linkfail_struct *linkfail;
 
        for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
-               (linkfail->func)(callsign, dev);
-}
-
-/*
- *     Return the state of an AX.25 link given source, destination, and
- *     device.
- */
-int ax25_link_up(ax25_address *src, ax25_address *dest, ax25_digi *digi, struct device *dev)
-{
-       return ax25_find_cb(src, dest, digi, dev) != NULL;
+               (linkfail->func)(ax25, reason);
 }
 
 int ax25_protocol_is_registered(unsigned int pid)
index 2e6090d7644367b6fd9426de8a1b184ad6c3102c..a17109bff862766f1afd535dec816134de2a82d4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -35,6 +35,7 @@
  *     AX.25 035       Hans(PE1AYX)    Fixed interface to IP layer.
  *     AX.25 036       Jonathan(G4KLX) Move DAMA code into own file.
  *                     Joerg(DL1BKE)   Fixed DAMA Slave.
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -136,7 +137,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
 
        if (skb == NULL) return 0;
 
-       ax25->idletimer = ax25->idle;
+       ax25_start_idletimer(ax25);
 
        pid = *skb->data;
 
@@ -193,8 +194,6 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
        if (ax25->state == AX25_STATE_0)
                return 0;
 
-       del_timer(&ax25->timer);
-
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
                case AX25_PROTO_STD_SIMPLEX:
                case AX25_PROTO_STD_DUPLEX:
@@ -211,8 +210,6 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
 #endif
        }
 
-       ax25_set_timer(ax25);
-
        return queued;
 }
 
@@ -413,7 +410,6 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                }
 
                ax25_fillin_cb(ax25, ax25_dev);
-               ax25->idletimer = ax25->idle;
        }
 
        ax25->source_addr = dest;
@@ -453,12 +449,13 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                ax25_dama_on(ax25);
 #endif
 
-       ax25->t3timer = ax25->t3;
-       ax25->state   = AX25_STATE_3;
+       ax25->state = AX25_STATE_3;
 
        ax25_insert_socket(ax25);
 
-       ax25_set_timer(ax25);
+       ax25_start_heartbeat(ax25);
+       ax25_start_t3timer(ax25);
+       ax25_start_idletimer(ax25);
 
        if (sk != NULL) {
                if (!sk->dead)
index 009428fa9a4d05b06e00614f090ada9666d42c44..d26f008dddb7b288193a5a300f2966a6886aa082 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -105,20 +105,25 @@ int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short typ
 int ax25_rebuild_header(struct sk_buff *skb)
 {
        struct sk_buff *ourskb;
-       int mode;
        unsigned char *bp  = skb->data;
        struct device *dev = skb->dev;
+       ax25_address *src, *dst;
+       ax25_route *route;
        ax25_dev *ax25_dev;
 
+       dst = (ax25_address *)(bp + 1);
+       src = (ax25_address *)(bp + 8);
+
        if (arp_find(bp + 1, skb))
                return 1;
 
        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
                return 1;
 
+       route = ax25_rt_find_route(dst, dev);
+
        if (bp[16] == AX25_P_IP) {
-               mode = ax25_ip_mode_get((ax25_address *)(bp + 1), dev);
-               if (mode == 'V' || (mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
+               if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
                        /*
                         *      We copy the buffer and release the original thereby
                         *      keeping it straight
@@ -146,7 +151,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
 
                        skb_pull(ourskb, AX25_HEADER_LEN - 1);  /* Keep PID */
 
-                       ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
+                       ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], src, dst, route->digipeat, dev);
 
                        return 1;
                }
@@ -160,15 +165,19 @@ int ax25_rebuild_header(struct sk_buff *skb)
        bp[14] |= AX25_EBIT;
        bp[14] |= AX25_SSSID_SPARE;
 
-       if ((ourskb = ax25_dg_build_path(skb, (ax25_address *)(bp + 1), dev)) == NULL) {
-               kfree_skb(skb, FREE_WRITE);
-               return 1;
+       if (route->digipeat != NULL) {
+               if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
+                       kfree_skb(skb, FREE_WRITE);
+                       return 1;
+               }
+
+               skb = ourskb;
        }
 
-       ourskb->dev      = dev;
-       ourskb->priority = SOPRI_NORMAL;
+       skb->dev      = dev;
+       skb->priority = SOPRI_NORMAL;
 
-       ax25_queue_xmit(ourskb);
+       ax25_queue_xmit(skb);
 
        return 1;
 }
index db7207b28dd56d0d37600fe8aaaa7b521882ede2..4550302d731b2368ae462bf9c006add7c1c74daf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -26,6 +26,7 @@
  *                                     AX.25 I-Frames. Added PACLEN parameter.
  *                     Joerg(DL1BKE)   Fixed a problem with buffer allocation
  *                                     for fragments.
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -52,7 +53,7 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 
-int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct device *dev)
+ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct device *dev)
 {
        ax25_dev *ax25_dev;
        ax25_cb *ax25;
@@ -65,15 +66,14 @@ int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_add
         */
        if ((ax25 = ax25_find_cb(src, dest, digi, dev)) != NULL) {
                ax25_output(ax25, paclen, skb);
-               ax25->idletimer = ax25->idle;
-               return 1;               /* It already existed */
+               return ax25;            /* It already existed */
        }
 
        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
-               return 0;
+               return NULL;
 
        if ((ax25 = ax25_create_cb()) == NULL)
-               return 0;
+               return NULL;
 
        ax25_fillin_cb(ax25, ax25_dev);
 
@@ -83,11 +83,9 @@ int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_add
        if (digi != NULL) {
                if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                        ax25_free_cb(ax25);
-                       return 0;
+                       return NULL;
                }
                *ax25->digipeat = *digi;
-       } else {
-               ax25_rt_build_path(ax25, dest, dev);
        }
 
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
@@ -106,19 +104,15 @@ int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_add
 #endif
        }
 
-       /* idle timeouts only for mode vc connections */
-
-       ax25->idletimer = ax25->idle;
-
        ax25_insert_socket(ax25);
 
        ax25->state = AX25_STATE_1;
 
-       ax25_set_timer(ax25);
+       ax25_start_heartbeat(ax25);
 
        ax25_output(ax25, paclen, skb);
 
-       return 1;                       /* We had to create it */
+       return ax25;                    /* We had to create it */
 }
 
 /*
@@ -195,10 +189,8 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
        }
 
        if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_SIMPLEX ||
-           ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_DUPLEX) {
-               if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4)
-                       ax25_kick(ax25);
-       }
+           ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_DUPLEX)
+               ax25_kick(ax25);
 }
 
 /* 
@@ -228,6 +220,8 @@ static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit)
                frame[1] |= (ax25->vr << 1);
        }
 
+       ax25_start_idletimer(ax25);
+
        ax25_transmit_buffer(ax25, skb, AX25_COMMAND);
 }
 
@@ -237,76 +231,80 @@ void ax25_kick(ax25_cb *ax25)
        int last = 1;
        unsigned short start, end, next;
 
-       del_timer(&ax25->timer);
+       if (ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4)
+               return;
+
+       if (ax25->condition & AX25_COND_PEER_RX_BUSY)
+               return;
+
+       if (skb_peek(&ax25->write_queue) == NULL)
+               return;
 
        start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
        end   = (ax25->va + ax25->window) % ax25->modulus;
 
-       if (!(ax25->condition & AX25_COND_PEER_RX_BUSY) &&
-           start != end                                &&
-           skb_peek(&ax25->write_queue) != NULL) {
+       if (start == end)
+               return;
 
-               ax25->vs = start;
+       ax25->vs = start;
 
-               /*
-                * Transmit data until either we're out of data to send or
-                * the window is full. Send a poll on the final I frame if
-                * the window is filled.
-                */
+       /*
+        * Transmit data until either we're out of data to send or
+        * the window is full. Send a poll on the final I frame if
+        * the window is filled.
+        */
 
-               /*
-                * Dequeue the frame and copy it.
-                */
-               skb  = skb_dequeue(&ax25->write_queue);
+       /*
+        * Dequeue the frame and copy it.
+        */
+       skb  = skb_dequeue(&ax25->write_queue);
 
-               do {
-                       if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
-                               skb_queue_head(&ax25->write_queue, skb);
-                               break;
-                       }
+       do {
+               if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+                       skb_queue_head(&ax25->write_queue, skb);
+                       break;
+               }
 
-                       if (skb->sk != NULL)
-                               skb_set_owner_w(skbn, skb->sk);
+               if (skb->sk != NULL)
+                       skb_set_owner_w(skbn, skb->sk);
 
-                       next = (ax25->vs + 1) % ax25->modulus;
-                       last = (next == end);
+               next = (ax25->vs + 1) % ax25->modulus;
+               last = (next == end);
 
-                       /*
-                        * Transmit the frame copy.
-                        * bke 960114: do not set the Poll bit on the last frame
-                        * in DAMA mode.
-                        */
-                       switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-                               case AX25_PROTO_STD_SIMPLEX:
-                               case AX25_PROTO_STD_DUPLEX:
-                                       ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
-                                       break;
+               /*
+                * Transmit the frame copy.
+                * bke 960114: do not set the Poll bit on the last frame
+                * in DAMA mode.
+                */
+               switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+                       case AX25_PROTO_STD_SIMPLEX:
+                       case AX25_PROTO_STD_DUPLEX:
+                               ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
+                               break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-                               case AX25_PROTO_DAMA_SLAVE:
-                                       ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
-                                       break;
+                       case AX25_PROTO_DAMA_SLAVE:
+                               ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
+                               break;
 #endif
-                       }
+               }
 
-                       ax25->vs = next;
+               ax25->vs = next;
 
-                       /*
-                        * Requeue the original data frame.
-                        */
-                       skb_queue_tail(&ax25->ack_queue, skb);
+               /*
+                * Requeue the original data frame.
+                */
+               skb_queue_tail(&ax25->ack_queue, skb);
 
-               } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
+       } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
 
-               ax25->condition &= ~AX25_COND_ACK_PENDING;
+       ax25->condition &= ~AX25_COND_ACK_PENDING;
 
-               if (ax25->t1timer == 0) {
-                       ax25->t3timer = 0;
-                       ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
-               }
+       if (!ax25_t1timer_running(ax25)) {
+               ax25_stop_t3timer(ax25);
+               ax25_calculate_t1(ax25);
+               ax25_start_t1timer(ax25);
        }
-
-       ax25_set_timer(ax25);
 }
 
 void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
@@ -316,14 +314,7 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
        int headroom;
 
        if (ax25->ax25_dev == NULL) {
-               if (ax25->sk != NULL) {
-                       ax25->sk->state     = TCP_CLOSE;
-                       ax25->sk->err       = ENETUNREACH;
-                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                       if (!ax25->sk->dead)
-                               ax25->sk->state_change(ax25->sk);
-                       ax25->sk->dead      = 1;
-               }
+               ax25_disconnect(ax25, ENETUNREACH);
                return;
        }
 
@@ -381,12 +372,13 @@ void ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
        if (ax25->vs == nr) {
                ax25_frames_acked(ax25, nr);
                ax25_calculate_rtt(ax25);
-               ax25->t1timer = 0;
-               ax25->t3timer = ax25->t3;
+               ax25_stop_t1timer(ax25);
+               ax25_start_t3timer(ax25);
        } else {
                if (ax25->va != nr) {
                        ax25_frames_acked(ax25, nr);
-                       ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+                       ax25_calculate_t1(ax25);
+                       ax25_start_t1timer(ax25);
                }
        }
 }
index 3cda48a173b1db1960547fd51c0b194bcf0606b2..2c7d082a94be6d63176bd2974a01506f972f8e97 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -120,13 +120,12 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
        struct ax25_routes_struct route;
        struct ax25_route_opt_struct rt_option;
        ax25_dev *ax25_dev;
-       int i, err;
+       int i;
 
        switch (cmd) {
                case SIOCADDRT:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
-                               return err;             
-                       copy_from_user(&route, arg, sizeof(route));
+                       if (copy_from_user(&route, arg, sizeof(route)))
+                               return -EFAULT;
                        if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
                                return -EINVAL;
                        if (route.digi_count > AX25_MAX_DIGIS)
@@ -175,9 +174,8 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
                        break;
 
                case SIOCDELRT:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
-                               return err;
-                       copy_from_user(&route, arg, sizeof(route));
+                       if (copy_from_user(&route, arg, sizeof(route)))
+                               return -EFAULT;
                        if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
                                return -EINVAL;
                        ax25_rt = ax25_route_list;
@@ -206,9 +204,8 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
                        break;
 
                case SIOCAX25OPTRT:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(rt_option))) != 0)
-                               return err;
-                       copy_from_user(&rt_option, arg, sizeof(rt_option));
+                       if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
+                               return -EFAULT;
                        if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL)
                                return -EINVAL;
                        for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
@@ -390,48 +387,32 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
  *     dl1bke 960117: build digipeater path
  *     dl1bke 960301: use the default route if it exists
  */
-void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr, struct device *dev)
+ax25_route *ax25_rt_find_route(ax25_address *addr, struct device *dev)
 {
+       static ax25_route route;
        ax25_route *ax25_rt;
 
-       if ((ax25_rt = ax25_find_route(addr, dev)) == NULL)
-               return;
-
-       if (ax25_rt->digipeat == NULL)
-               return;
-
-       if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
-               return;
-
-       if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL)
-               return;
+       if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) {
+               route.next     = NULL;
+               route.callsign = *addr;
+               route.dev      = dev;
+               route.digipeat = NULL;
+               route.ip_mode  = ' ';
+               return &route;
+       }
 
-       *ax25->digipeat = *ax25_rt->digipeat;
-       ax25_adjust_path(addr, ax25->digipeat);
+       return ax25_rt;
 }
 
-struct sk_buff *ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev)
+struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_address *dest, ax25_digi *digi)
 {
        struct sk_buff *skbn;
-       ax25_route *ax25_rt;
-       ax25_digi digipeat;
-       ax25_address src, dest;
        unsigned char *bp;
        int len;
 
        skb_pull(skb, 1);       /* skip KISS command */
 
-       if ((ax25_rt = ax25_find_route(addr, dev)) == NULL)
-               return skb;
-
-       if (ax25_rt->digipeat == NULL)
-               return skb;
-
-       digipeat = *ax25_rt->digipeat;
-
-       ax25_adjust_path(addr, &digipeat);
-
-       len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
+       len = digi->ndigi * AX25_ADDR_LEN;
 
        if (skb_headroom(skb) < len) {
                if ((skbn = skb_realloc_headroom(skb, len)) == NULL) {
@@ -447,30 +428,13 @@ struct sk_buff *ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, stru
                skb = skbn;
        }
 
-       memcpy(&dest, skb->data + 0, AX25_ADDR_LEN);
-       memcpy(&src,  skb->data + 7, AX25_ADDR_LEN);
-
        bp = skb_push(skb, len);
 
-       ax25_addr_build(bp, &src, &dest, ax25_rt->digipeat, AX25_COMMAND, AX25_MODULUS);
+       ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
 
        return skb;
 }
 
-/*
- *     Return the IP mode of a given callsign/device pair.
- */
-char ax25_ip_mode_get(ax25_address *callsign, struct device *dev)
-{
-       ax25_route *ax25_rt;
-
-       for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next)
-               if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev)
-                       return ax25_rt->ip_mode;
-
-       return ' ';
-}
-
 #ifdef MODULE
 
 /*
index 1efe0836612fd452bff7298f69b9ec0fe1e7de9e..7b7d437e885f9f50b1d2a2bcfcaa6e4436983d63 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -34,6 +34,7 @@
  *                                     Modularisation changes.
  *     AX.25 035       Hans(PE1AYX)    Fixed interface to IP layer.
  *     AX.25 036       Jonathan(G4KLX) Cloned from ax25_in.c.
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -87,9 +88,9 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                case AX25_UA:
                        if (pf) {
                                ax25_calculate_rtt(ax25);
-                               ax25->t1timer = 0;
-                               ax25->t3timer = ax25->t3;
-                               ax25->idletimer = ax25->idle;
+                               ax25_stop_t1timer(ax25);
+                               ax25_start_t3timer(ax25);
+                               ax25_start_idletimer(ax25);
                                ax25->vs      = 0;
                                ax25->va      = 0;
                                ax25->vr      = 0;
@@ -107,16 +108,7 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                case AX25_DM:
                        if (pf) {
                                if (ax25->modulus == AX25_MODULUS) {
-                                       ax25_clear_queues(ax25);
-                                       ax25->state = AX25_STATE_0;
-                                       if (ax25->sk != NULL) {
-                                               ax25->sk->state     = TCP_CLOSE;
-                                               ax25->sk->err       = ECONNREFUSED;
-                                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                               if (!ax25->sk->dead)
-                                                       ax25->sk->state_change(ax25->sk);
-                                               ax25->sk->dead      = 1;
-                                       }
+                                       ax25_disconnect(ax25, ECONNREFUSED);
                                } else {
                                        ax25->modulus = AX25_MODULUS;
                                        ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
@@ -146,30 +138,12 @@ static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
 
                case AX25_DISC:
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-                       ax25->state = AX25_STATE_0;
-                       if (ax25->sk != NULL) {
-                               ax25->sk->state     = TCP_CLOSE;
-                               ax25->sk->err       = 0;
-                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!ax25->sk->dead)
-                                       ax25->sk->state_change(ax25->sk);
-                               ax25->sk->dead      = 1;
-                       }
+                       ax25_disconnect(ax25, 0);
                        break;
 
                case AX25_DM:
                case AX25_UA:
-                       if (pf) {
-                               ax25->state = AX25_STATE_0;
-                               if (ax25->sk != NULL) {
-                                       ax25->sk->state     = TCP_CLOSE;
-                                       ax25->sk->err       = 0;
-                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                       if (!ax25->sk->dead)
-                                               ax25->sk->state_change(ax25->sk);
-                                       ax25->sk->dead      = 1;
-                               }
-                       }
+                       if (pf) ax25_disconnect(ax25, 0);
                        break;
 
                case AX25_I:
@@ -206,10 +180,11 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                                ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
                        }
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       ax25_stop_t1timer(ax25);
+                       ax25_stop_t2timer(ax25);
+                       ax25_start_t3timer(ax25);
+                       ax25_start_idletimer(ax25);
                        ax25->condition = 0x00;
-                       ax25->t1timer   = 0;
-                       ax25->t3timer   = ax25->t3;
-                       ax25->idletimer = ax25->idle;
                        ax25->vs        = 0;
                        ax25->va        = 0;
                        ax25->vr        = 0;
@@ -217,32 +192,12 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                        break;
 
                case AX25_DISC:
-                       ax25_clear_queues(ax25);
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-                       ax25->t3timer = 0;
-                       ax25->state   = AX25_STATE_0;
-                       if (ax25->sk != NULL) {
-                               ax25->sk->state     = TCP_CLOSE;
-                               ax25->sk->err       = 0;
-                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!ax25->sk->dead)
-                                       ax25->sk->state_change(ax25->sk);
-                               ax25->sk->dead      = 1;
-                       }
+                       ax25_disconnect(ax25, 0);
                        break;
 
                case AX25_DM:
-                       ax25_clear_queues(ax25);
-                       ax25->t3timer = 0;
-                       ax25->state   = AX25_STATE_0;
-                       if (ax25->sk != NULL) {
-                               ax25->sk->state     = TCP_CLOSE;
-                               ax25->sk->err       = ECONNRESET;
-                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!ax25->sk->dead)
-                                       ax25->sk->state_change(ax25->sk);
-                               ax25->sk->dead      = 1;
-                       }
+                       ax25_disconnect(ax25, ECONNRESET);
                        break;
 
                case AX25_RR:
@@ -268,8 +223,8 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                        if (ax25_validate_nr(ax25, nr)) {
                                ax25_frames_acked(ax25, nr);
                                ax25_calculate_rtt(ax25);
-                               ax25->t1timer = 0;
-                               ax25->t3timer = ax25->t3;
+                               ax25_stop_t1timer(ax25);
+                               ax25_start_t3timer(ax25);
                                ax25_requeue_frames(ax25);
                        } else {
                                ax25_std_nr_error_recovery(ax25);
@@ -295,18 +250,15 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                        if (ns == ax25->vr) {
                                ax25->vr = (ax25->vr + 1) % ax25->modulus;
                                queued = ax25_rx_iframe(ax25, skb);
-                               if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+                               if (ax25->condition & AX25_COND_OWN_RX_BUSY)
                                        ax25->vr = ns;  /* ax25->vr - 1 */
-                                       if (pf) ax25_std_enquiry_response(ax25);
-                                       break;
-                               }
                                ax25->condition &= ~AX25_COND_REJECT;
                                if (pf) {
                                        ax25_std_enquiry_response(ax25);
                                } else {
                                        if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
-                                               ax25->t2timer = ax25->t2;
                                                ax25->condition |= AX25_COND_ACK_PENDING;
+                                               ax25_start_t2timer(ax25);
                                        }
                                }
                        } else {
@@ -353,10 +305,11 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                                ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
                        }
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       ax25_stop_t1timer(ax25);
+                       ax25_stop_t2timer(ax25);
+                       ax25_start_t3timer(ax25);
+                       ax25_start_idletimer(ax25);
                        ax25->condition = 0x00;
-                       ax25->t1timer   = 0;
-                       ax25->t3timer   = ax25->t3;
-                       ax25->idletimer = ax25->idle;
                        ax25->vs        = 0;
                        ax25->va        = 0;
                        ax25->vr        = 0;
@@ -366,32 +319,12 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                        break;
 
                case AX25_DISC:
-                       ax25_clear_queues(ax25);
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-                       ax25->t3timer = 0;
-                       ax25->state   = AX25_STATE_0;
-                       if (ax25->sk != NULL) {
-                               ax25->sk->state     = TCP_CLOSE;
-                               ax25->sk->err       = 0;
-                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!ax25->sk->dead)
-                                       ax25->sk->state_change(ax25->sk);
-                               ax25->sk->dead      = 1;
-                       }
+                       ax25_disconnect(ax25, 0);
                        break;
 
                case AX25_DM:
-                       ax25_clear_queues(ax25);
-                       ax25->t3timer = 0;
-                       ax25->state   = AX25_STATE_0;
-                       if (ax25->sk != NULL) {
-                               ax25->sk->state     = TCP_CLOSE;
-                               ax25->sk->err       = ECONNRESET;
-                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                               if (!ax25->sk->dead)
-                                       ax25->sk->state_change(ax25->sk);
-                               ax25->sk->dead      = 1;
-                       }
+                       ax25_disconnect(ax25, ECONNRESET);
                        break;
 
                case AX25_RR:
@@ -401,11 +334,11 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                        else
                                ax25->condition |= AX25_COND_PEER_RX_BUSY;
                        if (type == AX25_RESPONSE && pf) {
-                               ax25->t1timer = 0;
+                               ax25_stop_t1timer(ax25);
                                if (ax25_validate_nr(ax25, nr)) {
                                        ax25_frames_acked(ax25, nr);
                                        if (ax25->vs == ax25->va) {
-                                               ax25->t3timer = ax25->t3;
+                                               ax25_start_t3timer(ax25);
                                                ax25->n2count = 0;
                                                ax25->state   = AX25_STATE_3;
                                        } else {
@@ -430,11 +363,11 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                case AX25_REJ:
                        ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
                        if (pf && type == AX25_RESPONSE) {
-                               ax25->t1timer = 0;
+                               ax25_stop_t1timer(ax25);
                                if (ax25_validate_nr(ax25, nr)) {
                                        ax25_frames_acked(ax25, nr);
                                        if (ax25->vs == ax25->va) {
-                                               ax25->t3timer = ax25->t3;
+                                               ax25_start_t3timer(ax25);
                                                ax25->n2count = 0;
                                                ax25->state   = AX25_STATE_3;
                                        } else {
@@ -471,18 +404,15 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                        if (ns == ax25->vr) {
                                ax25->vr = (ax25->vr + 1) % ax25->modulus;
                                queued = ax25_rx_iframe(ax25, skb);
-                               if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+                               if (ax25->condition & AX25_COND_OWN_RX_BUSY)
                                        ax25->vr = ns;  /* ax25->vr - 1 */
-                                       if (pf) ax25_std_enquiry_response(ax25);
-                                       break;
-                               }
                                ax25->condition &= ~AX25_COND_REJECT;
                                if (pf) {
                                        ax25_std_enquiry_response(ax25);
                                } else {
                                        if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
-                                               ax25->t2timer = ax25->t2;
                                                ax25->condition |= AX25_COND_ACK_PENDING;
+                                               ax25_start_t2timer(ax25);
                                        }
                                }
                        } else {
@@ -533,6 +463,8 @@ int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
                        break;
        }
 
+       ax25_kick(ax25);
+
        return queued;
 }
 
index 3661a63fbea813e4acb1425c882210d6ffd21a68..1b1d1c8bb7e8fc65292d1f61faf7c7ae023ea847 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -17,6 +17,7 @@
  *
  *     History
  *     AX.25 036       Jonathan(G4KLX) Split from ax25_out.c.
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -62,9 +63,11 @@ void ax25_std_establish_data_link(ax25_cb *ax25)
        else
                ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
 
-       ax25->t3timer = 0;
-       ax25->t2timer = 0;
-       ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+       ax25_calculate_t1(ax25);
+       ax25_stop_idletimer(ax25);
+       ax25_stop_t3timer(ax25);
+       ax25_stop_t2timer(ax25);
+       ax25_start_t1timer(ax25);
 }
 
 void ax25_std_transmit_enquiry(ax25_cb *ax25)
@@ -76,7 +79,8 @@ void ax25_std_transmit_enquiry(ax25_cb *ax25)
 
        ax25->condition &= ~AX25_COND_ACK_PENDING;
 
-       ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+       ax25_calculate_t1(ax25);
+       ax25_start_t1timer(ax25);
 }
        
 void ax25_std_enquiry_response(ax25_cb *ax25)
index 9a4a34c0f0977978f4d65aa54d7f7546227c2070..4e97c51b8566893819292916ebd4519f699f620c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -19,6 +19,7 @@
  *     AX.25 033       Jonathan(G4KLX) Modularisation functions.
  *     AX.25 035       Frederic(F1OAT) Support for pseudo-digipeating.
  *     AX.25 036       Jonathan(G4KLX) Split from ax25_timer.c.
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 
-void ax25_std_timer(ax25_cb *ax25)
+void ax25_std_heartbeat_expiry(ax25_cb *ax25)
 {
        switch (ax25->state) {
+
                case AX25_STATE_0:
                        /* Magic here: If we listen() and a new link dies before it
                           is accepted() it isn't 'dead' so doesn't get removed. */
                        if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
-                               del_timer(&ax25->timer);
                                ax25_destroy_socket(ax25);
                                return;
                        }
@@ -71,78 +72,57 @@ void ax25_std_timer(ax25_cb *ax25)
                                        break;
                                }
                        }
-                       /*
-                        * Check for frames to transmit.
-                        */
-                       ax25_kick(ax25);
-                       break;
-
-               default:
-                       break;
        }
 
-       if (ax25->t2timer > 0 && --ax25->t2timer == 0) {
-               if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) {
-                       if (ax25->condition & AX25_COND_ACK_PENDING) {
-                               ax25->condition &= ~AX25_COND_ACK_PENDING;
-                               ax25_std_timeout_response(ax25);
-                       }
-               }
-       }
+       ax25_start_heartbeat(ax25);
+}
 
-       if (ax25->t3timer > 0 && --ax25->t3timer == 0) {
-               if (ax25->state == AX25_STATE_3) {
-                       ax25->n2count = 0;
-                       ax25_std_transmit_enquiry(ax25);
-                       ax25->state   = AX25_STATE_4;
-               }
-               ax25->t3timer = ax25->t3;
+void ax25_std_t2timer_expiry(ax25_cb *ax25)
+{
+       if (ax25->condition & AX25_COND_ACK_PENDING) {
+               ax25->condition &= ~AX25_COND_ACK_PENDING;
+               ax25_std_timeout_response(ax25);
        }
+}
 
-       if (ax25->idletimer > 0 && --ax25->idletimer == 0) {
-               /* dl1bke 960228: close the connection when IDLE expires */
-               /*                similar to DAMA T3 timeout but with    */
-               /*                a "clean" disconnect of the connection */
-
-               ax25_clear_queues(ax25);
-
-               ax25->n2count = 0;
-               ax25->t3timer = 0;
-               ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-               ax25->state   = AX25_STATE_2;
-               ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
-
-               if (ax25->sk != NULL) {
-                       ax25->sk->state     = TCP_CLOSE;
-                       ax25->sk->err       = 0;
-                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                       if (!ax25->sk->dead)
-                               ax25->sk->state_change(ax25->sk);
-                       ax25->sk->dead      = 1;
-                       ax25->sk->destroy   = 1;
-               }
-       }
+void ax25_std_t3timer_expiry(ax25_cb *ax25)
+{
+       ax25->n2count = 0;
+       ax25_std_transmit_enquiry(ax25);
+       ax25->state   = AX25_STATE_4;
+}
 
-       if (ax25->t1timer == 0 || --ax25->t1timer > 0) {
-               ax25_set_timer(ax25);
-               return;
+void ax25_std_idletimer_expiry(ax25_cb *ax25)
+{
+       ax25_clear_queues(ax25);
+
+       ax25->n2count = 0;
+       ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+       ax25->state   = AX25_STATE_2;
+
+       ax25_calculate_t1(ax25);
+       ax25_start_t1timer(ax25);
+       ax25_stop_t2timer(ax25);
+       ax25_stop_t3timer(ax25);
+
+       if (ax25->sk != NULL) {
+               ax25->sk->state     = TCP_CLOSE;
+               ax25->sk->err       = 0;
+               ax25->sk->shutdown |= SEND_SHUTDOWN;
+               if (!ax25->sk->dead)
+                       ax25->sk->state_change(ax25->sk);
+               ax25->sk->dead      = 1;
        }
+}
 
+void ax25_std_t1timer_expiry(ax25_cb *ax25)
+{
        switch (ax25->state) {
                case AX25_STATE_1: 
                        if (ax25->n2count == ax25->n2) {
                                if (ax25->modulus == AX25_MODULUS) {
-                                       ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
-                                       ax25_clear_queues(ax25);
-                                       ax25->state = AX25_STATE_0;
-                                       if (ax25->sk != NULL) {
-                                               ax25->sk->state     = TCP_CLOSE;
-                                               ax25->sk->err       = ETIMEDOUT;
-                                               ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                               if (!ax25->sk->dead)
-                                                       ax25->sk->state_change(ax25->sk);
-                                               ax25->sk->dead      = 1;
-                                       }
+                                       ax25_disconnect(ax25, ETIMEDOUT);
+                                       return;
                                } else {
                                        ax25->modulus = AX25_MODULUS;
                                        ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
@@ -160,19 +140,9 @@ void ax25_std_timer(ax25_cb *ax25)
 
                case AX25_STATE_2:
                        if (ax25->n2count == ax25->n2) {
-                               ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
-                               ax25_clear_queues(ax25);
-                               ax25->state = AX25_STATE_0;
                                ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-
-                               if (ax25->sk != NULL) {
-                                       ax25->sk->state     = TCP_CLOSE;
-                                       ax25->sk->err       = ETIMEDOUT;
-                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                       if (!ax25->sk->dead)
-                                               ax25->sk->state_change(ax25->sk);
-                                       ax25->sk->dead      = 1;
-                               }
+                               ax25_disconnect(ax25, ETIMEDOUT);
+                               return;
                        } else {
                                ax25->n2count++;
                                ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
@@ -187,19 +157,9 @@ void ax25_std_timer(ax25_cb *ax25)
 
                case AX25_STATE_4:
                        if (ax25->n2count == ax25->n2) {
-                               ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
-                               ax25_clear_queues(ax25);
                                ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
-                               ax25->state = AX25_STATE_0;
-                               if (ax25->sk != NULL) {
-                                       SOCK_DEBUG(ax25->sk, "AX.25 link Failure\n");
-                                       ax25->sk->state     = TCP_CLOSE;
-                                       ax25->sk->err       = ETIMEDOUT;
-                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
-                                       if (!ax25->sk->dead)
-                                               ax25->sk->state_change(ax25->sk);
-                                       ax25->sk->dead      = 1;
-                               }
+                               ax25_disconnect(ax25, ETIMEDOUT);
+                               return;
                        } else {
                                ax25->n2count++;
                                ax25_std_transmit_enquiry(ax25);
@@ -207,9 +167,8 @@ void ax25_std_timer(ax25_cb *ax25)
                        break;
        }
 
-       ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
-
-       ax25_set_timer(ax25);
+       ax25_calculate_t1(ax25);
+       ax25_start_t1timer(ax25);
 }
 
 #endif
index ba2c72297e51d8c5b76e18493330e4b1a081bf6f..39dfd7d422f5582943cd6163b1a5656177a39718 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -30,6 +30,7 @@
  *     AX.25 032       Joerg(DL1BKE)   Added ax25_queue_length to count the number of
  *                                     enqueued buffers of a socket..
  *     AX.25 035       Frederic(F1OAT) Support for pseudo-digipeating.
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -259,7 +260,7 @@ void ax25_return_dm(struct device *dev, ax25_address *src, ax25_address *dest, a
 /*
  *     Exponential backoff for AX.25
  */
-unsigned short ax25_calculate_t1(ax25_cb *ax25)
+void ax25_calculate_t1(ax25_cb *ax25)
 {
        int n, t = 2;
 
@@ -278,7 +279,7 @@ unsigned short ax25_calculate_t1(ax25_cb *ax25)
                        break;
        }
 
-       return t * ax25->rtt;
+       ax25->t1 = t * ax25->rtt;
 }
 
 /*
@@ -289,8 +290,8 @@ void ax25_calculate_rtt(ax25_cb *ax25)
        if (ax25->backoff == 0)
                return;
 
-       if (ax25->t1timer > 0 && ax25->n2count == 0)
-               ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25->t1timer) / 10;
+       if (ax25_t1timer_running(ax25) && ax25->n2count == 0)
+               ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25_display_timer(&ax25->t1timer)) / 10;
 
        if (ax25->rtt < AX25_T1CLAMPLO)
                ax25->rtt = AX25_T1CLAMPLO;
@@ -299,4 +300,27 @@ void ax25_calculate_rtt(ax25_cb *ax25)
                ax25->rtt = AX25_T1CLAMPHI;
 }
 
+void ax25_disconnect(ax25_cb *ax25, int reason)
+{
+       ax25_clear_queues(ax25);
+
+       ax25_stop_t1timer(ax25);
+       ax25_stop_t2timer(ax25);
+       ax25_stop_t3timer(ax25);
+       ax25_stop_idletimer(ax25);
+
+       ax25->state = AX25_STATE_0;
+
+       ax25_link_failed(ax25, reason);
+
+       if (ax25->sk != NULL) {
+               ax25->sk->state     = TCP_CLOSE;
+               ax25->sk->err       = reason;
+               ax25->sk->shutdown |= SEND_SHUTDOWN;
+               if (!ax25->sk->dead)
+                       ax25->sk->state_change(ax25->sk);
+               ax25->sk->dead      = 1;
+       }
+}
+
 #endif
index c0a54da116f002057d9555c8f80b4f1d7a322234..8a384b58ba3222af723319c077f0b45951701a71 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -21,6 +21,7 @@
  *     AX.25 036       Jonathan(G4KLX) Split Standard and DAMA code into seperate files.
  *                     Joerg(DL1BKE)   Fixed DAMA Slave. We are *required* to start with
  *                                     standard AX.25 mode.
+ *     AX.25 037       Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 
-static void ax25_timer(unsigned long);
+static void ax25_heartbeat_expiry(unsigned long);
+static void ax25_t1timer_expiry(unsigned long);
+static void ax25_t2timer_expiry(unsigned long);
+static void ax25_t3timer_expiry(unsigned long);
+static void ax25_idletimer_expiry(unsigned long);
 
-/*
- *     Linux set timer
- */
-void ax25_set_timer(ax25_cb *ax25)
+void ax25_start_heartbeat(ax25_cb *ax25)
 {
-       unsigned long flags;    
-
-       save_flags(flags); cli();
        del_timer(&ax25->timer);
-       restore_flags(flags);
 
        ax25->timer.data     = (unsigned long)ax25;
-       ax25->timer.function = &ax25_timer;
-       ax25->timer.expires  = jiffies + (HZ / 10);
+       ax25->timer.function = &ax25_heartbeat_expiry;
+       ax25->timer.expires  = jiffies + 5 * HZ;
 
        add_timer(&ax25->timer);
 }
 
-/*
- *     AX.25 TIMER 
- *
- *     This routine is called every 100ms. Decrement timer by this
- *     amount - if expired then process the event.
- */
-static void ax25_timer(unsigned long param)
+void ax25_start_t1timer(ax25_cb *ax25)
+{
+       del_timer(&ax25->t1timer);
+
+       ax25->t1timer.data     = (unsigned long)ax25;
+       ax25->t1timer.function = &ax25_t1timer_expiry;
+       ax25->t1timer.expires  = jiffies + ax25->t1;
+
+       add_timer(&ax25->t1timer);
+}
+
+void ax25_start_t2timer(ax25_cb *ax25)
+{
+       del_timer(&ax25->t2timer);
+
+       ax25->t2timer.data     = (unsigned long)ax25;
+       ax25->t2timer.function = &ax25_t2timer_expiry;
+       ax25->t2timer.expires  = jiffies + ax25->t2;
+
+       add_timer(&ax25->t2timer);
+}
+
+void ax25_start_t3timer(ax25_cb *ax25)
+{
+       del_timer(&ax25->t3timer);
+
+       if (ax25->t3 > 0) {
+               ax25->t3timer.data     = (unsigned long)ax25;
+               ax25->t3timer.function = &ax25_t3timer_expiry;
+               ax25->t3timer.expires  = jiffies + ax25->t3;
+
+               add_timer(&ax25->t3timer);
+       }
+}
+
+void ax25_start_idletimer(ax25_cb *ax25)
+{
+       del_timer(&ax25->idletimer);
+
+       if (ax25->idle > 0) {
+               ax25->idletimer.data     = (unsigned long)ax25;
+               ax25->idletimer.function = &ax25_idletimer_expiry;
+               ax25->idletimer.expires  = jiffies + ax25->idle;
+
+               add_timer(&ax25->idletimer);
+       }
+}
+
+void ax25_stop_heartbeat(ax25_cb *ax25)
+{
+       del_timer(&ax25->timer);
+}
+
+void ax25_stop_t1timer(ax25_cb *ax25)
+{
+       del_timer(&ax25->t1timer);
+}
+
+void ax25_stop_t2timer(ax25_cb *ax25)
+{
+       del_timer(&ax25->t2timer);
+}
+
+void ax25_stop_t3timer(ax25_cb *ax25)
+{
+       del_timer(&ax25->t3timer);
+}
+
+void ax25_stop_idletimer(ax25_cb *ax25)
+{
+       del_timer(&ax25->idletimer);
+}
+
+int ax25_t1timer_running(ax25_cb *ax25)
+{
+       return (ax25->t1timer.prev != NULL || ax25->t1timer.next != NULL);
+}
+
+unsigned long ax25_display_timer(struct timer_list *timer)
+{
+       if (timer->prev == NULL && timer->next == NULL)
+               return 0;
+
+       return timer->expires - jiffies;
+}
+
+static void ax25_heartbeat_expiry(unsigned long param)
+{
+       ax25_cb *ax25 = (ax25_cb *)param;
+
+       switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+               case AX25_PROTO_STD_SIMPLEX:
+               case AX25_PROTO_STD_DUPLEX:
+                       ax25_std_heartbeat_expiry(ax25);
+                       break;
+
+#ifdef CONFIG_AX25_DAMA_SLAVE
+               case AX25_PROTO_DAMA_SLAVE:
+                       if (ax25->ax25_dev->dama.slave)
+                               ax25_ds_heartbeat_expiry(ax25);
+                       else
+                               ax25_std_heartbeat_expiry(ax25);
+                       break;
+#endif
+       }
+}
+
+static void ax25_t1timer_expiry(unsigned long param)
+{
+       ax25_cb *ax25 = (ax25_cb *)param;
+
+       switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+               case AX25_PROTO_STD_SIMPLEX:
+               case AX25_PROTO_STD_DUPLEX:
+                       ax25_std_t1timer_expiry(ax25);
+                       break;
+
+#ifdef CONFIG_AX25_DAMA_SLAVE
+               case AX25_PROTO_DAMA_SLAVE:
+                       if (!ax25->ax25_dev->dama.slave)
+                               ax25_std_t1timer_expiry(ax25);
+                       break;
+#endif
+       }
+}
+
+static void ax25_t2timer_expiry(unsigned long param)
+{
+       ax25_cb *ax25 = (ax25_cb *)param;
+
+       switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+               case AX25_PROTO_STD_SIMPLEX:
+               case AX25_PROTO_STD_DUPLEX:
+                       ax25_std_t2timer_expiry(ax25);
+                       break;
+
+#ifdef CONFIG_AX25_DAMA_SLAVE
+               case AX25_PROTO_DAMA_SLAVE:
+                       if (!ax25->ax25_dev->dama.slave)
+                               ax25_std_t2timer_expiry(ax25);
+                       break;
+#endif
+       }
+}
+
+static void ax25_t3timer_expiry(unsigned long param)
+{
+       ax25_cb *ax25 = (ax25_cb *)param;
+
+       switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+               case AX25_PROTO_STD_SIMPLEX:
+               case AX25_PROTO_STD_DUPLEX:
+                       ax25_std_t3timer_expiry(ax25);
+                       break;
+
+#ifdef CONFIG_AX25_DAMA_SLAVE
+               case AX25_PROTO_DAMA_SLAVE:
+                       if (ax25->ax25_dev->dama.slave)
+                               ax25_ds_t3timer_expiry(ax25);
+                       else
+                               ax25_std_t3timer_expiry(ax25);
+                       break;
+#endif
+       }
+}
+
+static void ax25_idletimer_expiry(unsigned long param)
 {
        ax25_cb *ax25 = (ax25_cb *)param;
 
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
                case AX25_PROTO_STD_SIMPLEX:
                case AX25_PROTO_STD_DUPLEX:
-                       ax25_std_timer(ax25);
+                       ax25_std_idletimer_expiry(ax25);
                        break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
                case AX25_PROTO_DAMA_SLAVE:
                        if (ax25->ax25_dev->dama.slave)
-                               ax25_ds_timer(ax25);
+                               ax25_ds_idletimer_expiry(ax25);
                        else
-                               ax25_std_timer(ax25);
+                               ax25_std_idletimer_expiry(ax25);
                        break;
 #endif
        }
index c5113fce8d4fcfb65b22fca6f36a8dbf3ffcb4da..5f33147cf37cd29c8fc656d3b42f2099fbd6f0ee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     AX.25 release 036
+ *     AX.25 release 037
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
index 1cf2bab65d5239c00e91538a0352d7ec329c4dae..000203aafe87ca67b70e703fda4ad8b0954e3cc7 100644 (file)
@@ -17,14 +17,14 @@ static int min_backoff[] = {0},             max_backoff[] = {2};
 static int min_conmode[] = {0},                max_conmode[] = {2};
 static int min_window[] = {1},         max_window[] = {7};
 static int min_ewindow[] = {1},                max_ewindow[] = {63};
-static int min_t1[] = {1},             max_t1[] = {30 * AX25_SLOWHZ};
-static int min_t2[] = {1},             max_t2[] = {20 * AX25_SLOWHZ};
-static int min_t3[] = {0},             max_t3[] = {3600 * AX25_SLOWHZ};
-static int min_idle[] = {0},           max_idle[] = {65535 * AX25_SLOWHZ};
+static int min_t1[] = {1},             max_t1[] = {30 * HZ};
+static int min_t2[] = {1},             max_t2[] = {20 * HZ};
+static int min_t3[] = {0},             max_t3[] = {3600 * HZ};
+static int min_idle[] = {0},           max_idle[] = {65535 * HZ};
 static int min_n2[] = {1},             max_n2[] = {31};
 static int min_paclen[] = {1},         max_paclen[] = {512};
 static int min_proto[] = {0},          max_proto[] = {3};
-static int min_ds_timeout[] = {0},     max_ds_timeout[] = {65535 * AX25_SLOWHZ};
+static int min_ds_timeout[] = {0},     max_ds_timeout[] = {65535 * HZ};
 
 static struct ctl_table_header *ax25_table_header;
 
index c912e8b2ea834ff061f8609b8352c0301b640409..b684fba334f2676f2a3682542b06a0dd372ac9d4 100644 (file)
@@ -7,6 +7,9 @@
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_SYSCTL
 
 extern __u32 sysctl_wmem_max;
 extern __u32 sysctl_rmem_max;
@@ -33,3 +36,4 @@ ctl_table core_table[] = {
         &proc_dointvec_jiffies},
        { 0 }
 };
+#endif
index 8115e819ae2cf11b9dfeb39c39254f27c1a434a7..d3b0c26c9403b1e4d86888905a3a869896e42e44 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.49 1997/06/09 13:27:35 freitag Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.51 1997/07/04 23:35:02 freitag Exp $
  *
  *             IPv4 specific functions
  *
@@ -701,6 +701,12 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp)
        }
 
        /* FIXME: What about the IP layer options size here? */
+       /* FIXME: add a timeout here, to cope with broken devices that
+                 drop all DF=1 packets. Do some more sanity checking 
+                 here to prevent DOS attacks?
+                 This code should kick the tcp_output routine to
+                 retransmit a packet immediately because we know that
+                 the last packet has been dropped. -AK */
        if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
                if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
                        int new_mtu = sk->dst_cache->pmtu - sizeof(struct iphdr) - tp->tcp_header_len;
index 2be6e565e71a16595d89877f96f7900212ce5c65..77382683c667737c8c740030a31a3e28963cdbef 100644 (file)
@@ -1,8 +1,5 @@
 /*
- *     LAPB release 001
- *
- *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *     releases, misbehave and/or generally screw up. It might even work. 
+ *     LAPB release 002
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -14,6 +11,7 @@
  *
  *     History
  *     LAPB 001        Jonathan Naylor Started Coding
+ *     LAPB 002        Jonathan Naylor New timer architecture.
  */
  
 #include <linux/config.h>
@@ -63,8 +61,7 @@ static void lapb_remove_cb(lapb_cb *lapb)
        lapb_cb *s;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        if ((s = lapb_list) == lapb) {
                lapb_list = s->next;
@@ -92,8 +89,7 @@ static void lapb_insert_cb(lapb_cb *lapb)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        lapb->next = lapb_list;
        lapb_list  = lapb;
@@ -130,11 +126,11 @@ static lapb_cb *lapb_create_cb(void)
 
        memset(lapb, 0x00, sizeof(*lapb));
 
-       skb_queue_head_init(&lapb->input_queue);
        skb_queue_head_init(&lapb->write_queue);
        skb_queue_head_init(&lapb->ack_queue);
 
-       init_timer(&lapb->timer);
+       init_timer(&lapb->t1timer);
+       init_timer(&lapb->t2timer);
 
        lapb->t1      = LAPB_DEFAULT_T1;
        lapb->t2      = LAPB_DEFAULT_T2;
@@ -161,9 +157,7 @@ int lapb_register(void *token, struct lapb_register_struct *callbacks)
 
        lapb_insert_cb(lapb);
 
-       lapb->t1timer = lapb->t1;
-
-       lapb_set_timer(lapb);
+       lapb_start_t1timer(lapb);
 
        return LAPB_OK;
 }
@@ -175,7 +169,8 @@ int lapb_unregister(void *token)
        if ((lapb = lapb_tokentostruct(token)) == NULL)
                return LAPB_BADTOKEN;
 
-       del_timer(&lapb->timer);
+       lapb_stop_t1timer(lapb);
+       lapb_stop_t2timer(lapb);
 
        lapb_clear_queues(lapb);
 
@@ -193,16 +188,24 @@ int lapb_getparms(void *token, struct lapb_parms_struct *parms)
        if ((lapb = lapb_tokentostruct(token)) == NULL)
                return LAPB_BADTOKEN;
 
-       parms->t1      = lapb->t1;
-       parms->t1timer = lapb->t1timer;
-       parms->t2      = lapb->t2;
-       parms->t2timer = lapb->t2timer;
+       parms->t1      = lapb->t1 / HZ;
+       parms->t2      = lapb->t2 / HZ;
        parms->n2      = lapb->n2;
        parms->n2count = lapb->n2count;
        parms->state   = lapb->state;
        parms->window  = lapb->window;
        parms->mode    = lapb->mode;
 
+       if (lapb->t1timer.prev == NULL && lapb->t1timer.next == NULL)
+               parms->t1timer = 0;
+       else
+               parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ;
+
+       if (lapb->t2timer.prev == NULL && lapb->t2timer.next == NULL)
+               parms->t2timer = 0;
+       else
+               parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
+
        return LAPB_OK;
 }
 
@@ -235,8 +238,8 @@ int lapb_setparms(void *token, struct lapb_parms_struct *parms)
                lapb->window  = parms->window;
        }
 
-       lapb->t1    = parms->t1;
-       lapb->t2    = parms->t2;
+       lapb->t1    = parms->t1 * HZ;
+       lapb->t2    = parms->t2 * HZ;
        lapb->n2    = parms->n2;
 
        return LAPB_OK;
@@ -287,8 +290,8 @@ int lapb_disconnect_request(void *token)
                        printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
 #endif
                        lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
-                       lapb->state   = LAPB_STATE_0;
-                       lapb->t1timer = lapb->t1;
+                       lapb->state = LAPB_STATE_0;
+                       lapb_start_t1timer(lapb);
                        return LAPB_NOTCONNECTED;
 
                case LAPB_STATE_2:
@@ -298,9 +301,9 @@ int lapb_disconnect_request(void *token)
        lapb_clear_queues(lapb);
        lapb->n2count = 0;
        lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
-       lapb->t1timer = lapb->t1;
-       lapb->t2timer = 0;
-       lapb->state   = LAPB_STATE_2;
+       lapb_start_t1timer(lapb);
+       lapb_stop_t2timer(lapb);
+       lapb->state = LAPB_STATE_2;
 
 #if LAPB_DEBUG > 1
        printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->token);
@@ -336,7 +339,7 @@ int lapb_data_received(void *token, struct sk_buff *skb)
        if ((lapb = lapb_tokentostruct(token)) == NULL)
                return LAPB_BADTOKEN;
 
-       skb_queue_tail(&lapb->input_queue, skb);
+       lapb_data_input(lapb, skb);
 
        return LAPB_OK;
 }
index 9aa36711506ea703647f7b5e4b2f34163186dda1..126b9367351eb911c70058559463ff6dabc43c02 100644 (file)
@@ -1,8 +1,5 @@
 /*
- *     LAPB release 001
- *
- *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *     releases, misbehave and/or generally screw up. It might even work. 
+ *     LAPB release 002
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -14,6 +11,7 @@
  *
  *     History
  *     LAPB 001        Jonathan Naulor Started Coding
+ *     LAPB 002        Jonathan Naylor New timer architecture.
  */
 
 #include <linux/config.h>
@@ -63,10 +61,10 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                                printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token);
 #endif
                                lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+                               lapb_stop_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb->state     = LAPB_STATE_3;
                                lapb->condition = 0x00;
-                               lapb->t1timer   = 0;
-                               lapb->t2timer   = 0;
                                lapb->n2count   = 0;
                                lapb->vs        = 0;
                                lapb->vr        = 0;
@@ -87,10 +85,10 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                                printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token);
 #endif
                                lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+                               lapb_stop_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb->state     = LAPB_STATE_3;
                                lapb->condition = 0x00;
-                               lapb->t1timer   = 0;
-                               lapb->t2timer   = 0;
                                lapb->n2count   = 0;
                                lapb->vs        = 0;
                                lapb->vr        = 0;
@@ -176,10 +174,10 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n", lapb->token);
 #endif
+                               lapb_stop_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb->state     = LAPB_STATE_3;
                                lapb->condition = 0x00;
-                               lapb->t1timer   = 0;
-                               lapb->t2timer   = 0;
                                lapb->n2count   = 0;
                                lapb->vs        = 0;
                                lapb->vr        = 0;
@@ -197,9 +195,9 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                                printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
 #endif
                                lapb_clear_queues(lapb);
-                               lapb->state   = LAPB_STATE_0;
-                               lapb->t1timer = lapb->t1;
-                               lapb->t2timer = 0;
+                               lapb->state = LAPB_STATE_0;
+                               lapb_start_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb_disconnect_indication(lapb, LAPB_REFUSED);
                        }
                        break;
@@ -243,9 +241,9 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
 #endif
-                               lapb->state   = LAPB_STATE_0;
-                               lapb->t1timer = lapb->t1;
-                               lapb->t2timer = 0;
+                               lapb->state = LAPB_STATE_0;
+                               lapb_start_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb_disconnect_confirmation(lapb, LAPB_OK);
                        }
                        break;
@@ -258,9 +256,9 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
 #endif
-                               lapb->state   = LAPB_STATE_0;
-                               lapb->t1timer = lapb->t1;
-                               lapb->t2timer = 0;
+                               lapb->state = LAPB_STATE_0;
+                               lapb_start_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED);
                        }
                        break;
@@ -309,9 +307,9 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                                printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf);
 #endif
                                lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+                               lapb_stop_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb->condition = 0x00;
-                               lapb->t1timer   = 0;
-                               lapb->t2timer   = 0;
                                lapb->n2count   = 0;
                                lapb->vs        = 0;
                                lapb->vr        = 0;
@@ -329,9 +327,9 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                                printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf);
 #endif
                                lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+                               lapb_stop_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb->condition = 0x00;
-                               lapb->t1timer   = 0;
-                               lapb->t2timer   = 0;
                                lapb->n2count   = 0;
                                lapb->vs        = 0;
                                lapb->vr        = 0;
@@ -354,9 +352,9 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
 #endif
                        lapb_clear_queues(lapb);
                        lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
-                       lapb->state   = LAPB_STATE_0;
-                       lapb->t1timer = lapb->t1;
-                       lapb->t2timer = 0;
+                       lapb_start_t1timer(lapb);
+                       lapb_stop_t2timer(lapb);
+                       lapb->state = LAPB_STATE_0;
                        lapb_disconnect_indication(lapb, LAPB_OK);
                        break;
 
@@ -368,9 +366,9 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                        printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token);
 #endif
                        lapb_clear_queues(lapb);
-                       lapb->state   = LAPB_STATE_0;
-                       lapb->t1timer = lapb->t1;
-                       lapb->t2timer = 0;
+                       lapb->state = LAPB_STATE_0;
+                       lapb_start_t1timer(lapb);
+                       lapb_stop_t2timer(lapb);
                        lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
                        break;
 
@@ -389,10 +387,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
 #endif
-                               lapb->state     = LAPB_STATE_4;
-                               lapb->t1timer   = lapb->t1;
-                               lapb->t2timer   = 0;
-                               lapb->n2count   = 0;
+                               lapb_start_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
+                               lapb->state   = LAPB_STATE_4;
+                               lapb->n2count = 0;
                        }
                        break;
 
@@ -411,10 +409,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
 #endif
-                               lapb->state     = LAPB_STATE_4;
-                               lapb->t1timer   = lapb->t1;
-                               lapb->t2timer   = 0;
-                               lapb->n2count   = 0;
+                               lapb_start_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
+                               lapb->state   = LAPB_STATE_4;
+                               lapb->n2count = 0;
                        }
                        break;
 
@@ -426,7 +424,7 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                        lapb_check_need_response(lapb, frame->cr, frame->pf);
                        if (lapb_validate_nr(lapb, frame->nr)) {
                                lapb_frames_acked(lapb, frame->nr);
-                               lapb->t1timer = 0;
+                               lapb_stop_t1timer(lapb);
                                lapb->n2count = 0;
                                lapb_requeue_frames(lapb);
                        } else {
@@ -436,10 +434,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
 #endif
-                               lapb->state     = LAPB_STATE_4;
-                               lapb->t1timer   = lapb->t1;
-                               lapb->t2timer   = 0;
-                               lapb->n2count   = 0;
+                               lapb_start_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
+                               lapb->state   = LAPB_STATE_4;
+                               lapb->n2count = 0;
                        }
                        break;
 
@@ -454,10 +452,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
 #endif
-                               lapb->state     = LAPB_STATE_4;
-                               lapb->t1timer   = lapb->t1;
-                               lapb->t2timer   = 0;
-                               lapb->n2count   = 0;
+                               lapb_start_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
+                               lapb->state   = LAPB_STATE_4;
+                               lapb->n2count = 0;
                                break;
                        }
                        if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) {
@@ -473,8 +471,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                                        lapb_enquiry_response(lapb);
                                } else {
                                        if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) {
-                                               lapb->t2timer = lapb->t2;
                                                lapb->condition |= LAPB_ACK_PENDING_CONDITION;
+                                               lapb_start_t2timer(lapb);
                                        }
                                }
                        } else {
@@ -514,10 +512,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
 #if LAPB_DEBUG > 0
                        printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
 #endif
-                       lapb->state     = LAPB_STATE_4;
-                       lapb->t1timer   = lapb->t1;
-                       lapb->t2timer   = 0;
-                       lapb->n2count   = 0;
+                       lapb_start_t1timer(lapb);
+                       lapb_stop_t2timer(lapb);
+                       lapb->state   = LAPB_STATE_4;
+                       lapb->n2count = 0;
                        break;
 
                default:
@@ -552,10 +550,10 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                                printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token);
 #endif
                                lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+                               lapb_stop_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb->state     = LAPB_STATE_3;
                                lapb->condition = 0x00;
-                               lapb->t1timer   = 0;
-                               lapb->t2timer   = 0;
                                lapb->n2count   = 0;
                                lapb->vs        = 0;
                                lapb->vr        = 0;
@@ -576,10 +574,10 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
                                printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token);
 #endif
                                lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+                               lapb_stop_t1timer(lapb);
+                               lapb_stop_t2timer(lapb);
                                lapb->state     = LAPB_STATE_3;
                                lapb->condition = 0x00;
-                               lapb->t1timer   = 0;
-                               lapb->t2timer   = 0;
                                lapb->n2count   = 0;
                                lapb->vs        = 0;
                                lapb->vr        = 0;
@@ -626,6 +624,8 @@ void lapb_data_input(lapb_cb *lapb, struct sk_buff *skb)
                        lapb_state4_machine(lapb, skb, &frame);
                        break;
        }
+
+       lapb_kick(lapb);
 }
 
 #endif
index 1256e3a3c109f59340a7a2966ea090a4d928cfa1..9e1cdf4758bea16d8699ab41b5ed393bf913e410 100644 (file)
@@ -1,8 +1,5 @@
 /*
- *     LAPB release 001
- *
- *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *     releases, misbehave and/or generally screw up. It might even work. 
+ *     LAPB release 002
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -14,6 +11,7 @@
  *
  *     History
  *     LAPB 001        Jonathan Naylor Started Coding
+ *     LAPB 002        Jonathan Naylor New timer architecture.
  */
 
 #include <linux/config.h>
@@ -77,8 +75,6 @@ void lapb_kick(lapb_cb *lapb)
        struct sk_buff *skb, *skbn;
        unsigned short modulus, start, end;
 
-       del_timer(&lapb->timer);
-
        modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
 
        start = (skb_peek(&lapb->ack_queue) == NULL) ? lapb->va : lapb->vs;
@@ -120,11 +116,9 @@ void lapb_kick(lapb_cb *lapb)
 
                lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
 
-               if (lapb->t1timer == 0)
-                       lapb->t1timer = lapb->t1;
+               if (!lapb_t1timer_running(lapb))
+                       lapb_start_t1timer(lapb);
        }
-
-       lapb_set_timer(lapb);
 }
 
 void lapb_transmit_buffer(lapb_cb *lapb, struct sk_buff *skb, int type)
@@ -184,8 +178,8 @@ void lapb_establish_data_link(lapb_cb *lapb)
                lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
        }
 
-       lapb->t2timer = 0;
-       lapb->t1timer = lapb->t1;
+       lapb_start_t1timer(lapb);
+       lapb_stop_t2timer(lapb);
 }
 
 void lapb_enquiry_response(lapb_cb *lapb)
@@ -214,12 +208,12 @@ void lapb_check_iframes_acked(lapb_cb *lapb, unsigned short nr)
 {
        if (lapb->vs == nr) {
                lapb_frames_acked(lapb, nr);
-               lapb->t1timer = 0;
+               lapb_stop_t1timer(lapb);
                lapb->n2count = 0;
        } else {
                if (lapb->va != nr) {
                        lapb_frames_acked(lapb, nr);
-                       lapb->t1timer = lapb->t1;
+                       lapb_start_t1timer(lapb);
                }
        }
 }
index 626e0892747518502d12bdf567b4ffd06764c9f5..3f7f0a84e9048decacefe181f17293a7a501ca1f 100644 (file)
@@ -1,8 +1,5 @@
 /*
- *     LAPB release 001
- *
- *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *     releases, misbehave and/or generally screw up. It might even work. 
+ *     LAPB release 002
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -45,9 +42,6 @@ void lapb_clear_queues(lapb_cb *lapb)
 {
        struct sk_buff *skb;
 
-       while ((skb = skb_dequeue(&lapb->input_queue)) != NULL)
-               kfree_skb(skb, FREE_READ);
-
        while ((skb = skb_dequeue(&lapb->write_queue)) != NULL)
                kfree_skb(skb, FREE_WRITE);
 
index 2679ff514dcfbd49f45d9e3e8e582cd9f222f3c0..757fd10d94099020ce92d057f6d38c5a78da28d5 100644 (file)
@@ -1,8 +1,5 @@
 /*
- *     LAPB release 001
- *
- *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *     releases, misbehave and/or generally screw up. It might even work. 
+ *     LAPB release 002
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -14,6 +11,7 @@
  *
  *     History
  *     LAPB 001        Jonathan Naylor Started Coding
+ *     LAPB 002        Jonathan Naylor New timer architecture.
  */
 
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <net/lapb.h>
 
-static void lapb_timer(unsigned long);
+static void lapb_t1timer_expiry(unsigned long);
+static void lapb_t2timer_expiry(unsigned long);
 
-/*
- *     Linux set timer
- */
-void lapb_set_timer(lapb_cb *lapb)
+void lapb_start_t1timer(lapb_cb *lapb)
 {
-       unsigned long flags;    
+       del_timer(&lapb->t1timer);
+
+       lapb->t1timer.data     = (unsigned long)lapb;
+       lapb->t1timer.function = &lapb_t1timer_expiry;
+       lapb->t1timer.expires  = jiffies + lapb->t1;
 
-       save_flags(flags); cli();
-       del_timer(&lapb->timer);
-       restore_flags(flags);
+       add_timer(&lapb->t1timer);
+}
+
+void lapb_start_t2timer(lapb_cb *lapb)
+{
+       del_timer(&lapb->t2timer);
 
-       lapb->timer.data     = (unsigned long)lapb;
-       lapb->timer.function = &lapb_timer;
-       lapb->timer.expires  = jiffies + (HZ / 10);
+       lapb->t2timer.data     = (unsigned long)lapb;
+       lapb->t2timer.function = &lapb_t2timer_expiry;
+       lapb->t2timer.expires  = jiffies + lapb->t2;
 
-       add_timer(&lapb->timer);
+       add_timer(&lapb->t2timer);
 }
 
-/*
- *     LAPB TIMER 
- *
- *     This routine is called every 100ms. Decrement timer by this
- *     amount - if expired then process the event.
- */
-static void lapb_timer(unsigned long param)
+void lapb_stop_t1timer(lapb_cb *lapb)
+{
+       del_timer(&lapb->t1timer);
+}
+
+void lapb_stop_t2timer(lapb_cb *lapb)
+{
+       del_timer(&lapb->t2timer);
+}
+
+int lapb_t1timer_running(lapb_cb *lapb)
+{
+       return (lapb->t1timer.prev != NULL || lapb->t1timer.next != NULL);
+}
+
+static void lapb_t2timer_expiry(unsigned long param)
 {
        lapb_cb *lapb = (lapb_cb *)param;
-       struct sk_buff *skb;
-
-       /*
-        *      Process all packet received since the last clock tick.
-        */
-       while ((skb = skb_dequeue(&lapb->input_queue)) != NULL)
-               lapb_data_input(lapb, skb);
-
-       /*
-        *      If in a data transfer state, transmit any data.
-        */
-       if (lapb->state == LAPB_STATE_3)
-               lapb_kick(lapb);
-
-       /*
-        *      T2 expiry code.
-        */
-       if (lapb->t2timer > 0 && --lapb->t2timer == 0) {
-               if (lapb->state == LAPB_STATE_3) {
-                       if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
-                               lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
-                               lapb_timeout_response(lapb);
-                       }
-               }
-       }
 
-       /*
-        *      If T1 isn't running, or hasn't timed out yet, keep going.
-        */
-       if (lapb->t1timer == 0 || --lapb->t1timer > 0) {
-               lapb_set_timer(lapb);
-               return;
+       if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
+               lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
+               lapb_timeout_response(lapb);
        }
+}
+
+static void lapb_t1timer_expiry(unsigned long param)
+{
+       lapb_cb *lapb = (lapb_cb *)param;
 
-       /*
-        *      T1 has expired.
-        */
        switch (lapb->state) {
 
                /*
@@ -120,12 +106,12 @@ static void lapb_timer(unsigned long param)
                case LAPB_STATE_1: 
                        if (lapb->n2count == lapb->n2) {
                                lapb_clear_queues(lapb);
-                               lapb->state   = LAPB_STATE_0;
-                               lapb->t2timer = 0;
+                               lapb->state = LAPB_STATE_0;
                                lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
 #endif
+                               return;
                        } else {
                                lapb->n2count++;
                                if (lapb->mode & LAPB_EXTENDED) {
@@ -148,12 +134,12 @@ static void lapb_timer(unsigned long param)
                case LAPB_STATE_2:
                        if (lapb->n2count == lapb->n2) {
                                lapb_clear_queues(lapb);
-                               lapb->state   = LAPB_STATE_0;
-                               lapb->t2timer = 0;
+                               lapb->state = LAPB_STATE_0;
                                lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
 #endif
+                               return;
                        } else {
                                lapb->n2count++;
 #if LAPB_DEBUG > 1
@@ -169,12 +155,13 @@ static void lapb_timer(unsigned long param)
                case LAPB_STATE_3:
                        if (lapb->n2count == lapb->n2) {
                                lapb_clear_queues(lapb);
-                               lapb->state   = LAPB_STATE_0;
-                               lapb->t2timer = 0;
+                               lapb->state = LAPB_STATE_0;
+                               lapb_stop_t2timer(lapb);
                                lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token);
 #endif
+                               return;
                        } else {
                                lapb->n2count++;
                                lapb_requeue_frames(lapb);
@@ -187,12 +174,12 @@ static void lapb_timer(unsigned long param)
                case LAPB_STATE_4:
                        if (lapb->n2count == lapb->n2) {
                                lapb_clear_queues(lapb);
-                               lapb->state   = LAPB_STATE_0;
-                               lapb->t2timer = 0;
+                               lapb->state = LAPB_STATE_0;
                                lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
                                printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token);
 #endif
+                               return;
                        } else {
                                lapb->n2count++;
                                lapb_transmit_frmr(lapb);
@@ -200,9 +187,7 @@ static void lapb_timer(unsigned long param)
                        break;
        }
 
-       lapb->t1timer = lapb->t1;
-
-       lapb_set_timer(lapb);
+       lapb_start_t1timer(lapb);
 }
 
 #endif
index 22e1afbeeea784b3c62df0db472c191a86f356b4..dd80a211b29b8560671245cf8a38d205efd1024d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     NET/ROM release 006
+ *     NET/ROM release 007
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -28,6 +28,8 @@
  *                     Alan(GW4PTS)    Started POSIXisms
  *     NET/ROM 006     Alan(GW4PTS)    Brought in line with the ANK changes
  *                     Jonathan(G4KLX) Removed hdrincl.
+ *     NET/ROM 007     Jonathan(G4KLX) New timer architecture.
+ *                                     Impmented Idle timer.
  */
 
 #include <linux/config.h>
@@ -122,8 +124,7 @@ static void nr_remove_socket(struct sock *sk)
        struct sock *s;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        if ((s = nr_list) == sk) {
                nr_list = s->next;
@@ -152,15 +153,8 @@ static void nr_kill_by_device(struct device *dev)
        struct sock *s;
 
        for (s = nr_list; s != NULL; s = s->next) {
-               if (s->protinfo.nr->device == dev) {
-                       s->protinfo.nr->state  = NR_STATE_0;
-                       s->protinfo.nr->device = NULL;
-                       s->state               = TCP_CLOSE;
-                       s->err                 = ENETUNREACH;
-                       s->shutdown           |= SEND_SHUTDOWN;
-                       s->state_change(s);
-                       s->dead                = 1;
-               }
+               if (s->protinfo.nr->device == dev)
+                       nr_disconnect(s, ENETUNREACH);
        }
 }
 
@@ -187,8 +181,7 @@ static void nr_insert_socket(struct sock *sk)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        sk->next = nr_list;
        nr_list  = sk;
@@ -289,10 +282,13 @@ void nr_destroy_socket(struct sock *sk)   /* Not static as it's used by the timer
        struct sk_buff *skb;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
-       del_timer(&sk->timer);
+       nr_stop_heartbeat(sk);
+       nr_stop_t1timer(sk);
+       nr_stop_t2timer(sk);
+       nr_stop_t4timer(sk);
+       nr_stop_idletimer(sk);
 
        nr_remove_socket(sk);
        nr_clear_queues(sk);            /* Flush the queues */
@@ -300,7 +296,7 @@ void nr_destroy_socket(struct sock *sk)     /* Not static as it's used by the timer
        while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
                if (skb->sk != sk) {                    /* A pending connection */
                        skb->sk->dead = 1;      /* Queue the unaccepted socket for death */
-                       nr_set_timer(skb->sk);
+                       nr_start_heartbeat(skb->sk);
                        skb->sk->protinfo.nr->state = NR_STATE_0;
                }
 
@@ -345,13 +341,13 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
                case NETROM_T1:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.nr->t1 = opt * NR_SLOWHZ;
+                       sk->protinfo.nr->t1 = opt * HZ;
                        return 0;
 
                case NETROM_T2:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.nr->t2 = opt * NR_SLOWHZ;
+                       sk->protinfo.nr->t2 = opt * HZ;
                        return 0;
 
                case NETROM_N2:
@@ -363,13 +359,13 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
                case NETROM_T4:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.nr->t4 = opt * NR_SLOWHZ;
+                       sk->protinfo.nr->t4 = opt * HZ;
                        return 0;
 
                case NETROM_IDLE:
-                       if (opt < 1)
+                       if (opt < 0)
                                return -EINVAL;
-                       sk->protinfo.nr->idle = opt * 60 * NR_SLOWHZ;
+                       sk->protinfo.nr->idle = opt * 60 * HZ;
                        return 0;
 
                default:
@@ -392,11 +388,11 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
 
        switch (optname) {
                case NETROM_T1:
-                       val = (sk->protinfo.nr->t1 * 2) / NR_SLOWHZ;
+                       val = sk->protinfo.nr->t1 / HZ;
                        break;
 
                case NETROM_T2:
-                       val = sk->protinfo.nr->t2 / NR_SLOWHZ;
+                       val = sk->protinfo.nr->t2 / HZ;
                        break;
 
                case NETROM_N2:
@@ -404,11 +400,11 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
                        break;
 
                case NETROM_T4:
-                       val = sk->protinfo.nr->t4 / NR_SLOWHZ;
+                       val = sk->protinfo.nr->t4 / HZ;
                        break;
 
                case NETROM_IDLE:
-                       val = sk->protinfo.nr->idle / (NR_SLOWHZ * 60);
+                       val = sk->protinfo.nr->idle / (60 * HZ);
                        break;
 
                default:
@@ -463,6 +459,11 @@ static int nr_create(struct socket *sock, int protocol)
        skb_queue_head_init(&nr->reseq_queue);
        skb_queue_head_init(&nr->frag_queue);
 
+       init_timer(&nr->t1timer);
+       init_timer(&nr->t2timer);
+       init_timer(&nr->t4timer);
+       init_timer(&nr->idletimer);
+
        nr->t1     = sysctl_netrom_transport_timeout;
        nr->t2     = sysctl_netrom_transport_acknowledge_delay;
        nr->n2     = sysctl_netrom_transport_maximum_tries;
@@ -507,6 +508,11 @@ static struct sock *nr_make_new(struct sock *osk)
        skb_queue_head_init(&nr->reseq_queue);
        skb_queue_head_init(&nr->frag_queue);
 
+       init_timer(&nr->t1timer);
+       init_timer(&nr->t2timer);
+       init_timer(&nr->t4timer);
+       init_timer(&nr->idletimer);
+
        nr->t1      = osk->protinfo.nr->t1;
        nr->t2      = osk->protinfo.nr->t2;
        nr->n2      = osk->protinfo.nr->n2;
@@ -539,39 +545,20 @@ static int nr_release(struct socket *sock, struct socket *peer)
        switch (sk->protinfo.nr->state) {
 
                case NR_STATE_0:
-                       sk->state     = TCP_CLOSE;
-                       sk->shutdown |= SEND_SHUTDOWN;
-                       sk->state_change(sk);
-                       sk->dead      = 1;
+               case NR_STATE_2:
+                       nr_disconnect(sk, 0);
                        nr_destroy_socket(sk);
                        break;
 
                case NR_STATE_1:
-                       sk->protinfo.nr->state = NR_STATE_0;
-                       sk->state              = TCP_CLOSE;
-                       sk->shutdown          |= SEND_SHUTDOWN;
-                       sk->state_change(sk);
-                       sk->dead               = 1;
-                       nr_destroy_socket(sk);
-                       break;
-
-               case NR_STATE_2:
-                       nr_write_internal(sk, NR_DISCACK);
-                       sk->protinfo.nr->state = NR_STATE_0;
-                       sk->state              = TCP_CLOSE;
-                       sk->shutdown          |= SEND_SHUTDOWN;
-                       sk->state_change(sk);
-                       sk->dead               = 1;
-                       nr_destroy_socket(sk);
-                       break;                  
-
                case NR_STATE_3:
                        nr_clear_queues(sk);
                        sk->protinfo.nr->n2count = 0;
                        nr_write_internal(sk, NR_DISCREQ);
-                       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
-                       sk->protinfo.nr->t2timer = 0;
-                       sk->protinfo.nr->t4timer = 0;
+                       nr_start_t1timer(sk);
+                       nr_stop_t2timer(sk);
+                       nr_stop_t4timer(sk);
+                       nr_stop_idletimer(sk);
                        sk->protinfo.nr->state   = NR_STATE_2;
                        sk->state                = TCP_CLOSE;
                        sk->shutdown            |= SEND_SHUTDOWN;
@@ -704,9 +691,12 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
        /* Move to connecting socket, start sending Connect Requests */
        sock->state            = SS_CONNECTING;
        sk->state              = TCP_SYN_SENT;
+
        nr_establish_data_link(sk);
+
        sk->protinfo.nr->state = NR_STATE_1;
-       nr_set_timer(sk);
+
+       nr_start_heartbeat(sk);
 
        /* Now the loop */
        if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -838,13 +828,13 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
 
        circuit_index = skb->data[15];
        circuit_id    = skb->data[16];
-       frametype     = skb->data[19];
+       frametype     = skb->data[19] & 0x0F;
 
 #ifdef CONFIG_INET
        /*
         * Check for an incoming IP over NET/ROM frame.
         */
-        if ((frametype & 0x0F) == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
+        if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
                skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
                skb->h.raw = skb->data;
 
@@ -856,11 +846,11 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
         * Find an existing socket connection, based on circuit ID, if it's
         * a Connect Request base it on their circuit ID.
         */
-       if (((frametype & 0x0F) != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
-           ((frametype & 0x0F) == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id)) != NULL)) {
+       if ((frametype != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
+           (frametype == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id)) != NULL)) {
                skb->h.raw = skb->data;
 
-               if ((frametype & 0x0F) == NR_CONNACK && skb->len == 22)
+               if (frametype == NR_CONNACK && skb->len == 22)
                        sk->protinfo.nr->bpqext = 1;
                else
                        sk->protinfo.nr->bpqext = 0;
@@ -868,8 +858,16 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
                return nr_process_rx_frame(sk, skb);
        }
 
-       if ((frametype & 0x0F) != NR_CONNREQ)
-               return 0;
+       switch (frametype) {
+               case NR_CONNREQ:
+                       break;
+               case NR_DISCREQ:
+               case NR_DISCACK:
+                       return 0;
+               default:
+                       nr_transmit_dm(skb);
+                       return 0;
+       }
 
        sk = nr_find_listener(dest);
 
@@ -905,8 +903,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
        /* L4 timeout negotiation */
        if (skb->len == 37) {
                timeout = skb->data[36] * 256 + skb->data[35];
-               if (timeout * NR_SLOWHZ < make->protinfo.nr->t1)
-                       make->protinfo.nr->t1 = timeout * NR_SLOWHZ;
+               if (timeout * HZ < make->protinfo.nr->t1)
+                       make->protinfo.nr->t1 = timeout * HZ;
                make->protinfo.nr->bpqext = 1;
        } else {
                make->protinfo.nr->bpqext = 0;
@@ -927,7 +925,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
 
        skb_queue_head(&sk->receive_queue, skb);
 
-       nr_set_timer(make);
+       nr_start_heartbeat(make);
+       nr_start_idletimer(make);
 
        if (!sk->dead)
                sk->data_ready(sk, skb->len);
@@ -973,6 +972,7 @@ static int nr_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct s
                sax.sax25_family = AF_NETROM;
                sax.sax25_call   = sk->protinfo.nr->dest_addr;
        }
+
        SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n");
 
        /* Build a packet */
@@ -1074,37 +1074,35 @@ static int nr_shutdown(struct socket *sk, int how)
 static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
-       int err;
-       long amount = 0;
 
        switch (cmd) {
-               case TIOCOUTQ:
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0)
-                               return err;
+               case TIOCOUTQ: {
+                       long amount;
                        amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
                        if (amount < 0)
                                amount = 0;
-                       put_user(amount, (int *)arg);
+                       if (put_user(amount, (int *)arg))
+                               return -EFAULT;
                        return 0;
+               }
 
                case TIOCINQ: {
                        struct sk_buff *skb;
+                       long amount = 0L;
                        /* These two are safe on a single CPU system as only user tasks fiddle here */
                        if ((skb = skb_peek(&sk->receive_queue)) != NULL)
-                               amount = skb->len - 20;
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0)
-                               return err;
-                       put_user(amount, (int *)arg);
+                               amount = skb->len;
+                       if (put_user(amount, (int *)arg))
+                               return -EFAULT;
                        return 0;
                }
 
                case SIOCGSTAMP:
                        if (sk != NULL) {
-                               if (sk->stamp.tv_sec==0)
+                               if (sk->stamp.tv_sec == 0)
                                        return -ENOENT;
-                               if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0)
-                                       return err;
-                               copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval));
+                               if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+                                       return -EFAULT;
                                return 0;
                        }
                        return -EINVAL;
@@ -1146,7 +1144,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
 
        cli();
 
-       len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2    n2  wnd Snd-Q Rcv-Q\n");
+       len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2     t4      idle   n2  wnd Snd-Q Rcv-Q\n");
 
        for (s = nr_list; s != NULL; s = s->next) {
                if ((dev = s->protinfo.nr->device) == NULL)
@@ -1158,20 +1156,30 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
                        ax2asc(&s->protinfo.nr->user_addr));
                len += sprintf(buffer + len, "%-9s ",
                        ax2asc(&s->protinfo.nr->dest_addr));
-               len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %5d %5d\n",
+               len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d\n",
                        ax2asc(&s->protinfo.nr->source_addr),
-                       devname, s->protinfo.nr->my_index, s->protinfo.nr->my_id,
-                       s->protinfo.nr->your_index, s->protinfo.nr->your_id,
+                       devname,
+                       s->protinfo.nr->my_index,
+                       s->protinfo.nr->my_id,
+                       s->protinfo.nr->your_index,
+                       s->protinfo.nr->your_id,
                        s->protinfo.nr->state,
-                       s->protinfo.nr->vs, s->protinfo.nr->vr, s->protinfo.nr->va,
-                       s->protinfo.nr->t1timer / NR_SLOWHZ,
-                       s->protinfo.nr->t1      / NR_SLOWHZ,
-                       s->protinfo.nr->t2timer / NR_SLOWHZ,
-                       s->protinfo.nr->t2      / NR_SLOWHZ,
+                       s->protinfo.nr->vs,
+                       s->protinfo.nr->vr,
+                       s->protinfo.nr->va,
+                       ax25_display_timer(&s->protinfo.nr->t1timer) / HZ,
+                       s->protinfo.nr->t1 / HZ,
+                       ax25_display_timer(&s->protinfo.nr->t2timer) / HZ,
+                       s->protinfo.nr->t2 / HZ,
+                       ax25_display_timer(&s->protinfo.nr->t4timer) / HZ,
+                       s->protinfo.nr->t4 / HZ,
+                       ax25_display_timer(&s->protinfo.nr->idletimer) / (60 * HZ),
+                       s->protinfo.nr->idle / (60 * HZ),
                        s->protinfo.nr->n2count,
                        s->protinfo.nr->n2,
                        s->protinfo.nr->window,
-                       atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
+                       atomic_read(&s->wmem_alloc),
+                       atomic_read(&s->rmem_alloc));
 
                pos = begin + len;
 
@@ -1269,7 +1277,7 @@ __initfunc(void nr_proto_init(struct net_proto *pro))
 
        sock_register(&nr_family_ops);
        register_netdevice_notifier(&nr_dev_notifier);
-       printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.6 for AX25.035 Linux 2.1\n");
+       printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.1\n");
 
        ax25_protocol_register(AX25_P_NETROM, nr_route_frame);
        ax25_linkfail_register(nr_link_failed);
index 2d88bec2bafa9cd973e396c9b908a28c952d8f9c..f7b617dccb14146dbf0b7b76ef974b14f0ea8473 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     NET/ROM release 006
+ *     NET/ROM release 007
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
index c13e92666174e6679aaa59d0afc23c60d9206296..a0d3148c2fdeacc3de0aef1f64587aec1d0b476f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     NET/ROM release 006
+ *     NET/ROM release 007
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -21,6 +21,7 @@
  *                     Darryl(G7LED)   Added missing INFO with NAK case, optimized
  *                                     INFOACK handling, removed reconnect on error.
  *     NET/ROM 006     Jonathan(G4KLX) Hdrincl removal changes.
+ *     NET/ROM 007     Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -54,6 +55,8 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
 
        skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
 
+       nr_start_idletimer(sk);
+
        if (more) {
                sk->protinfo.nr->fraglen += skb->len;
                skb_queue_tail(&sk->protinfo.nr->frag_queue, skb);
@@ -90,11 +93,10 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype
        switch (frametype) {
 
                case NR_CONNACK:
+                       nr_stop_t1timer(sk);
+                       nr_start_idletimer(sk);
                        sk->protinfo.nr->your_index = skb->data[17];
                        sk->protinfo.nr->your_id    = skb->data[18];
-                       sk->protinfo.nr->t1timer    = 0;
-                       sk->protinfo.nr->t2timer    = 0;
-                       sk->protinfo.nr->t4timer    = 0;
                        sk->protinfo.nr->vs         = 0;
                        sk->protinfo.nr->va         = 0;
                        sk->protinfo.nr->vr         = 0;
@@ -103,20 +105,12 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype
                        sk->protinfo.nr->n2count    = 0;
                        sk->protinfo.nr->window     = skb->data[20];
                        sk->state                   = TCP_ESTABLISHED;
-                       /* For WAIT_SABM connections we will produce an accept ready socket here */
                        if (!sk->dead)
                                sk->state_change(sk);
                        break;
 
                case NR_CONNACK | NR_CHOKE_FLAG:
-                       nr_clear_queues(sk);
-                       sk->protinfo.nr->state = NR_STATE_0;
-                       sk->state              = TCP_CLOSE;
-                       sk->err                = ECONNREFUSED;
-                       sk->shutdown          |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead               = 1;
+                       nr_disconnect(sk, ECONNREFUSED);
                        break;
 
                default:
@@ -139,13 +133,7 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype
                        nr_write_internal(sk, NR_DISCACK);
 
                case NR_DISCACK:
-                       sk->protinfo.nr->state = NR_STATE_0;
-                       sk->state              = TCP_CLOSE;
-                       sk->err                = 0;
-                       sk->shutdown          |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead               = 1;
+                       nr_disconnect(sk, 0);
                        break;
 
                default:
@@ -178,26 +166,12 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
                        break;
 
                case NR_DISCREQ:
-                       nr_clear_queues(sk);
                        nr_write_internal(sk, NR_DISCACK);
-                       sk->protinfo.nr->state = NR_STATE_0;
-                       sk->state              = TCP_CLOSE;
-                       sk->err                = 0;
-                       sk->shutdown          |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead               = 1;
+                       nr_disconnect(sk, 0);
                        break;
 
                case NR_DISCACK:
-                       nr_clear_queues(sk);
-                       sk->protinfo.nr->state = NR_STATE_0;
-                       sk->state              = TCP_CLOSE;
-                       sk->err                = ECONNRESET;
-                       sk->shutdown          |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead               = 1;
+                       nr_disconnect(sk, ECONNRESET);
                        break;
 
                case NR_INFOACK:
@@ -206,10 +180,10 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
                case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
                        if (frametype & NR_CHOKE_FLAG) {
                                sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY;
-                               sk->protinfo.nr->t4timer = sk->protinfo.nr->t4;
+                               nr_start_t4timer(sk);
                        } else {
                                sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
-                               sk->protinfo.nr->t4timer = 0;
+                               nr_stop_t4timer(sk);
                        }
                        if (!nr_validate_nr(sk, nr)) {
                                break;
@@ -236,10 +210,10 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
                case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
                        if (frametype & NR_CHOKE_FLAG) {
                                sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY;
-                               sk->protinfo.nr->t4timer = sk->protinfo.nr->t4;
+                               nr_start_t4timer(sk);
                        } else {
                                sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
-                               sk->protinfo.nr->t4timer = 0;
+                               nr_stop_t4timer(sk);
                        }
                        if (nr_validate_nr(sk, nr)) {
                                if (frametype & NR_NAK_FLAG) {
@@ -286,8 +260,8 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
                                nr_enquiry_response(sk);
                        } else {
                                if (!(sk->protinfo.nr->condition & NR_COND_ACK_PENDING)) {
-                                       sk->protinfo.nr->t2timer = sk->protinfo.nr->t2;
                                        sk->protinfo.nr->condition |= NR_COND_ACK_PENDING;
+                                       nr_start_t2timer(sk);
                                }
                        }
                        break;
@@ -307,8 +281,6 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
        if (sk->protinfo.nr->state == NR_STATE_0)
                return 0;
 
-       del_timer(&sk->timer);
-
        frametype = skb->data[19];
 
        switch (sk->protinfo.nr->state) {
@@ -323,7 +295,7 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
                        break;
        }
 
-       nr_set_timer(sk);
+       nr_kick(sk);
 
        return queued;
 }
index 7c053b4826247bfb95e960136c741811b3c34677..4c3eb61d8d412c97e20cd19f7ae17daa6f6a506f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     NET/ROM release 006
+ *     NET/ROM release 007
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -13,6 +13,7 @@
  *     NET/ROM 001     Jonathan(G4KLX) Cloned from ax25_out.c
  *     NET/ROM 003     Jonathan(G4KLX) Added NET/ROM fragmentation.
  *                     Darryl(G7LED)   Fixed NAK, to give out correct reponse.
+ *     NET/ROM 007     Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -83,8 +84,7 @@ void nr_output(struct sock *sk, struct sk_buff *skb)
                skb_queue_tail(&sk->write_queue, skb);          /* Throw it on the queue */
        }
 
-       if (sk->protinfo.nr->state == NR_STATE_3)
-               nr_kick(sk);
+       nr_kick(sk);
 }
 
 /* 
@@ -102,6 +102,8 @@ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
        if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)
                skb->data[4] |= NR_CHOKE_FLAG;
 
+       nr_start_idletimer(sk);
+
        nr_transmit_buffer(sk, skb);    
 }
 
@@ -125,7 +127,8 @@ void nr_send_nak_frame(struct sock *sk)
 
        sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
        sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
-       sk->protinfo.nr->t1timer    = 0;
+
+       nr_stop_t1timer(sk);
 }
 
 void nr_kick(struct sock *sk)
@@ -133,57 +136,60 @@ void nr_kick(struct sock *sk)
        struct sk_buff *skb, *skbn;
        unsigned short start, end;
 
-       del_timer(&sk->timer);
+       if (sk->protinfo.nr->state != NR_STATE_3)
+               return;
+
+       if (sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY)
+               return;
+
+       if (skb_peek(&sk->write_queue) == NULL)
+               return;
 
        start = (skb_peek(&sk->protinfo.nr->ack_queue) == NULL) ? sk->protinfo.nr->va : sk->protinfo.nr->vs;
        end   = (sk->protinfo.nr->va + sk->protinfo.nr->window) % NR_MODULUS;
 
-       if (!(sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY) &&
-           start != end                                         &&
-           skb_peek(&sk->write_queue) != NULL) {
-
-               sk->protinfo.nr->vs = start;
+       if (start == end)
+               return;
 
-               /*
-                * Transmit data until either we're out of data to send or
-                * the window is full.
-                */
+       sk->protinfo.nr->vs = start;
 
-               /*
-                * Dequeue the frame and copy it.
-                */
-               skb  = skb_dequeue(&sk->write_queue);
+       /*
+        * Transmit data until either we're out of data to send or
+        * the window is full.
+        */
 
-               do {
-                       if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
-                               skb_queue_head(&sk->write_queue, skb);
-                               break;
-                       }
+       /*
+        * Dequeue the frame and copy it.
+        */
+       skb  = skb_dequeue(&sk->write_queue);
 
-                       skb_set_owner_w(skbn, sk);
+       do {
+               if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+                       skb_queue_head(&sk->write_queue, skb);
+                       break;
+               }
 
-                       /*
-                        * Transmit the frame copy.
-                        */
-                       nr_send_iframe(sk, skbn);
+               skb_set_owner_w(skbn, sk);
 
-                       sk->protinfo.nr->vs = (sk->protinfo.nr->vs + 1) % NR_MODULUS;
+               /*
+                * Transmit the frame copy.
+                */
+               nr_send_iframe(sk, skbn);
 
-                       /*
-                        * Requeue the original data frame.
-                        */
-                       skb_queue_tail(&sk->protinfo.nr->ack_queue, skb);
+               sk->protinfo.nr->vs = (sk->protinfo.nr->vs + 1) % NR_MODULUS;
 
-               } while (sk->protinfo.nr->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+               /*
+                * Requeue the original data frame.
+                */
+               skb_queue_tail(&sk->protinfo.nr->ack_queue, skb);
 
-               sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
-               sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
+       } while (sk->protinfo.nr->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
 
-               if (sk->protinfo.nr->t1timer == 0)
-                       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
-       }
+       sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
+       sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
 
-       nr_set_timer(sk);
+       if (!nr_t1timer_running(sk))
+               nr_start_t1timer(sk);
 }
 
 void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
@@ -211,13 +217,7 @@ void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
 
        if (!nr_route_frame(skb, NULL)) {
                kfree_skb(skb, FREE_WRITE);
-
-               sk->state     = TCP_CLOSE;
-               sk->err       = ENETUNREACH;
-               sk->shutdown |= SEND_SHUTDOWN;
-               if (!sk->dead)
-                       sk->state_change(sk);
-               sk->dead      = 1;
+               nr_disconnect(sk, ENETUNREACH);
        }
 }
 
@@ -233,8 +233,10 @@ void nr_establish_data_link(struct sock *sk)
 
        nr_write_internal(sk, NR_CONNREQ);
 
-       sk->protinfo.nr->t2timer = 0;
-       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
+       nr_stop_t2timer(sk);
+       nr_stop_t4timer(sk);
+       nr_stop_idletimer(sk);
+       nr_start_t1timer(sk);
 }
 
 /*
@@ -261,12 +263,12 @@ void nr_check_iframes_acked(struct sock *sk, unsigned short nr)
 {
        if (sk->protinfo.nr->vs == nr) {
                nr_frames_acked(sk, nr);
-               sk->protinfo.nr->t1timer = 0;
+               nr_stop_t1timer(sk);
                sk->protinfo.nr->n2count = 0;
        } else {
                if (sk->protinfo.nr->va != nr) {
                        nr_frames_acked(sk, nr);
-                       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
+                       nr_start_t1timer(sk);
                }
        }
 }
index 41399a53caa35abfc42d0cfb8e60f5b926ab61cd..ffbb240c411af1c4829f1b3a85f74c9c996b14fd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     NET/ROM release 006
+ *     NET/ROM release 007
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -93,6 +93,7 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
 
                nr_neigh->callsign = *ax25;
                nr_neigh->digipeat = NULL;
+               nr_neigh->ax25     = NULL;
                nr_neigh->dev      = dev;
                nr_neigh->quality  = sysctl_netrom_default_path_quality;
                nr_neigh->locked   = 0;
@@ -372,6 +373,7 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct dev
 
        nr_neigh->callsign = *callsign;
        nr_neigh->digipeat = NULL;
+       nr_neigh->ax25     = NULL;
        nr_neigh->dev      = dev;
        nr_neigh->quality  = quality;
        nr_neigh->locked   = 1;
@@ -582,7 +584,7 @@ static ax25_digi *nr_call_to_digi(int ndigis, ax25_address *digipeaters)
        }
 
        ax25_digi.ndigi      = ndigis;
-       ax25_digi.lastrepeat = 0;
+       ax25_digi.lastrepeat = -1;
 
        return &ax25_digi;
 }
@@ -594,14 +596,12 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
 {
        struct nr_route_struct nr_route;
        struct device *dev;
-       int err;
 
        switch (cmd) {
 
                case SIOCADDRT:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
-                               return err;
-                       copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct));
+                       if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
+                               return -EFAULT;
                        if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
                                return -EINVAL;
                        if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS)
@@ -623,9 +623,8 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
                        }
 
                case SIOCDELRT:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
-                               return err;
-                       copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct));
+                       if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
+                               return -EFAULT;
                        if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
                                return -EINVAL;
                        switch (nr_route.type) {
@@ -653,17 +652,19 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
  *     A level 2 link has timed out, therefore it appears to be a poor link,
  *     then don't use that neighbour until it is reset.
  */
-void nr_link_failed(ax25_address *callsign, struct device *dev)
+void nr_link_failed(ax25_cb *ax25, int reason)
 {
        struct nr_neigh *nr_neigh;
        struct nr_node  *nr_node;
 
        for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
-               if (ax25cmp(&nr_neigh->callsign, callsign) == 0 && nr_neigh->dev == dev)
+               if (nr_neigh->ax25 == ax25)
                        break;
 
        if (nr_neigh == NULL) return;
 
+       nr_neigh->ax25 = NULL;
+
        if (++nr_neigh->failed < sysctl_netrom_link_fails_count) return;
 
        for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
@@ -724,7 +725,9 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        dptr  = skb_push(skb, 1);
        *dptr = AX25_P_NETROM;
 
-       return ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
+       nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
+
+       return (nr_neigh->ax25 != NULL);
 }
 
 int nr_nodes_get_info(char *buffer, char **start, off_t offset,
index 5eae252796b97d4fc858ae6097f604e3e0d59624..d311418769f7b16098c15cab7abedf3077ba7a04 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     NET/ROM release 006
+ *     NET/ROM release 007
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -12,6 +12,7 @@
  *     History
  *     NET/ROM 001     Jonathan(G4KLX) Cloned from ax25_subr.c
  *     NET/ROM 003     Jonathan(G4KLX) Added G8BPQ NET/ROM extensions.
+ *     NET/ROM 007     Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -172,7 +173,7 @@ void nr_write_internal(struct sock *sk, int frametype)
        switch (frametype & 0x0F) {
 
                case NR_CONNREQ:
-                       timeout  = sk->protinfo.nr->t1 / NR_SLOWHZ;
+                       timeout  = sk->protinfo.nr->t1 / HZ;
                        *dptr++  = sk->protinfo.nr->my_index;
                        *dptr++  = sk->protinfo.nr->my_id;
                        *dptr++  = 0;
@@ -268,4 +269,25 @@ void nr_transmit_dm(struct sk_buff *skb)
                kfree_skb(skbn, FREE_WRITE);
 }
 
+void nr_disconnect(struct sock *sk, int reason)
+{
+       nr_stop_t1timer(sk);
+       nr_stop_t2timer(sk);
+       nr_stop_t4timer(sk);
+       nr_stop_idletimer(sk);
+
+       nr_clear_queues(sk);
+
+       sk->protinfo.nr->state = NR_STATE_0;
+
+       sk->state     = TCP_CLOSE;
+       sk->err       = reason;
+       sk->shutdown |= SEND_SHUTDOWN;
+
+       if (!sk->dead)
+               sk->state_change(sk);
+
+       sk->dead = 1;
+}
+
 #endif
index cc96f26dd12e3cc93455cd03f19e0a0283734d82..b3fbd012ebac3efafde896c111e6ff776f2bf379 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     NET/ROM release 006
+ *     NET/ROM release 007
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -11,6 +11,8 @@
  *
  *     History
  *     NET/ROM 001     Jonathan(G4KLX) Cloned from ax25_timer.c
+ *     NET/ROM 007     Jonathan(G4KLX) New timer architecture.
+ *                                     Implemented idle timer.
  */
 
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <net/netrom.h>
 
-static void nr_timer(unsigned long);
+static void nr_heartbeat_expiry(unsigned long);
+static void nr_t1timer_expiry(unsigned long);
+static void nr_t2timer_expiry(unsigned long);
+static void nr_t4timer_expiry(unsigned long);
+static void nr_idletimer_expiry(unsigned long);
 
-/*
- *     Linux set timer
- */
-void nr_set_timer(struct sock *sk)
+void nr_start_t1timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.nr->t1timer);
+
+       sk->protinfo.nr->t1timer.data     = (unsigned long)sk;
+       sk->protinfo.nr->t1timer.function = &nr_t1timer_expiry;
+       sk->protinfo.nr->t1timer.expires  = jiffies + sk->protinfo.nr->t1;
+
+       add_timer(&sk->protinfo.nr->t1timer);
+}
+
+void nr_start_t2timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.nr->t2timer);
+
+       sk->protinfo.nr->t2timer.data     = (unsigned long)sk;
+       sk->protinfo.nr->t2timer.function = &nr_t2timer_expiry;
+       sk->protinfo.nr->t2timer.expires  = jiffies + sk->protinfo.nr->t2;
+
+       add_timer(&sk->protinfo.nr->t2timer);
+}
+
+void nr_start_t4timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.nr->t4timer);
+
+       sk->protinfo.nr->t4timer.data     = (unsigned long)sk;
+       sk->protinfo.nr->t4timer.function = &nr_t4timer_expiry;
+       sk->protinfo.nr->t4timer.expires  = jiffies + sk->protinfo.nr->t4;
+
+       add_timer(&sk->protinfo.nr->t4timer);
+}
+
+void nr_start_idletimer(struct sock *sk)
 {
-       unsigned long flags;
+       del_timer(&sk->protinfo.nr->idletimer);
+
+       if (sk->protinfo.nr->idle > 0) {
+               sk->protinfo.nr->idletimer.data     = (unsigned long)sk;
+               sk->protinfo.nr->idletimer.function = &nr_idletimer_expiry;
+               sk->protinfo.nr->idletimer.expires  = jiffies + sk->protinfo.nr->idle;
+
+               add_timer(&sk->protinfo.nr->idletimer);
+       }
+}
 
-       save_flags(flags); cli();
+void nr_start_heartbeat(struct sock *sk)
+{
        del_timer(&sk->timer);
-       restore_flags(flags);
 
        sk->timer.data     = (unsigned long)sk;
-       sk->timer.function = &nr_timer;
-       sk->timer.expires  = jiffies + (HZ / 10);
+       sk->timer.function = &nr_heartbeat_expiry;
+       sk->timer.expires  = jiffies + 5 * HZ;
 
        add_timer(&sk->timer);
 }
 
-/*
- *     NET/ROM TIMER 
- *
- *     This routine is called every 100ms. Decrement timer by this
- *     amount - if expired then process the event.
- */
-static void nr_timer(unsigned long param)
+void nr_stop_t1timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.nr->t1timer);
+}
+
+void nr_stop_t2timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.nr->t2timer);
+}
+
+void nr_stop_t4timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.nr->t4timer);
+}
+
+void nr_stop_idletimer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.nr->idletimer);
+}
+
+void nr_stop_heartbeat(struct sock *sk)
+{
+       del_timer(&sk->timer);
+}
+
+int nr_t1timer_running(struct sock *sk)
+{
+       return (sk->protinfo.nr->t1timer.prev != NULL ||
+               sk->protinfo.nr->t1timer.next != NULL);
+}
+
+static void nr_heartbeat_expiry(unsigned long param)
 {
        struct sock *sk = (struct sock *)param;
 
        switch (sk->protinfo.nr->state) {
+
                case NR_STATE_0:
                        /* Magic here: If we listen() and a new link dies before it
                           is accepted() it isn't 'dead' so doesn't get removed. */
                        if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
-                               del_timer(&sk->timer);
                                nr_destroy_socket(sk);
                                return;
                        }
@@ -90,45 +160,63 @@ static void nr_timer(unsigned long param)
                                nr_write_internal(sk, NR_INFOACK);
                                break;
                        }
-                       /*
-                        * Check for frames to transmit.
-                        */
-                       nr_kick(sk);
-                       break;
-
-               default:
                        break;
        }
 
-       if (sk->protinfo.nr->t2timer > 0 && --sk->protinfo.nr->t2timer == 0) {
-               if (sk->protinfo.nr->state == NR_STATE_3) {
-                       if (sk->protinfo.nr->condition & NR_COND_ACK_PENDING) {
-                               sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
-                               nr_enquiry_response(sk);
-                       }
-               }
-       }
+       nr_start_heartbeat(sk);
+}
 
-       if (sk->protinfo.nr->t4timer > 0 && --sk->protinfo.nr->t4timer == 0) {
-               sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
-       }
+static void nr_t2timer_expiry(unsigned long param)
+{
+       struct sock *sk = (struct sock *)param;
 
-       if (sk->protinfo.nr->t1timer == 0 || --sk->protinfo.nr->t1timer > 0) {
-               nr_set_timer(sk);
-               return;
+       if (sk->protinfo.nr->condition & NR_COND_ACK_PENDING) {
+               sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
+               nr_enquiry_response(sk);
        }
+}
+
+static void nr_t4timer_expiry(unsigned long param)
+{
+       struct sock *sk = (struct sock *)param;
+
+       sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
+}
+
+static void nr_idletimer_expiry(unsigned long param)
+{
+       struct sock *sk = (struct sock *)param;
+
+       nr_clear_queues(sk);
+
+       sk->protinfo.nr->n2count = 0;
+       nr_write_internal(sk, NR_DISCREQ);
+       sk->protinfo.nr->state = NR_STATE_2;
+
+       nr_start_t1timer(sk);
+       nr_stop_t2timer(sk);
+       nr_stop_t4timer(sk);
+
+       sk->state     = TCP_CLOSE;
+       sk->err       = 0;
+       sk->shutdown |= SEND_SHUTDOWN;
+
+       if (!sk->dead)
+               sk->state_change(sk);
+
+       sk->dead = 1;
+}
+
+static void nr_t1timer_expiry(unsigned long param)
+{
+       struct sock *sk = (struct sock *)param;
 
        switch (sk->protinfo.nr->state) {
+
                case NR_STATE_1: 
                        if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) {
-                               nr_clear_queues(sk);
-                               sk->protinfo.nr->state = NR_STATE_0;
-                               sk->state              = TCP_CLOSE;
-                               sk->err                = ETIMEDOUT;
-                               sk->shutdown          |= SEND_SHUTDOWN;
-                               if (!sk->dead)
-                                       sk->state_change(sk);
-                               sk->dead               = 1;
+                               nr_disconnect(sk, ETIMEDOUT);
+                               return;
                        } else {
                                sk->protinfo.nr->n2count++;
                                nr_write_internal(sk, NR_CONNREQ);
@@ -137,14 +225,8 @@ static void nr_timer(unsigned long param)
 
                case NR_STATE_2:
                        if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) {
-                               nr_clear_queues(sk);
-                               sk->protinfo.nr->state = NR_STATE_0;
-                               sk->state              = TCP_CLOSE;
-                               sk->err                = ETIMEDOUT;
-                               sk->shutdown          |= SEND_SHUTDOWN;
-                               if (!sk->dead)
-                                       sk->state_change(sk);
-                               sk->dead               = 1;
+                               nr_disconnect(sk, ETIMEDOUT);
+                               return;
                        } else {
                                sk->protinfo.nr->n2count++;
                                nr_write_internal(sk, NR_DISCREQ);
@@ -153,14 +235,8 @@ static void nr_timer(unsigned long param)
 
                case NR_STATE_3:
                        if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) {
-                               nr_clear_queues(sk);
-                               sk->protinfo.nr->state = NR_STATE_0;
-                               sk->state              = TCP_CLOSE;
-                               sk->err                = ETIMEDOUT;
-                               sk->shutdown          |= SEND_SHUTDOWN;
-                               if (!sk->dead)
-                                       sk->state_change(sk);
-                               sk->dead               = 1;
+                               nr_disconnect(sk, ETIMEDOUT);
+                               return;
                        } else {
                                sk->protinfo.nr->n2count++;
                                nr_requeue_frames(sk);
@@ -168,9 +244,7 @@ static void nr_timer(unsigned long param)
                        break;
        }
 
-       sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
-
-       nr_set_timer(sk);
+       nr_start_t1timer(sk);
 }
 
 #endif
index c6a415ee6ae579a4ba4755baa12edf4b00bb6ec8..3ce3e71f278126878b7414c28be034de2d786c54 100644 (file)
 static int min_quality[] = {0}, max_quality[] = {255};
 static int min_obs[]     = {0}, max_obs[]     = {255};
 static int min_ttl[]     = {0}, max_ttl[]     = {255};
-static int min_t1[]      = {5 * NR_SLOWHZ};
-static int max_t1[]      = {600 * NR_SLOWHZ};
+static int min_t1[]      = {5 * HZ};
+static int max_t1[]      = {600 * HZ};
 static int min_n2[]      = {2}, max_n2[]      = {127};
-static int min_t2[]      = {1 * NR_SLOWHZ};
-static int max_t2[]      = {60 * NR_SLOWHZ};
-static int min_t4[]      = {1 * NR_SLOWHZ};
-static int max_t4[]      = {1000 * NR_SLOWHZ};
+static int min_t2[]      = {1 * HZ};
+static int max_t2[]      = {60 * HZ};
+static int min_t4[]      = {1 * HZ};
+static int max_t4[]      = {1000 * HZ};
 static int min_window[]  = {1}, max_window[]  = {127};
-static int min_idle[]    = {0 * NR_SLOWHZ};
-static int max_idle[]    = {65535 * NR_SLOWHZ};
+static int min_idle[]    = {0 * HZ};
+static int max_idle[]    = {65535 * HZ};
 static int min_route[]   = {0}, max_route[]   = {1};
 static int min_fails[]   = {1}, max_fails[]   = {10};
 
index 9896de9cbd12fa9a7d337bdf45642a634dcffc8e..134eee17a27b5c6435321e52b0b861e09a760b82 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     ROSE release 002
+ *     ROSE release 003
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -17,6 +17,9 @@
  *     ROSE 002        Jonathan(G4KLX) Changed hdrincl to qbitincl.
  *                                     Added random number facilities entry.
  *                                     Variable number of ROSE devices.
+ *     ROSE 003        Jonathan(G4KLX) New timer architecture.
+ *                                     Implemented idle timer.
+ *                                     Added use count to neighbour.
  */
 
 #include <linux/config.h>
@@ -172,8 +175,7 @@ static void rose_remove_socket(struct sock *sk)
        struct sock *s;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        if ((s = rose_list) == sk) {
                rose_list = s->next;
@@ -204,13 +206,9 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
 
        for (s = rose_list; s != NULL; s = s->next) {
                if (s->protinfo.rose->neighbour == neigh) {
-                       s->protinfo.rose->state     = ROSE_STATE_0;
+                       rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
+                       s->protinfo.rose->neighbour->use--;
                        s->protinfo.rose->neighbour = NULL;
-                       s->state                    = TCP_CLOSE;
-                       s->err                      = ENETUNREACH;
-                       s->shutdown                |= SEND_SHUTDOWN;
-                       s->state_change(s);
-                       s->dead                     = 1;
                }
        }
 }
@@ -224,13 +222,9 @@ static void rose_kill_by_device(struct device *dev)
        
        for (s = rose_list; s != NULL; s = s->next) {
                if (s->protinfo.rose->device == dev) {
-                       s->protinfo.rose->state  = ROSE_STATE_0;
+                       rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
+                       s->protinfo.rose->neighbour->use--;
                        s->protinfo.rose->device = NULL;
-                       s->state                 = TCP_CLOSE;
-                       s->err                   = ENETUNREACH;
-                       s->shutdown             |= SEND_SHUTDOWN;
-                       s->state_change(s);
-                       s->dead                  = 1;
                }
        }
 }
@@ -265,8 +259,7 @@ static void rose_insert_socket(struct sock *sk)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        sk->next  = rose_list;
        rose_list = sk;
@@ -283,8 +276,7 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
        unsigned long flags;
        struct sock *s;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        for (s = rose_list; s != NULL; s = s->next) {
                if (rosecmp(&s->protinfo.rose->source_addr, addr) == 0 && ax25cmp(&s->protinfo.rose->source_call, call) == 0 && s->protinfo.rose->source_ndigis == 0 && s->state == TCP_LISTEN) {
@@ -312,8 +304,7 @@ struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh)
        struct sock *s;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        for (s = rose_list; s != NULL; s = s->next) {
                if (s->protinfo.rose->lci == lci && s->protinfo.rose->neighbour == neigh) {
@@ -371,10 +362,11 @@ void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the time
        struct sk_buff *skb;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
-       del_timer(&sk->timer);
+       rose_stop_heartbeat(sk);
+       rose_stop_idletimer(sk);
+       rose_stop_timer(sk);
 
        rose_remove_socket(sk);
        rose_clear_queues(sk);          /* Flush the queues */
@@ -382,7 +374,7 @@ void rose_destroy_socket(struct sock *sk)   /* Not static as it's used by the time
        while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
                if (skb->sk != sk) {                    /* A pending connection */
                        skb->sk->dead = 1;      /* Queue the unaccepted socket for death */
-                       rose_set_timer(skb->sk);
+                       rose_start_heartbeat(skb->sk);
                        skb->sk->protinfo.rose->state = ROSE_STATE_0;
                }
 
@@ -424,34 +416,38 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
                return -EFAULT;
 
        switch (optname) {
+               case ROSE_DEFER:
+                       sk->protinfo.rose->defer = opt ? 1 : 0;
+                       return 0;
+
                case ROSE_T1:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.rose->t1 = opt * ROSE_SLOWHZ;
+                       sk->protinfo.rose->t1 = opt * HZ;
                        return 0;
 
                case ROSE_T2:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.rose->t2 = opt * ROSE_SLOWHZ;
+                       sk->protinfo.rose->t2 = opt * HZ;
                        return 0;
 
                case ROSE_T3:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.rose->t3 = opt * ROSE_SLOWHZ;
+                       sk->protinfo.rose->t3 = opt * HZ;
                        return 0;
 
                case ROSE_HOLDBACK:
                        if (opt < 1)
                                return -EINVAL;
-                       sk->protinfo.rose->hb = opt * ROSE_SLOWHZ;
+                       sk->protinfo.rose->hb = opt * HZ;
                        return 0;
 
                case ROSE_IDLE:
-                       if (opt < 1)
+                       if (opt < 0)
                                return -EINVAL;
-                       sk->protinfo.rose->idle = opt * 60 * ROSE_SLOWHZ;
+                       sk->protinfo.rose->idle = opt * 60 * HZ;
                        return 0;
 
                case ROSE_QBITINCL:
@@ -477,24 +473,28 @@ static int rose_getsockopt(struct socket *sock, int level, int optname,
                return -EFAULT;
        
        switch (optname) {
+               case ROSE_DEFER:
+                       val = sk->protinfo.rose->defer;
+                       break;
+
                case ROSE_T1:
-                       val = sk->protinfo.rose->t1 / ROSE_SLOWHZ;
+                       val = sk->protinfo.rose->t1 / HZ;
                        break;
 
                case ROSE_T2:
-                       val = sk->protinfo.rose->t2 / ROSE_SLOWHZ;
+                       val = sk->protinfo.rose->t2 / HZ;
                        break;
 
                case ROSE_T3:
-                       val = sk->protinfo.rose->t3 / ROSE_SLOWHZ;
+                       val = sk->protinfo.rose->t3 / HZ;
                        break;
 
                case ROSE_HOLDBACK:
-                       val = sk->protinfo.rose->hb / ROSE_SLOWHZ;
+                       val = sk->protinfo.rose->hb / HZ;
                        break;
 
                case ROSE_IDLE:
-                       val = sk->protinfo.rose->idle / (ROSE_SLOWHZ * 60);
+                       val = sk->protinfo.rose->idle / (60 * HZ);
                        break;
 
                case ROSE_QBITINCL:
@@ -550,7 +550,10 @@ static int rose_create(struct socket *sock, int protocol)
        
        sock->ops    = &rose_proto_ops;
        sk->protocol = protocol;
-       sk->mtu      = ROSE_MTU;        /* 128 */
+       sk->mtu      = ROSE_MTU;        /* 253 */
+
+       init_timer(&rose->timer);
+       init_timer(&rose->idletimer);
 
        skb_queue_head_init(&rose->frag_queue);
 
@@ -592,6 +595,9 @@ static struct sock *rose_make_new(struct sock *osk)
        sk->sleep    = osk->sleep;
        sk->zapped   = osk->zapped;
 
+       init_timer(&rose->timer);
+       init_timer(&rose->idletimer);
+
        skb_queue_head_init(&rose->frag_queue);
 
        rose->t1      = osk->protinfo.rose->t1;
@@ -600,6 +606,7 @@ static struct sock *rose_make_new(struct sock *osk)
        rose->hb      = osk->protinfo.rose->hb;
        rose->idle    = osk->protinfo.rose->idle;
 
+       rose->defer    = osk->protinfo.rose->defer;
        rose->device   = osk->protinfo.rose->device;
        rose->qbitincl = osk->protinfo.rose->qbitincl;
 
@@ -625,28 +632,24 @@ static int rose_release(struct socket *sock, struct socket *peer)
        switch (sk->protinfo.rose->state) {
 
                case ROSE_STATE_0:
-                       sk->state     = TCP_CLOSE;
-                       sk->shutdown |= SEND_SHUTDOWN;
-                       sk->state_change(sk);
-                       sk->dead      = 1;
+                       rose_disconnect(sk, 0, -1, -1);
                        rose_destroy_socket(sk);
                        break;
 
                case ROSE_STATE_2:
-                       sk->protinfo.rose->state = ROSE_STATE_0;
-                       sk->state                = TCP_CLOSE;
-                       sk->shutdown            |= SEND_SHUTDOWN;
-                       sk->state_change(sk);
-                       sk->dead                 = 1;
+                       sk->protinfo.rose->neighbour->use--;
+                       rose_disconnect(sk, 0, -1, -1);
                        rose_destroy_socket(sk);
-                       break;                  
+                       break;
 
                case ROSE_STATE_1:
                case ROSE_STATE_3:
                case ROSE_STATE_4:
+               case ROSE_STATE_5:
                        rose_clear_queues(sk);
+                       rose_stop_idletimer(sk);
                        rose_write_internal(sk, ROSE_CLEAR_REQUEST);
-                       sk->protinfo.rose->timer = sk->protinfo.rose->t3;
+                       rose_start_t3timer(sk);
                        sk->protinfo.rose->state = ROSE_STATE_2;
                        sk->state                = TCP_CLOSE;
                        sk->shutdown            |= SEND_SHUTDOWN;
@@ -714,6 +717,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
 {
        struct sock *sk = sock->sk;
        struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
+       unsigned char cause, diagnostic;
        ax25_address *user;
        struct device *dev;
 
@@ -739,7 +743,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        if (addr->srose_family != AF_ROSE)
                return -EINVAL;
 
-       if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr)) == NULL)
+       if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic)) == NULL)
                return -ENETUNREACH;
 
        if ((sk->protinfo.rose->lci = rose_new_lci(sk->protinfo.rose->neighbour)) == 0)
@@ -775,10 +779,12 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        sk->state     = TCP_SYN_SENT;
 
        sk->protinfo.rose->state = ROSE_STATE_1;
-       sk->protinfo.rose->timer = sk->protinfo.rose->t1;
-       rose_write_internal(sk, ROSE_CALL_REQUEST);
 
-       rose_set_timer(sk);
+       sk->protinfo.rose->neighbour->use++;
+
+       rose_write_internal(sk, ROSE_CALL_REQUEST);
+       rose_start_heartbeat(sk);
+       rose_start_t1timer(sk);
 
        /* Now the loop */
        if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -911,11 +917,8 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
        /*
         *      skb->data points to the rose frame start
         */
-
-       /*
-        * XXX This is an error.
-        */
        if (!rose_parse_facilities(skb, &facilities)) {
+               rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76);
                return 0;
        }
 
@@ -925,7 +928,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
         * We can't accept the Call Request.
         */
        if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = rose_make_new(sk)) == NULL) {
-               rose_transmit_clear_request(neigh, lci, 0x01);
+               rose_transmit_clear_request(neigh, lci, ROSE_NETWORK_CONGESTION, 120);
                return 0;
        }
 
@@ -944,14 +947,21 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
        make->protinfo.rose->neighbour     = neigh;
        make->protinfo.rose->device        = dev;
 
-       rose_write_internal(make, ROSE_CALL_ACCEPTED);
+       make->protinfo.rose->neighbour->use++;
+
+       if (sk->protinfo.rose->defer) {
+               make->protinfo.rose->state = ROSE_STATE_5;
+       } else {
+               rose_write_internal(make, ROSE_CALL_ACCEPTED);
+               make->protinfo.rose->state = ROSE_STATE_3;
+               rose_start_idletimer(make);
+       }
 
        make->protinfo.rose->condition = 0x00;
        make->protinfo.rose->vs        = 0;
        make->protinfo.rose->va        = 0;
        make->protinfo.rose->vr        = 0;
        make->protinfo.rose->vl        = 0;
-       make->protinfo.rose->state     = ROSE_STATE_3;
        sk->ack_backlog++;
        make->pair = sk;
 
@@ -959,7 +969,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
 
        skb_queue_head(&sk->receive_queue, skb);
 
-       rose_set_timer(make);
+       rose_start_heartbeat(make);
 
        if (!sk->dead)
                sk->data_ready(sk, skb->len);
@@ -1146,37 +1156,35 @@ static int rose_shutdown(struct socket *sk, int how)
 static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
-       int err;
-       long amount = 0;
 
        switch (cmd) {
-               case TIOCOUTQ:
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int))) != 0)
-                               return err;
+               case TIOCOUTQ: {
+                       long amount;
                        amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
                        if (amount < 0)
                                amount = 0;
-                       put_user(amount, (unsigned int *)arg);
+                       if (put_user(amount, (unsigned int *)arg))
+                               return -EFAULT;
                        return 0;
+               }
 
                case TIOCINQ: {
                        struct sk_buff *skb;
+                       long amount = 0L;
                        /* These two are safe on a single CPU system as only user tasks fiddle here */
                        if ((skb = skb_peek(&sk->receive_queue)) != NULL)
-                               amount = skb->len - 20;
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int))) != 0)
-                               return err;
-                       put_user(amount, (unsigned int *)arg);
+                               amount = skb->len;
+                       if (put_user(amount, (unsigned int *)arg))
+                               return -EFAULT;
                        return 0;
                }
 
                case SIOCGSTAMP:
                        if (sk != NULL) {
-                               if (sk->stamp.tv_sec==0)
+                               if (sk->stamp.tv_sec == 0)
                                        return -ENOENT;
-                               if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0)
-                                       return err;
-                               copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval));
+                               if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+                                       return -EFAULT;
                                return 0;
                        }
                        return -EINVAL;
@@ -1195,20 +1203,51 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
                case SIOCADDRT:
                case SIOCDELRT:
+               case SIOCRSCLRRT:
                        if (!suser()) return -EPERM;
                        return rose_rt_ioctl(cmd, (void *)arg);
 
+               case SIOCRSGCAUSE: {
+                       struct rose_cause_struct rose_cause;
+                       rose_cause.cause      = sk->protinfo.rose->cause;
+                       rose_cause.diagnostic = sk->protinfo.rose->diagnostic;
+                       if (copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+               case SIOCRSSCAUSE: {
+                       struct rose_cause_struct rose_cause;
+                       if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct)))
+                               return -EFAULT;
+                       sk->protinfo.rose->cause      = rose_cause.cause;
+                       sk->protinfo.rose->diagnostic = rose_cause.diagnostic;
+                       return 0;
+               }
+
                case SIOCRSL2CALL:
                        if (!suser()) return -EPERM;
-                       if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_address))) != 0)
-                               return err;
                        if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
                                ax25_listen_release(&rose_callsign, NULL);
-                       copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address));
+                       if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address)))
+                               return -EFAULT;
                        if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
                                ax25_listen_register(&rose_callsign, NULL);
                        return 0;
 
+               case SIOCRSACCEPT:
+                       if (sk->protinfo.rose->state == ROSE_STATE_5) {
+                               rose_write_internal(sk, ROSE_CALL_ACCEPTED);
+                               rose_start_idletimer(sk);
+                               sk->protinfo.rose->condition = 0x00;
+                               sk->protinfo.rose->vs        = 0;
+                               sk->protinfo.rose->va        = 0;
+                               sk->protinfo.rose->vr        = 0;
+                               sk->protinfo.rose->vl        = 0;
+                               sk->protinfo.rose->state     = ROSE_STATE_3;
+                       }
+                       return 0;
+
                default:
                        return dev_ioctl(cmd, (void *)arg);
        }
@@ -1228,7 +1267,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
 
        cli();
 
-       len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci st vs vr va   t  t1  t2  t3  hb  Snd-Q Rcv-Q\n");
+       len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q\n");
 
        for (s = rose_list; s != NULL; s = s->next) {
                if ((dev = s->protinfo.rose->device) == NULL)
@@ -1245,17 +1284,24 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
                else
                        callsign = ax2asc(&s->protinfo.rose->source_call);
 
-               len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X  %d  %d  %d  %d %3d %3d %3d %3d %3d %5d %5d\n",
-                       rose2asc(&s->protinfo.rose->source_addr), callsign,
-                       devname,  s->protinfo.rose->lci & 0x0FFF,
+               len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d\n",
+                       rose2asc(&s->protinfo.rose->source_addr),
+                       callsign,
+                       devname, 
+                       s->protinfo.rose->lci & 0x0FFF,
                        s->protinfo.rose->state,
-                       s->protinfo.rose->vs, s->protinfo.rose->vr, s->protinfo.rose->va,
-                       s->protinfo.rose->timer / ROSE_SLOWHZ,
-                       s->protinfo.rose->t1    / ROSE_SLOWHZ,
-                       s->protinfo.rose->t2    / ROSE_SLOWHZ,
-                       s->protinfo.rose->t3    / ROSE_SLOWHZ,
-                       s->protinfo.rose->hb    / ROSE_SLOWHZ,
-                       atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
+                       s->protinfo.rose->vs,
+                       s->protinfo.rose->vr,
+                       s->protinfo.rose->va,
+                       ax25_display_timer(&s->protinfo.rose->timer) / HZ,
+                       s->protinfo.rose->t1 / HZ,
+                       s->protinfo.rose->t2 / HZ,
+                       s->protinfo.rose->t3 / HZ,
+                       s->protinfo.rose->hb / HZ,
+                       ax25_display_timer(&s->protinfo.rose->idletimer) / (60 * HZ),
+                       s->protinfo.rose->idle / (60 * HZ),
+                       atomic_read(&s->wmem_alloc),
+                       atomic_read(&s->rmem_alloc));
 
                pos = begin + len;
 
@@ -1360,7 +1406,7 @@ __initfunc(void rose_proto_init(struct net_proto *pro))
 
        sock_register(&rose_family_ops);
        register_netdevice_notifier(&rose_dev_notifier);
-       printk(KERN_INFO "G4KLX ROSE for Linux. Version 0.2 for AX25.035 Linux 2.1\n");
+       printk(KERN_INFO "G4KLX ROSE for Linux. Version 0.3 for AX25.037 Linux 2.1\n");
 
        ax25_protocol_register(AX25_P_ROSE, rose_route_frame);
        ax25_linkfail_register(rose_link_failed);
index 73d0aa55293f5b30c776be574345cbe88c4d0233..7861220eede8e6502086e17759ddb1a85bd45ebb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     ROSE release 002
+ *     ROSE release 003
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -101,7 +101,7 @@ static int rose_rebuild_header(struct sk_buff *skb)
        unsigned char *bp = (unsigned char *)skb->data;
        struct sk_buff *skbn;
 
-       if (!arp_find(bp + 7, skb)) {
+       if (arp_find(bp + 7, skb)) {
                kfree_skb(skb, FREE_WRITE);
                return 1;
        }
index 3c3e17b2b8ae6bd1d0b1d974bd109517cf7636d9..1ac11528dc9771d22363a668977760bf0df99b54 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     ROSE release 002
+ *     ROSE release 003
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -17,6 +17,8 @@
  *
  *     History
  *     ROSE 001        Jonathan(G4KLX) Cloned from nr_in.c
+ *     ROSE 002        Jonathan(G4KLX) Return cause and diagnostic codes from Clear Requests.
+ *     ROSE 003        Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -48,6 +50,8 @@ static int rose_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
 {
        struct sk_buff *skbo, *skbn = skb;
 
+       rose_start_idletimer(sk);
+
        if (more) {
                sk->protinfo.rose->fraglen += skb->len;
                skb_queue_tail(&sk->protinfo.rose->frag_queue, skb);
@@ -89,8 +93,9 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
        switch (frametype) {
 
                case ROSE_CALL_ACCEPTED:
+                       rose_stop_timer(sk);
+                       rose_start_idletimer(sk);
                        sk->protinfo.rose->condition = 0x00;
-                       sk->protinfo.rose->timer     = 0;
                        sk->protinfo.rose->vs        = 0;
                        sk->protinfo.rose->va        = 0;
                        sk->protinfo.rose->vr        = 0;
@@ -102,15 +107,9 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
                        break;
 
                case ROSE_CLEAR_REQUEST:
-                       rose_clear_queues(sk);
                        rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
-                       sk->protinfo.rose->state = ROSE_STATE_0;
-                       sk->state                = TCP_CLOSE;
-                       sk->err                  = ECONNREFUSED;
-                       sk->shutdown            |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                 = 1;
+                       rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
+                       sk->protinfo.rose->neighbour->use--;
                        break;
 
                default:
@@ -131,15 +130,13 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety
 
                case ROSE_CLEAR_REQUEST:
                        rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+                       rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+                       sk->protinfo.rose->neighbour->use--;
+                       break;
+
                case ROSE_CLEAR_CONFIRMATION:
-                       rose_clear_queues(sk);
-                       sk->protinfo.rose->state = ROSE_STATE_0;
-                       sk->state                = TCP_CLOSE;
-                       sk->err                  = 0;
-                       sk->shutdown            |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                 = 1;
+                       rose_disconnect(sk, 0, -1, -1);
+                       sk->protinfo.rose->neighbour->use--;
                        break;
 
                default:
@@ -161,9 +158,10 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
        switch (frametype) {
 
                case ROSE_RESET_REQUEST:
+                       rose_stop_timer(sk);
+                       rose_start_idletimer(sk);
                        rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
                        sk->protinfo.rose->condition = 0x00;
-                       sk->protinfo.rose->timer     = 0;
                        sk->protinfo.rose->vs        = 0;
                        sk->protinfo.rose->vr        = 0;
                        sk->protinfo.rose->va        = 0;
@@ -171,15 +169,9 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                        break;
 
                case ROSE_CLEAR_REQUEST:
-                       rose_clear_queues(sk);
                        rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
-                       sk->protinfo.rose->state = ROSE_STATE_0;
-                       sk->state                = TCP_CLOSE;
-                       sk->err                  = 0;
-                       sk->shutdown            |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                 = 1;
+                       rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+                       sk->protinfo.rose->neighbour->use--;
                        break;
 
                case ROSE_RR:
@@ -189,7 +181,6 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                        else
                                sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
                        if (!rose_validate_nr(sk, nr)) {
-                               rose_clear_queues(sk);
                                rose_write_internal(sk, ROSE_RESET_REQUEST);
                                sk->protinfo.rose->condition = 0x00;
                                sk->protinfo.rose->vs        = 0;
@@ -197,7 +188,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                                sk->protinfo.rose->va        = 0;
                                sk->protinfo.rose->vl        = 0;
                                sk->protinfo.rose->state     = ROSE_STATE_4;
-                               sk->protinfo.rose->timer     = sk->protinfo.rose->t2;
+                               rose_start_t2timer(sk);
+                               rose_stop_idletimer(sk);
                        } else {
                                if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
                                        sk->protinfo.rose->va = nr;
@@ -210,7 +202,6 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                case ROSE_DATA: /* XXX */
                        sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
                        if (!rose_validate_nr(sk, nr)) {
-                               rose_clear_queues(sk);
                                rose_write_internal(sk, ROSE_RESET_REQUEST);
                                sk->protinfo.rose->condition = 0x00;
                                sk->protinfo.rose->vs        = 0;
@@ -218,7 +209,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                                sk->protinfo.rose->va        = 0;
                                sk->protinfo.rose->vl        = 0;
                                sk->protinfo.rose->state     = ROSE_STATE_4;
-                               sk->protinfo.rose->timer     = sk->protinfo.rose->t2;
+                               rose_start_t2timer(sk);
+                               rose_stop_idletimer(sk);
                                break;
                        }
                        if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
@@ -242,11 +234,11 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                         */
                        if (((sk->protinfo.rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == sk->protinfo.rose->vr) {
                                sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
-                               sk->protinfo.rose->timer      = 0;
+                               rose_stop_timer(sk);
                                rose_enquiry_response(sk);
                        } else {
                                sk->protinfo.rose->condition |= ROSE_COND_ACK_PENDING;
-                               sk->protinfo.rose->timer      = sk->protinfo.rose->hb;
+                               rose_start_hbtimer(sk);
                        }
                        break;
 
@@ -270,7 +262,8 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
                case ROSE_RESET_REQUEST:
                        rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
                case ROSE_RESET_CONFIRMATION:
-                       sk->protinfo.rose->timer     = 0;
+                       rose_stop_timer(sk);
+                       rose_start_idletimer(sk);
                        sk->protinfo.rose->condition = 0x00;
                        sk->protinfo.rose->va        = 0;
                        sk->protinfo.rose->vr        = 0;
@@ -280,16 +273,9 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
                        break;
 
                case ROSE_CLEAR_REQUEST:
-                       rose_clear_queues(sk);
                        rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
-                       sk->protinfo.rose->timer = 0;
-                       sk->protinfo.rose->state = ROSE_STATE_0;
-                       sk->state                = TCP_CLOSE;
-                       sk->err                  = 0;
-                       sk->shutdown            |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                 = 1;
+                       rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+                       sk->protinfo.rose->neighbour->use--;
                        break;
 
                default:
@@ -299,6 +285,22 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
        return 0;
 }
 
+/*
+ * State machine for state 5, Awaiting Call Acceptance State.
+ * The handling of the timer(s) is in file rose_timer.c
+ * Handling of state 0 and connection release is in af_rose.c.
+ */
+static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype)
+{
+       if (frametype == ROSE_CLEAR_REQUEST) {
+               rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+               rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+               sk->protinfo.rose->neighbour->use--;
+       }
+
+       return 0;
+}
+
 /* Higher level upcall for a LAPB frame */
 int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
@@ -307,8 +309,6 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
        if (sk->protinfo.rose->state == ROSE_STATE_0)
                return 0;
 
-       del_timer(&sk->timer);
-
        frametype = rose_decode(skb, &ns, &nr, &q, &d, &m);
 
        switch (sk->protinfo.rose->state) {
@@ -324,9 +324,12 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
                case ROSE_STATE_4:
                        queued = rose_state4_machine(sk, skb, frametype);
                        break;
+               case ROSE_STATE_5:
+                       queued = rose_state5_machine(sk, skb, frametype);
+                       break;
        }
 
-       rose_set_timer(sk);
+       rose_kick(sk);
 
        return queued;
 }
index 86626511e735f320b3aa1835c73f490e72dc4d0a..b481e485feaf282db0af30f44016009bb317cfdc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     ROSE release 002
+ *     ROSE release 003
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -11,6 +11,7 @@
  *
  *     History
  *     ROSE 001        Jonathan(G4KLX) Cloned from rose_timer.c
+ *     ROSE 003        Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
 #include <linux/firewall.h>
 #include <net/rose.h>
 
-static void rose_link_timer(unsigned long);
+static void rose_ftimer_expiry(unsigned long);
+static void rose_t0timer_expiry(unsigned long);
 
-/*
- *     Linux set timer
- */
-void rose_link_set_timer(struct rose_neigh *neigh)
+void rose_start_ftimer(struct rose_neigh *neigh)
 {
-       unsigned long flags;
+       del_timer(&neigh->ftimer);
 
-       save_flags(flags); cli();
-       del_timer(&neigh->timer);
-       restore_flags(flags);
+       neigh->ftimer.data     = (unsigned long)neigh;
+       neigh->ftimer.function = &rose_ftimer_expiry;
+       neigh->ftimer.expires  = jiffies + sysctl_rose_link_fail_timeout;
 
-       neigh->timer.data     = (unsigned long)neigh;
-       neigh->timer.function = &rose_link_timer;
-       neigh->timer.expires  = jiffies + (HZ / 10);
+       add_timer(&neigh->ftimer);
+}
+
+void rose_start_t0timer(struct rose_neigh *neigh)
+{
+       del_timer(&neigh->t0timer);
 
-       add_timer(&neigh->timer);
+       neigh->t0timer.data     = (unsigned long)neigh;
+       neigh->t0timer.function = &rose_t0timer_expiry;
+       neigh->t0timer.expires  = jiffies + sysctl_rose_restart_request_timeout;
+
+       add_timer(&neigh->t0timer);
 }
 
-/*
- *     ROSE Link Timer
- *
- *     This routine is called every 100ms. Decrement timer by this
- *     amount - if expired then process the event.
- */
-static void rose_link_timer(unsigned long param)
+void rose_stop_ftimer(struct rose_neigh *neigh)
 {
-       struct rose_neigh *neigh = (struct rose_neigh *)param;
+       del_timer(&neigh->ftimer);
+}
 
-       if (neigh->ftimer > 0)
-               neigh->ftimer--;
+void rose_stop_t0timer(struct rose_neigh *neigh)
+{
+       del_timer(&neigh->t0timer);
+}
 
-       if (neigh->t0timer > 0) {
-               neigh->t0timer--;
+int rose_ftimer_running(struct rose_neigh *neigh)
+{
+       return (neigh->ftimer.prev != NULL || neigh->ftimer.next != NULL);
+}
 
-               if (neigh->t0timer == 0) {
-                       rose_transmit_restart_request(neigh);
-                       neigh->dce_mode = 0;
-                       neigh->t0timer  = sysctl_rose_restart_request_timeout;
-               }
-       }
+int rose_t0timer_running(struct rose_neigh *neigh)
+{
+       return (neigh->t0timer.prev != NULL || neigh->t0timer.next != NULL);
+}
 
-       if (neigh->ftimer > 0 || neigh->t0timer > 0)
-               rose_link_set_timer(neigh);
-       else
-               del_timer(&neigh->timer);
+static void rose_ftimer_expiry(unsigned long param)
+{
+}
+
+static void rose_t0timer_expiry(unsigned long param)
+{
+       struct rose_neigh *neigh = (struct rose_neigh *)param;
+
+       rose_transmit_restart_request(neigh);
+
+       neigh->dce_mode = 0;
+
+       rose_start_t0timer(neigh);
 }
 
 /*
@@ -101,7 +113,9 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
        else
                rose_call = &rose_callsign;
 
-       return ax25_send_frame(skb, 256, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+       neigh->ax25 = ax25_send_frame(skb, 256, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+
+       return (neigh->ax25 != NULL);
 }
 
 /*
@@ -118,7 +132,9 @@ static int rose_link_up(struct rose_neigh *neigh)
        else
                rose_call = &rose_callsign;
 
-       return ax25_link_up(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+       neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+
+       return (neigh->ax25 != NULL);
 }
 
 /*
@@ -130,17 +146,15 @@ void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigne
 
        switch (frametype) {
                case ROSE_RESTART_REQUEST:
-                       neigh->t0timer   = 0;
+                       rose_stop_t0timer(neigh);
                        neigh->restarted = 1;
-                       neigh->dce_mode  = (skb->data[3] == 0x00);
-                       del_timer(&neigh->timer);
+                       neigh->dce_mode  = (skb->data[3] == ROSE_DTE_ORIGINATED);
                        rose_transmit_restart_confirmation(neigh);
                        break;
 
                case ROSE_RESTART_CONFIRMATION:
-                       neigh->t0timer   = 0;
+                       rose_stop_t0timer(neigh);
                        neigh->restarted = 1;
-                       del_timer(&neigh->timer);
                        break;
 
                case ROSE_DIAGNOSTIC:
@@ -181,7 +195,7 @@ void rose_transmit_restart_request(struct rose_neigh *neigh)
        *dptr++ = ROSE_GFI;
        *dptr++ = 0x00;
        *dptr++ = ROSE_RESTART_REQUEST;
-       *dptr++ = 0x00;
+       *dptr++ = ROSE_DTE_ORIGINATED;
        *dptr++ = 0;
 
        if (!rose_send_frame(skb, neigh))
@@ -247,7 +261,7 @@ void rose_transmit_diagnostic(struct rose_neigh *neigh, unsigned char diag)
  * This routine is called when a Clear Request is needed outside of the context
  * of a connected socket.
  */
-void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause)
+void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause, unsigned char diagnostic)
 {
        struct sk_buff *skb;
        unsigned char *dptr;
@@ -267,7 +281,7 @@ void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, uns
        *dptr++ = ((lci >> 0) & 0xFF);
        *dptr++ = ROSE_CLEAR_REQUEST;
        *dptr++ = cause;
-       *dptr++ = 0x00;
+       *dptr++ = diagnostic;
 
        if (!rose_send_frame(skb, neigh))
                kfree_skb(skb, FREE_WRITE);
@@ -294,11 +308,10 @@ void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
        } else {
                skb_queue_tail(&neigh->queue, skb);
 
-               if (neigh->t0timer == 0) {
+               if (!rose_t0timer_running(neigh)) {
                        rose_transmit_restart_request(neigh);
                        neigh->dce_mode = 0;
-                       neigh->t0timer  = sysctl_rose_restart_request_timeout;
-                       rose_link_set_timer(neigh);
+                       rose_start_t0timer(neigh);
                }
        }
 }
index f0e212dc3fa85b6c12d206298984c1956db3bb22..0ed9f7480a23905c842f7299d350e94da68394e7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     ROSE release 002
+ *     ROSE release 003
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -11,6 +11,7 @@
  *
  *     History
  *     ROSE 001        Jonathan(G4KLX) Cloned from nr_out.c
+ *     ROSE 003        Jonathan(G4KLX) New timer architecture.
  */
 
 #include <linux/config.h>
@@ -80,8 +81,7 @@ void rose_output(struct sock *sk, struct sk_buff *skb)
                skb_queue_tail(&sk->write_queue, skb);          /* Throw it on the queue */
        }
 
-       if (sk->protinfo.rose->state == ROSE_STATE_3)
-               rose_kick(sk);
+       rose_kick(sk);
 }
 
 /* 
@@ -96,6 +96,8 @@ static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
        skb->data[2] |= (sk->protinfo.rose->vr << 5) & 0xE0;
        skb->data[2] |= (sk->protinfo.rose->vs << 1) & 0x0E;
 
+       rose_start_idletimer(sk);
+
        rose_transmit_link(skb, sk->protinfo.rose->neighbour);  
 }
 
@@ -104,36 +106,41 @@ void rose_kick(struct sock *sk)
        struct sk_buff *skb;
        unsigned short end;
 
-       del_timer(&sk->timer);
+       if (sk->protinfo.rose->state != ROSE_STATE_3)
+               return;
+
+       if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY)
+               return;
+
+       if (skb_peek(&sk->write_queue) == NULL)
+               return;
 
        end = (sk->protinfo.rose->va + sysctl_rose_window_size) % ROSE_MODULUS;
 
-       if (!(sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) &&
-           sk->protinfo.rose->vs != end                             &&
-           skb_peek(&sk->write_queue) != NULL) {
-               /*
-                * Transmit data until either we're out of data to send or
-                * the window is full.
-                */
+       if (sk->protinfo.rose->vs == end)
+               return;
 
-               skb  = skb_dequeue(&sk->write_queue);
+       /*
+        * Transmit data until either we're out of data to send or
+        * the window is full.
+        */
 
-               do {
-                       /*
-                        * Transmit the frame.
-                        */
-                       rose_send_iframe(sk, skb);
+       skb  = skb_dequeue(&sk->write_queue);
 
-                       sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
+       do {
+               /*
+                * Transmit the frame.
+                */
+               rose_send_iframe(sk, skb);
 
-               } while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+               sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
 
-               sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
-               sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
-               sk->protinfo.rose->timer      = 0;
-       }
+       } while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
 
-       rose_set_timer(sk);
+       sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
+       sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
+
+       rose_stop_timer(sk);
 }
 
 /*
@@ -150,7 +157,8 @@ void rose_enquiry_response(struct sock *sk)
 
        sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
        sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
-       sk->protinfo.rose->timer      = 0;
+
+       rose_stop_timer(sk);
 }
 
 void rose_check_iframes_acked(struct sock *sk, unsigned short nr)
index 5b1338609b5a40b8586c34be88e1c7fd3baefabc..43358644c4aab66e10ca88b1ce98404836d6d686 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     ROSE release 002
+ *     ROSE release 003
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -15,6 +15,8 @@
  *                                     address masks.
  *     ROSE 002        Jonathan(G4KLX) Uprated through routing of packets.
  *                                     Routing loop detection.
+ *     ROSE 003        Jonathan(G4KLX) New timer architecture.
+ *                                     Added use count to neighbours.
  */
 
 #include <linux/config.h>
@@ -80,24 +82,32 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
 
                rose_neigh->callsign  = rose_route->neighbour;
                rose_neigh->digipeat  = NULL;
+               rose_neigh->ax25      = NULL;
                rose_neigh->dev       = dev;
                rose_neigh->count     = 0;
+               rose_neigh->use       = 0;
                rose_neigh->dce_mode  = 0;
                rose_neigh->number    = rose_neigh_no++;
                rose_neigh->restarted = 0;
+
                skb_queue_head_init(&rose_neigh->queue);
-               rose_neigh->t0timer   = 0;
-               rose_neigh->ftimer    = 0;
-               init_timer(&rose_neigh->timer);
+
+               init_timer(&rose_neigh->ftimer);
+               init_timer(&rose_neigh->t0timer);
 
                if (rose_route->ndigis != 0) {
                        if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
                                kfree(rose_neigh);
                                return -ENOMEM;
                        }
-                       rose_neigh->digipeat->ndigi = rose_route->ndigis;
-                       for (i = 0; i < rose_route->ndigis; i++)
-                               rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i];
+
+                       rose_neigh->digipeat->ndigi      = rose_route->ndigis;
+                       rose_neigh->digipeat->lastrepeat = -1;
+
+                       for (i = 0; i < rose_route->ndigis; i++) {
+                               rose_neigh->digipeat->calls[i]    = rose_route->digipeaters[i];
+                               rose_neigh->digipeat->repeated[i] = 0;
+                       }
                }
 
                save_flags(flags); cli();
@@ -207,13 +217,13 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
        unsigned long flags;
        struct sk_buff *skb;
 
-       del_timer(&rose_neigh->timer);
+       rose_stop_ftimer(rose_neigh);
+       rose_stop_t0timer(rose_neigh);
 
        while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
                kfree_skb(skb, FREE_WRITE);
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        if ((s = rose_neigh_list) == rose_neigh) {
                rose_neigh_list = rose_neigh->next;
@@ -244,9 +254,14 @@ static void rose_remove_route(struct rose_route *rose_route)
 {
        struct rose_route *s;
        unsigned long flags;
-       
-       save_flags(flags);
-       cli();
+
+       if (rose_route->neigh1 != NULL)
+               rose_route->neigh1->use--;
+
+       if (rose_route->neigh2 != NULL)
+               rose_route->neigh2->use--;
+
+       save_flags(flags); cli();
 
        if ((s = rose_route_list) == rose_route) {
                rose_route_list = rose_route->next;
@@ -295,7 +310,7 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct device *de
                if (rose_node->neighbour[i] == rose_neigh) {
                        rose_neigh->count--;
 
-                       if (rose_neigh->count == 0)
+                       if (rose_neigh->count == 0 && rose_neigh->use == 0)
                                rose_remove_neigh(rose_neigh);
 
                        rose_node->count--;
@@ -380,6 +395,35 @@ void rose_route_device_down(struct device *dev)
        }
 }
 
+/*
+ *     Clear all nodes and neighbours out, except for neighbours with
+ *     active connections going through them.
+ */
+static int rose_clear_routes(void)
+{
+       struct rose_neigh *s, *rose_neigh = rose_neigh_list;
+       struct rose_node  *t, *rose_node  = rose_node_list;
+
+       while (rose_node != NULL) {
+               t         = rose_node;
+               rose_node = rose_node->next;
+
+               rose_remove_node(t);
+       }
+
+       while (rose_neigh != NULL) {
+               s          = rose_neigh;
+               rose_neigh = rose_neigh->next;
+
+               s->count = 0;
+
+               if (s->use == 0)
+                       rose_remove_neigh(s);
+       }
+
+       return 0;
+}
+
 /*
  *     Check that the device given is a valid AX.25 interface that is "up".
  */
@@ -440,20 +484,31 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig
 /*
  *     Find a neighbour given a ROSE address.
  */
-struct rose_neigh *rose_get_neigh(rose_address *addr)
+struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsigned char *diagnostic)
 {
        struct rose_node *node;
+       int failed = 0;
        int i;
 
        for (node = rose_node_list; node != NULL; node = node->next) {
                if (rosecmpm(addr, &node->address, node->mask) == 0) {
                        for (i = 0; i < node->count; i++) {
-                               if (node->neighbour[i]->ftimer == 0)
+                               if (!rose_ftimer_running(node->neighbour[i]))
                                        return node->neighbour[i];
+                               else
+                                       failed = 1;
                        }
                }
        }
 
+       if (failed) {
+               *cause      = ROSE_OUT_OF_ORDER;
+               *diagnostic = 0;
+       } else {
+               *cause      = ROSE_NOT_OBTAINABLE;
+               *diagnostic = 0;
+       }
+
        return NULL;
 }
 
@@ -464,14 +519,12 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
 {
        struct rose_route_struct rose_route;
        struct device *dev;
-       int err;
 
        switch (cmd) {
 
                case SIOCADDRT:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0)
-                               return err;
-                       copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct));
+                       if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
+                               return -EFAULT;
                        if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
                                return -EINVAL;
                        if (rose_dev_get(&rose_route.address) != NULL)  /* Can't add routes to ourself */
@@ -482,13 +535,15 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
                        return rose_add_node(&rose_route, dev);
 
                case SIOCDELRT:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0)
-                               return err;
-                       copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct));
+                       if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
+                               return -EFAULT;
                        if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
                                return -EINVAL;
                        return rose_del_node(&rose_route, dev);
 
+               case SIOCRSCLRRT:
+                       return rose_clear_routes();
+
                default:
                        return -EINVAL;
        }
@@ -502,10 +557,9 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
        struct sk_buff    *skb;
 
        rose_neigh->restarted = 0;
-       rose_neigh->t0timer   = 0;
-       rose_neigh->ftimer    = sysctl_rose_link_fail_timeout;
 
-       rose_link_set_timer(rose_neigh);
+       rose_stop_t0timer(rose_neigh);
+       rose_start_ftimer(rose_neigh);
 
        while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
                kfree_skb(skb, FREE_WRITE);
@@ -523,13 +577,15 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
                }
 
                if (rose_route->neigh1 == rose_neigh) {
+                       rose_route->neigh1->use--;
                        rose_route->neigh1 = NULL;
-                       rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, 0x0D);
+                       rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0);
                }
 
                if (rose_route->neigh2 == rose_neigh) {
+                       rose_route->neigh2->use--;
                        rose_route->neigh2 = NULL;
-                       rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, 0x0D);
+                       rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0);
                }
 
                rose_route = rose_route->next;
@@ -541,16 +597,18 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
  *     then don't use that neighbour until it is reset. Blow away all through
  *     routes and connections using this route.
  */
-void rose_link_failed(ax25_address *callsign, struct device *dev)
+void rose_link_failed(ax25_cb *ax25, int reason)
 {
        struct rose_neigh *rose_neigh;
 
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
-               if (ax25cmp(&rose_neigh->callsign, callsign) == 0 && rose_neigh->dev == dev)
+               if (rose_neigh->ax25 == ax25)
                        break;
 
        if (rose_neigh == NULL) return;
 
+       rose_neigh->ax25 = NULL;
+
        rose_del_route_by_neigh(rose_neigh);
        rose_kill_by_neigh(rose_neigh);
 }
@@ -583,6 +641,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        struct sock *sk;
        unsigned short frametype;
        unsigned int lci, new_lci;
+       unsigned char cause, diagnostic;
        struct device *dev;
        unsigned long flags;
 
@@ -604,7 +663,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        /*
         *      Obviously the link is working, halt the ftimer.
         */
-       rose_neigh->ftimer = 0;
+       rose_stop_ftimer(rose_neigh);
 
        /*
         *      LCI of zero is always for us, and its always a restart
@@ -631,7 +690,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                        return rose_rx_call_request(skb, dev, rose_neigh, lci);
 
        if (!sysctl_rose_routing_control) {
-               rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+               rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0);
                return 0;
        }
 
@@ -679,7 +738,10 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        if (frametype != ROSE_CALL_REQUEST)     /* XXX */
                return 0;
 
-       rose_parse_facilities(skb, &facilities);
+       if (!rose_parse_facilities(skb, &facilities)) {
+               rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76);
+               return 0;
+       }
 
        /*
         *      Check for routing loops.
@@ -691,25 +753,25 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                    ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) {
                        printk(KERN_DEBUG "ROSE: routing loop from %s\n", rose2asc(src_addr));
                        printk(KERN_DEBUG "ROSE:                to %s\n", rose2asc(dest_addr));
-                       rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+                       rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120);
                        return 0;
                }
        }
 
-       if ((new_neigh = rose_get_neigh(dest_addr)) == NULL) {
-               printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr));
-               rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+       if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
+               if (cause == ROSE_NOT_OBTAINABLE)
+                       printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr));
+               rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
                return 0;
        }
 
        if ((new_lci = rose_new_lci(new_neigh)) == 0) {
-               printk(KERN_DEBUG "ROSE: no spare VCs to %s\n", rose2asc(dest_addr));
-               rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+               rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71);
                return 0;
        }
 
        if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
-               rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+               rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120);
                return 0;
        }
 
@@ -723,6 +785,9 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        rose_route->lci2      = new_lci;
        rose_route->neigh2    = new_neigh;
 
+       rose_route->neigh1->use++;
+       rose_route->neigh2->use++;
+
        save_flags(flags); cli();
        rose_route->next = rose_route_list;
        rose_route_list  = rose_route;
@@ -790,21 +855,30 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset,
        int len     = 0;
        off_t pos   = 0;
        off_t begin = 0;
+       int i;
 
        cli();
 
-       len += sprintf(buffer, "addr  callsign  dev  count  mode  restart   t0   tf\n");
+       len += sprintf(buffer, "addr  callsign  dev  count use mode restart  t0  tf digipeaters\n");
 
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
-               len += sprintf(buffer + len, "%05d %-9s %-4s   %3d   %3s      %3s  %3d  %3d\n",
+               len += sprintf(buffer + len, "%05d %-9s %-4s   %3d %3d  %3s     %3s %3lu %3lu",
                        rose_neigh->number,
                        ax2asc(&rose_neigh->callsign),
                        rose_neigh->dev ? rose_neigh->dev->name : "???",
                        rose_neigh->count,
+                       rose_neigh->use,
                        (rose_neigh->dce_mode) ? "DCE" : "DTE",
                        (rose_neigh->restarted) ? "yes" : "no",
-                       rose_neigh->t0timer / ROSE_SLOWHZ,
-                       rose_neigh->ftimer  / ROSE_SLOWHZ);
+                       ax25_display_timer(&rose_neigh->t0timer) / HZ,
+                       ax25_display_timer(&rose_neigh->ftimer)  / HZ);
+
+               if (rose_neigh->digipeat != NULL) {
+                       for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
+                               len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
+               }
+
+               len += sprintf(buffer + len, "\n");
 
                pos = begin + len;
 
index 4e0530cb49626b84fa8bbe48710f698969e7a88f..ee710bd6e353b7a27fea6531f0e908d4d9bd5e39 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     ROSE release 002
+ *     ROSE release 003
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -11,6 +11,8 @@
  *
  *     History
  *     ROSE 001        Jonathan(G4KLX) Cloned from nr_subr.c
+ *     ROSE 002        Jonathan(G4KLX) Centralised disconnect processing.
+ *     ROSE 003        Jonathan(G4KLX) Added use count to neighbours.
  */
 
 #include <linux/config.h>
@@ -92,12 +94,8 @@ void rose_write_internal(struct sock *sk, int frametype)
                case ROSE_CALL_ACCEPTED:
                case ROSE_CLEAR_REQUEST:
                case ROSE_RESET_REQUEST:
-               case ROSE_DIAGNOSTIC:
                        len   += 2;
                        break;
-               case ROSE_INTERRUPT:
-                       len   += 1;
-                       break;
        }
 
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -137,24 +135,23 @@ void rose_write_internal(struct sock *sk, int frametype)
                        break;
 
                case ROSE_CLEAR_REQUEST:
-               case ROSE_RESET_REQUEST:
                        *dptr++ = ROSE_GFI | lci1;
                        *dptr++ = lci2;
                        *dptr++ = frametype;
-                       *dptr++ = 0x00;         /* XXX */
-                       *dptr++ = 0x00;         /* XXX */
+                       *dptr++ = sk->protinfo.rose->cause;
+                       *dptr++ = sk->protinfo.rose->diagnostic;
                        break;
 
-               case ROSE_INTERRUPT:
+               case ROSE_RESET_REQUEST:
                        *dptr++ = ROSE_GFI | lci1;
                        *dptr++ = lci2;
                        *dptr++ = frametype;
-                       *dptr++ = 0x00;         /* XXX */
+                       *dptr++ = ROSE_DTE_ORIGINATED;
+                       *dptr++ = 0;
                        break;
 
                case ROSE_RR:
                case ROSE_RNR:
-               case ROSE_REJ:
                        *dptr++ = ROSE_GFI | lci1;
                        *dptr++ = lci2;
                        *dptr   = frametype;
@@ -162,7 +159,6 @@ void rose_write_internal(struct sock *sk, int frametype)
                        break;
 
                case ROSE_CLEAR_CONFIRMATION:
-               case ROSE_INTERRUPT_CONFIRMATION:
                case ROSE_RESET_CONFIRMATION:
                        *dptr++ = ROSE_GFI | lci1;
                        *dptr++ = lci2;
@@ -191,23 +187,15 @@ int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
                case ROSE_CALL_ACCEPTED:
                case ROSE_CLEAR_REQUEST:
                case ROSE_CLEAR_CONFIRMATION:
-               case ROSE_INTERRUPT:
-               case ROSE_INTERRUPT_CONFIRMATION:
                case ROSE_RESET_REQUEST:
                case ROSE_RESET_CONFIRMATION:
-               case ROSE_RESTART_REQUEST:
-               case ROSE_RESTART_CONFIRMATION:
-               case ROSE_REGISTRATION_REQUEST:
-               case ROSE_REGISTRATION_CONFIRMATION:
-               case ROSE_DIAGNOSTIC:
                        return frame[2];
                default:
                        break;
        }
 
        if ((frame[2] & 0x1F) == ROSE_RR  ||
-           (frame[2] & 0x1F) == ROSE_RNR ||
-           (frame[2] & 0x1F) == ROSE_REJ) {
+           (frame[2] & 0x1F) == ROSE_RNR) {
                *nr = (frame[2] >> 5) & 0x07;
                return frame[2] & 0x1F;
        }
@@ -437,4 +425,30 @@ int rose_create_facilities(unsigned char *buffer, rose_cb *rose)
        return len;
 }
 
+void rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic)
+{
+       rose_stop_timer(sk);
+       rose_stop_idletimer(sk);
+
+       rose_clear_queues(sk);
+
+       sk->protinfo.rose->lci   = 0;
+       sk->protinfo.rose->state = ROSE_STATE_0;
+
+       if (cause != -1)
+               sk->protinfo.rose->cause = cause;
+
+       if (diagnostic != -1)
+               sk->protinfo.rose->diagnostic = diagnostic;
+
+       sk->state     = TCP_CLOSE;
+       sk->err       = reason;
+       sk->shutdown |= SEND_SHUTDOWN;
+
+       if (!sk->dead)
+               sk->state_change(sk);
+
+       sk->dead  = 1;
+}
+
 #endif
index 572975e5d3149187648dece2462e2b5ce1688672..718a64ec04d2aed8cfed9a3b02be15f355248107 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     ROSE release 002
+ *     ROSE release 003
  *
  *     This code REQUIRES 2.1.15 or higher/ NET3.038
  *
@@ -11,6 +11,8 @@
  *
  *     History
  *     ROSE 001        Jonathan(G4KLX) Cloned from nr_timer.c
+ *     ROSE 003        Jonathan(G4KLX) New timer architecture.
+ *                                     Implemented idle timer.
  */
 
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <net/rose.h>
 
-static void rose_timer(unsigned long);
+static void rose_heartbeat_expiry(unsigned long);
+static void rose_timer_expiry(unsigned long);
+static void rose_idletimer_expiry(unsigned long);
 
-/*
- *     Linux set timer
- */
-void rose_set_timer(struct sock *sk)
+void rose_start_heartbeat(struct sock *sk)
 {
-       unsigned long flags;
-
-       save_flags(flags); cli();
        del_timer(&sk->timer);
-       restore_flags(flags);
 
        sk->timer.data     = (unsigned long)sk;
-       sk->timer.function = &rose_timer;
-       sk->timer.expires  = jiffies + (HZ / 10);
+       sk->timer.function = &rose_heartbeat_expiry;
+       sk->timer.expires  = jiffies + 5 * HZ;
 
        add_timer(&sk->timer);
 }
 
-/*
- *     ROSE Timer
- *
- *     This routine is called every 100ms. Decrement timer by this
- *     amount - if expired then process the event.
- */
-static void rose_timer(unsigned long param)
+void rose_start_t1timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.rose->timer);
+
+       sk->protinfo.rose->timer.data     = (unsigned long)sk;
+       sk->protinfo.rose->timer.function = &rose_timer_expiry;
+       sk->protinfo.rose->timer.expires  = jiffies + sk->protinfo.rose->t1;
+
+       add_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_start_t2timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.rose->timer);
+
+       sk->protinfo.rose->timer.data     = (unsigned long)sk;
+       sk->protinfo.rose->timer.function = &rose_timer_expiry;
+       sk->protinfo.rose->timer.expires  = jiffies + sk->protinfo.rose->t2;
+
+       add_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_start_t3timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.rose->timer);
+
+       sk->protinfo.rose->timer.data     = (unsigned long)sk;
+       sk->protinfo.rose->timer.function = &rose_timer_expiry;
+       sk->protinfo.rose->timer.expires  = jiffies + sk->protinfo.rose->t3;
+
+       add_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_start_hbtimer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.rose->timer);
+
+       sk->protinfo.rose->timer.data     = (unsigned long)sk;
+       sk->protinfo.rose->timer.function = &rose_timer_expiry;
+       sk->protinfo.rose->timer.expires  = jiffies + sk->protinfo.rose->hb;
+
+       add_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_start_idletimer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.rose->idletimer);
+
+       if (sk->protinfo.rose->idle > 0) {
+               sk->protinfo.rose->idletimer.data     = (unsigned long)sk;
+               sk->protinfo.rose->idletimer.function = &rose_idletimer_expiry;
+               sk->protinfo.rose->idletimer.expires  = jiffies + sk->protinfo.rose->idle;
+
+               add_timer(&sk->protinfo.rose->idletimer);
+       }
+}
+
+void rose_stop_heartbeat(struct sock *sk)
+{
+       del_timer(&sk->timer);
+}
+
+void rose_stop_timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_stop_idletimer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.rose->idletimer);
+}
+
+static void rose_heartbeat_expiry(unsigned long param)
 {
        struct sock *sk = (struct sock *)param;
 
        switch (sk->protinfo.rose->state) {
+
                case ROSE_STATE_0:
                        /* Magic here: If we listen() and a new link dies before it
                           is accepted() it isn't 'dead' so doesn't get removed. */
                        if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
-                               del_timer(&sk->timer);
                                rose_destroy_socket(sk);
                                return;
                        }
@@ -87,57 +150,62 @@ static void rose_timer(unsigned long param)
                                sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
                                sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
                                sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
-                               sk->protinfo.rose->timer      = 0;
                                rose_write_internal(sk, ROSE_RR);
+                               rose_stop_timer(sk);    /* HB */
                                break;
                        }
-                       /*
-                        * Check for frames to transmit.
-                        */
-                       rose_kick(sk);
-                       break;
-
-               default:
                        break;
        }
 
-       if (sk->protinfo.rose->timer == 0 || --sk->protinfo.rose->timer > 0) {
-               rose_set_timer(sk);
-               return;
-       }
+       rose_start_heartbeat(sk);
+}
+
+static void rose_timer_expiry(unsigned long param)
+{
+       struct sock *sk = (struct sock *)param;
 
-       /*
-        * Timer has expired, it may have been T1, T2, T3 or HB. We can tell
-        * by the socket state.
-        */
        switch (sk->protinfo.rose->state) {
-               case ROSE_STATE_3:      /* HB */
-                       if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) {
-                               sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
-                               rose_enquiry_response(sk);
-                       }
-                       break;
 
                case ROSE_STATE_1:      /* T1 */
                case ROSE_STATE_4:      /* T2 */
                        rose_write_internal(sk, ROSE_CLEAR_REQUEST);
                        sk->protinfo.rose->state = ROSE_STATE_2;
-                       sk->protinfo.rose->timer = sk->protinfo.rose->t3;
+                       rose_start_t3timer(sk);
                        break;
 
                case ROSE_STATE_2:      /* T3 */
-                       rose_clear_queues(sk);
-                       sk->protinfo.rose->state = ROSE_STATE_0;
-                       sk->state                = TCP_CLOSE;
-                       sk->err                  = ETIMEDOUT;
-                       sk->shutdown            |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                 = 1;
+                       sk->protinfo.rose->neighbour->use--;
+                       rose_disconnect(sk, ETIMEDOUT, -1, -1);
+                       break;
+
+               case ROSE_STATE_3:      /* HB */
+                       if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) {
+                               sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
+                               rose_enquiry_response(sk);
+                       }
                        break;
        }
+}
+
+static void rose_idletimer_expiry(unsigned long param)
+{
+       struct sock *sk = (struct sock *)param;
+
+       rose_clear_queues(sk);
+
+       rose_write_internal(sk, ROSE_CLEAR_REQUEST);
+       sk->protinfo.rose->state = ROSE_STATE_2;
+
+       rose_start_t3timer(sk);
+
+       sk->state     = TCP_CLOSE;
+       sk->err       = 0;
+       sk->shutdown |= SEND_SHUTDOWN;  
+
+       if (!sk->dead)
+               sk->state_change(sk);
 
-       rose_set_timer(sk);
+       sk->dead = 1;
 }
 
 #endif
index 409f79b524b33f3df586e99c7467e2b7571072b5..ad45e3b4783b838f1bac743bb4fe0b8b1d3f139a 100644 (file)
 #include <net/ax25.h>
 #include <net/rose.h>
 
-static int min_timer[]  = {1 * ROSE_SLOWHZ};
-static int max_timer[]  = {300 * ROSE_SLOWHZ};
-static int min_idle[]   = {0 * ROSE_SLOWHZ};
-static int max_idle[]   = {65535 * ROSE_SLOWHZ};
+static int min_timer[]  = {1 * HZ};
+static int max_timer[]  = {300 * HZ};
+static int min_idle[]   = {0 * HZ};
+static int max_idle[]   = {65535 * HZ};
 static int min_route[]  = {0}, max_route[] = {1};
-static int min_ftimer[] = {60 * ROSE_SLOWHZ};
-static int max_ftimer[] = {600 * ROSE_SLOWHZ};
+static int min_ftimer[] = {60 * HZ};
+static int max_ftimer[] = {600 * HZ};
 static int min_maxvcs[] = {1}, max_maxvcs[] = {254};
 static int min_window[] = {1}, max_window[] = {7};
 
index 2587083bcfa48373b3af960241afd37bb326b830..ba5f5057ed4d5a3faf21df63fccdcb8d7663f8d9 100644 (file)
@@ -67,6 +67,7 @@
 #include <linux/socket.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
+#include <linux/dalloc.h>
 #include <linux/net.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
@@ -266,6 +267,7 @@ struct socket *sock_alloc(void)
        inode = get_empty_inode();
        if (!inode)
                return NULL;
+
        sock = socki_lookup(inode);
 
        inode->i_mode = S_IFSOCK;
index 18ce57684d293ccdad02da4205127dceba4ccf22..f487ae95adbd44f8ae10ccbe21ff66069c42b1d5 100644 (file)
@@ -13,6 +13,9 @@
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_SYSCTL
 
 extern int sysctl_unix_destroy_delay;
 extern int sysctl_unix_delete_delay;
@@ -26,3 +29,4 @@ ctl_table unix_table[] = {
         &proc_dointvec_jiffies},
        {0}
 };
+#endif
index a77380648477b1d0a152ef61d63d10519c1d2224..f59dd3a5140bd8150d8512543f6970ab7de99bbf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     X.25 Packet Layer release 001
+ *     X.25 Packet Layer release 002
  *
  *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *     releases, misbehave and/or generally screw up. It might even work. 
@@ -14,6 +14,8 @@
  *
  *     History
  *     X.25 001        Jonathan Naylor Started coding.
+ *     X.25 002        Jonathan Naylor Centralised disconnect handling.
+ *                                     New timer architecture.
  */
 
 #include <linux/config.h>
@@ -54,8 +56,6 @@ int sysctl_x25_reset_request_timeout   = X25_DEFAULT_T22;
 int sysctl_x25_clear_request_timeout   = X25_DEFAULT_T23;
 int sysctl_x25_ack_holdback_timeout    = X25_DEFAULT_T2;
 
-static unsigned int lci = 1;
-
 static struct sock *volatile x25_list = NULL;
 
 static struct proto_ops x25_proto_ops;
@@ -173,16 +173,9 @@ static void x25_kill_by_device(struct device *dev)
 {
        struct sock *s;
 
-       for (s = x25_list; s != NULL; s = s->next) {
-               if (s->protinfo.x25->neighbour->dev == dev) {
-                       s->protinfo.x25->state  = X25_STATE_0;
-                       s->state                = TCP_CLOSE;
-                       s->err                  = ENETUNREACH;
-                       s->shutdown            |= SEND_SHUTDOWN;
-                       s->state_change(s);
-                       s->dead                 = 1;
-               }
-       }
+       for (s = x25_list; s != NULL; s = s->next)
+               if (s->protinfo.x25->neighbour->dev == dev)
+                       x25_disconnect(s, ENETUNREACH, 0, 0);
 }
 
 /*
@@ -254,9 +247,9 @@ static struct sock *x25_find_listener(x25_address *addr)
 }
 
 /*
- *     Find a connected X.25 socket given my LCI.
+ *     Find a connected X.25 socket given my LCI and neighbour.
  */
-struct sock *x25_find_socket(unsigned int lci)
+struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
 {
        struct sock *s;
        unsigned long flags;
@@ -265,7 +258,7 @@ struct sock *x25_find_socket(unsigned int lci)
        cli();
 
        for (s = x25_list; s != NULL; s = s->next) {
-               if (s->protinfo.x25->lci == lci) {
+               if (s->protinfo.x25->lci == lci && s->protinfo.x25->neighbour == neigh) {
                        restore_flags(flags);
                        return s;
                }
@@ -278,14 +271,13 @@ struct sock *x25_find_socket(unsigned int lci)
 /*
  *     Find a unique LCI for a given device.
  */
-unsigned int x25_new_lci(void)
+unsigned int x25_new_lci(struct x25_neigh *neigh)
 {
-       lci++;
-       if (lci > 4095) lci = 1;
+       unsigned int lci = 1;
 
-       while (x25_find_socket(lci) != NULL) {
+       while (x25_find_socket(lci, neigh) != NULL) {
                lci++;
-               if (lci > 4095) lci = 1;
+               if (lci == 4096) return 0;
        }
 
        return lci;
@@ -318,7 +310,8 @@ void x25_destroy_socket(struct sock *sk)    /* Not static as it's used by the timer
        save_flags(flags);
        cli();
 
-       del_timer(&sk->timer);
+       x25_stop_heartbeat(sk);
+       x25_stop_timer(sk);
 
        x25_remove_socket(sk);
        x25_clear_queues(sk);           /* Flush the queues */
@@ -326,7 +319,7 @@ void x25_destroy_socket(struct sock *sk)    /* Not static as it's used by the timer
        while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
                if (skb->sk != sk) {            /* A pending connection */
                        skb->sk->dead = 1;      /* Queue the unaccepted socket for death */
-                       x25_set_timer(skb->sk);
+                       x25_start_heartbeat(skb->sk);
                        skb->sk->protinfo.x25->state = X25_STATE_0;
                }
 
@@ -469,6 +462,8 @@ static int x25_create(struct socket *sock, int protocol)
 
        sock_init_data(sock, sk);
 
+       init_timer(&x25->timer);
+
        sock->ops    = &x25_proto_ops;
        sk->protocol = protocol;
        sk->mtu      = X25_DEFAULT_PACKET_SIZE; /* X25_PS128 */
@@ -523,6 +518,8 @@ static struct sock *x25_make_new(struct sock *osk)
 
        x25->qbitincl   = osk->protinfo.x25->qbitincl;
 
+       init_timer(&x25->timer);
+
        return sk;
 }
 
@@ -545,28 +542,17 @@ static int x25_release(struct socket *sock, struct socket *peer)
        switch (sk->protinfo.x25->state) {
 
                case X25_STATE_0:
-                       sk->state     = TCP_CLOSE;
-                       sk->shutdown |= SEND_SHUTDOWN;
-                       sk->state_change(sk);
-                       sk->dead      = 1;
-                       x25_destroy_socket(sk);
-                       break;
-
                case X25_STATE_2:
-                       sk->protinfo.x25->state = X25_STATE_0;
-                       sk->state               = TCP_CLOSE;
-                       sk->shutdown           |= SEND_SHUTDOWN;
-                       sk->state_change(sk);
-                       sk->dead                = 1;
+                       x25_disconnect(sk, 0, 0, 0);
                        x25_destroy_socket(sk);
-                       break;                  
+                       break;
 
                case X25_STATE_1:
                case X25_STATE_3:
                case X25_STATE_4:
                        x25_clear_queues(sk);
                        x25_write_internal(sk, X25_CLEAR_REQUEST);
-                       sk->protinfo.x25->timer = sk->protinfo.x25->t23;
+                       x25_start_t23timer(sk);
                        sk->protinfo.x25->state = X25_STATE_2;
                        sk->state               = TCP_CLOSE;
                        sk->shutdown           |= SEND_SHUTDOWN;
@@ -644,6 +630,9 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
        if ((sk->protinfo.x25->neighbour = x25_get_neigh(dev)) == NULL)
                return -ENETUNREACH;
 
+       if ((sk->protinfo.x25->lci = x25_new_lci(sk->protinfo.x25->neighbour)) == 0)
+               return -ENETUNREACH;
+
        if (sk->zapped)         /* Must bind first - autobinding does not work */
                return -EINVAL;
 
@@ -651,17 +640,17 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
                memset(&sk->protinfo.x25->source_addr, '\0', X25_ADDR_LEN);
 
        sk->protinfo.x25->dest_addr = addr->sx25_addr;
-       sk->protinfo.x25->lci       = x25_new_lci();
 
        /* Move to connecting socket, start sending Connect Requests */
        sock->state   = SS_CONNECTING;
        sk->state     = TCP_SYN_SENT;
 
        sk->protinfo.x25->state = X25_STATE_1;
-       sk->protinfo.x25->timer = sk->protinfo.x25->t21;
+
        x25_write_internal(sk, X25_CALL_REQUEST);
 
-       x25_set_timer(sk);
+       x25_start_heartbeat(sk);
+       x25_start_t21timer(sk);
 
        /* Now the loop */
        if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -850,7 +839,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
 
        skb_queue_head(&sk->receive_queue, skb);
 
-       x25_set_timer(make);
+       x25_start_heartbeat(make);
 
        if (!sk->dead)
                sk->data_ready(sk, skb->len);
@@ -987,8 +976,7 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
                x25_output(sk, skb);
        }
 
-       if (sk->protinfo.x25->state == X25_STATE_3)
-               x25_kick(sk);
+       x25_kick(sk);
 
        return len;
 }
@@ -1072,30 +1060,27 @@ static int x25_shutdown(struct socket *sk, int how)
 
 static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-       struct x25_facilities facilities;
-       struct x25_calluserdata calluserdata;
        struct sock *sk = sock->sk;
-       int err;
-       long amount = 0;
 
        switch (cmd) {
-               case TIOCOUTQ:
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
-                               return err;
+               case TIOCOUTQ: {
+                       long amount;
                        amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
                        if (amount < 0)
                                amount = 0;
-                       put_user(amount, (unsigned long *)arg);
+                       if (put_user(amount, (unsigned long *)arg))
+                               return -EFAULT;
                        return 0;
+               }
 
                case TIOCINQ: {
                        struct sk_buff *skb;
+                       long amount = 0L;
                        /* These two are safe on a single CPU system as only user tasks fiddle here */
                        if ((skb = skb_peek(&sk->receive_queue)) != NULL)
-                               amount = skb->len - 20;
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
-                               return err;
-                       put_user(amount, (unsigned long *)arg);
+                               amount = skb->len;
+                       if (put_user(amount, (unsigned long *)arg))
+                               return -EFAULT;
                        return 0;
                }
 
@@ -1103,9 +1088,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        if (sk != NULL) {
                                if (sk->stamp.tv_sec == 0)
                                        return -ENOENT;
-                               if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0)
-                                       return err;
-                               copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval));
+                               if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+                                       return -EFAULT;
                                return 0;
                        }
                        return -EINVAL;
@@ -1134,17 +1118,18 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        if (!suser()) return -EPERM;
                        return x25_subscr_ioctl(cmd, (void *)arg);
 
-               case SIOCX25GFACILITIES:
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(facilities))) != 0)
-                               return err;
+               case SIOCX25GFACILITIES: {
+                       struct x25_facilities facilities;
                        facilities = sk->protinfo.x25->facilities;
-                       copy_to_user((void *)arg, &facilities, sizeof(facilities));
+                       if (copy_to_user((void *)arg, &facilities, sizeof(facilities)))
+                               return -EFAULT;
                        return 0;
+               }
 
-               case SIOCX25SFACILITIES:
-                       if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(facilities))) != 0)
-                               return err;
-                       copy_from_user(&facilities, (void *)arg, sizeof(facilities));
+               case SIOCX25SFACILITIES: {
+                       struct x25_facilities facilities;
+                       if (copy_from_user(&facilities, (void *)arg, sizeof(facilities)))
+                               return -EFAULT;
                        if (sk->state != TCP_LISTEN)
                                return -EINVAL;
                        if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096)
@@ -1168,22 +1153,33 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                                return -EINVAL;
                        sk->protinfo.x25->facilities = facilities;
                        return 0;
+               }
 
-               case SIOCX25GCALLUSERDATA:
-                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(calluserdata))) != 0)
-                               return err;
+               case SIOCX25GCALLUSERDATA: {
+                       struct x25_calluserdata calluserdata;
                        calluserdata = sk->protinfo.x25->calluserdata;
-                       copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata));
+                       if (copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata)))
+                               return -EFAULT;
                        return 0;
+               }
 
-               case SIOCX25SCALLUSERDATA:
-                       if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(calluserdata))) != 0)
-                               return err;
-                       copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata));
+               case SIOCX25SCALLUSERDATA: {
+                       struct x25_calluserdata calluserdata;
+                       if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata)))
+                               return -EFAULT;
                        if (calluserdata.cudlength > X25_MAX_CUD_LEN)
                                return -EINVAL;
                        sk->protinfo.x25->calluserdata = calluserdata;
                        return 0;
+               }
+
+               case SIOCX25GCAUSEDIAG: {
+                       struct x25_causediag causediag;
+                       causediag = sk->protinfo.x25->causediag;
+                       if (copy_to_user((void *)arg, &causediag, sizeof(causediag)))
+                               return -EFAULT;
+                       return 0;
+               }
 
                default:
                        return dev_ioctl(cmd, (void *)arg);
@@ -1212,18 +1208,22 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length, in
                else
                        devname = s->protinfo.x25->neighbour->dev->name;
 
-               len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3d %3d %3d %3d %3d %5d %5d\n",
+               len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %5d %5d\n",
                        (s->protinfo.x25->dest_addr.x25_addr[0] == '\0')   ? "*" : s->protinfo.x25->dest_addr.x25_addr,
                        (s->protinfo.x25->source_addr.x25_addr[0] == '\0') ? "*" : s->protinfo.x25->source_addr.x25_addr,
-                       devname,  s->protinfo.x25->lci & 0x0FFF,
+                       devname, 
+                       s->protinfo.x25->lci & 0x0FFF,
                        s->protinfo.x25->state,
-                       s->protinfo.x25->vs, s->protinfo.x25->vr, s->protinfo.x25->va,
-                       s->protinfo.x25->timer / X25_SLOWHZ,
-                       s->protinfo.x25->t2    / X25_SLOWHZ,
-                       s->protinfo.x25->t21   / X25_SLOWHZ,
-                       s->protinfo.x25->t22   / X25_SLOWHZ,
-                       s->protinfo.x25->t23   / X25_SLOWHZ,
-                       atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
+                       s->protinfo.x25->vs,
+                       s->protinfo.x25->vr,
+                       s->protinfo.x25->va,
+                       x25_display_timer(s) / HZ,
+                       s->protinfo.x25->t2  / HZ,
+                       s->protinfo.x25->t21 / HZ,
+                       s->protinfo.x25->t22 / HZ,
+                       s->protinfo.x25->t23 / HZ,
+                       atomic_read(&s->wmem_alloc),
+                       atomic_read(&s->rmem_alloc));
 
                pos = begin + len;
 
@@ -1310,7 +1310,7 @@ __initfunc(void x25_proto_init(struct net_proto *pro))
 
        register_netdevice_notifier(&x25_dev_notifier);
 
-       printk(KERN_INFO "X.25 for Linux. Version 0.1 for Linux 2.1.15\n");
+       printk(KERN_INFO "X.25 for Linux. Version 0.2 for Linux 2.1.15\n");
 
 #ifdef CONFIG_SYSCTL
        x25_register_sysctl();
index 8454ac9d962cf8b64260f7ed63649148e09c3794..42893df320cf8347d85811fecd5109310e4d676b 100644 (file)
@@ -13,8 +13,8 @@
 #include <linux/init.h>
 #include <net/x25.h>
 
-static int min_timer[] = {1   * X25_SLOWHZ};
-static int max_timer[] = {300 * X25_SLOWHZ};
+static int min_timer[] = {1   * HZ};
+static int max_timer[] = {300 * HZ};
 
 static struct ctl_table_header *x25_table_header;
 
index 6b02a944175fa21e0897fffaecb9f0d9670f8433..e4cd99ae7ba4fcb560f54052d64a8f9d4ab9faa2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     X.25 Packet Layer release 001
+ *     X.25 Packet Layer release 002
  *
  *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *     releases, misbehave and/or generally screw up. It might even work. 
@@ -73,7 +73,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
        /*
         *      Find an existing socket.
         */
-       if ((sk = x25_find_socket(lci)) != NULL) {
+       if ((sk = x25_find_socket(lci, neigh)) != NULL) {
                skb->h.raw = skb->data;
                return x25_process_rx_frame(sk, skb);
        }
index 13759d1eaa88df2362933012090fb4cae4fbea0d..af072ce22dbe2b59d08d963937c2d9602f83a2c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     X.25 Packet Layer release 001
+ *     X.25 Packet Layer release 002
  *
  *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *     releases, misbehave and/or generally screw up. It might even work. 
index 82e5c0817abd0e9872b8beaeec797f1e6d7a3faa..96b459a4ee19689250091a62c4e3a98052644cbc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     X.25 Packet Layer release 001
+ *     X.25 Packet Layer release 002
  *
  *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *     releases, misbehave and/or generally screw up. It might even work. 
@@ -14,6 +14,8 @@
  *
  *     History
  *     X.25 001        Jonathan Naylor Started coding.
+ *     X.25 002        Jonathan Naylor Centralised disconnection code.
+ *                                     New timer architecture.
  */
 
 #include <linux/config.h>
@@ -88,8 +90,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
        switch (frametype) {
 
                case X25_CALL_ACCEPTED:
+                       x25_stop_timer(sk);
                        sk->protinfo.x25->condition = 0x00;
-                       sk->protinfo.x25->timer     = 0;
                        sk->protinfo.x25->vs        = 0;
                        sk->protinfo.x25->va        = 0;
                        sk->protinfo.x25->vr        = 0;
@@ -114,15 +116,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                        break;
 
                case X25_CLEAR_REQUEST:
-                       x25_clear_queues(sk);
                        x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
-                       sk->protinfo.x25->state = X25_STATE_0;
-                       sk->state               = TCP_CLOSE;
-                       sk->err                 = ECONNREFUSED;
-                       sk->shutdown           |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                = 1;
+                       x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
                        break;
 
                default:
@@ -143,15 +138,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
 
                case X25_CLEAR_REQUEST:
                        x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
+                       x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
+                       break;
+
                case X25_CLEAR_CONFIRMATION:
-                       x25_clear_queues(sk);
-                       sk->protinfo.x25->state = X25_STATE_0;
-                       sk->state               = TCP_CLOSE;
-                       sk->err                 = 0;
-                       sk->shutdown           |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                = 1;
+                       x25_disconnect(sk, 0, 0, 0);
                        break;
 
                default:
@@ -177,8 +168,8 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
 
                case X25_RESET_REQUEST:
                        x25_write_internal(sk, X25_RESET_CONFIRMATION);
+                       x25_stop_timer(sk);
                        sk->protinfo.x25->condition = 0x00;
-                       sk->protinfo.x25->timer     = 0;
                        sk->protinfo.x25->vs        = 0;
                        sk->protinfo.x25->vr        = 0;
                        sk->protinfo.x25->va        = 0;
@@ -186,15 +177,8 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                        break;
 
                case X25_CLEAR_REQUEST:
-                       x25_clear_queues(sk);
                        x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
-                       sk->protinfo.x25->state = X25_STATE_0;
-                       sk->state               = TCP_CLOSE;
-                       sk->err                 = 0;
-                       sk->shutdown           |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                = 1;
+                       x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
                        break;
 
                case X25_RR:
@@ -207,13 +191,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                        if (!x25_validate_nr(sk, nr)) {
                                x25_clear_queues(sk);
                                x25_write_internal(sk, X25_RESET_REQUEST);
+                               x25_start_t22timer(sk);
                                sk->protinfo.x25->condition = 0x00;
                                sk->protinfo.x25->vs        = 0;
                                sk->protinfo.x25->vr        = 0;
                                sk->protinfo.x25->va        = 0;
                                sk->protinfo.x25->vl        = 0;
                                sk->protinfo.x25->state     = X25_STATE_4;
-                               sk->protinfo.x25->timer     = sk->protinfo.x25->t22;
                        } else {
                                if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
                                        sk->protinfo.x25->va = nr;
@@ -228,13 +212,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                        if (!x25_validate_nr(sk, nr)) {
                                x25_clear_queues(sk);
                                x25_write_internal(sk, X25_RESET_REQUEST);
+                               x25_start_t22timer(sk);
                                sk->protinfo.x25->condition = 0x00;
                                sk->protinfo.x25->vs        = 0;
                                sk->protinfo.x25->vr        = 0;
                                sk->protinfo.x25->va        = 0;
                                sk->protinfo.x25->vl        = 0;
                                sk->protinfo.x25->state     = X25_STATE_4;
-                               sk->protinfo.x25->timer     = sk->protinfo.x25->t22;
                                break;
                        }
                        if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
@@ -258,11 +242,11 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                         */
                        if (((sk->protinfo.x25->vl + sk->protinfo.x25->facilities.winsize_in) % modulus) == sk->protinfo.x25->vr) {
                                sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
-                               sk->protinfo.x25->timer      = 0;
+                               x25_stop_timer(sk);
                                x25_enquiry_response(sk);
                        } else {
                                sk->protinfo.x25->condition |= X25_COND_ACK_PENDING;
-                               sk->protinfo.x25->timer      = sk->protinfo.x25->t2;
+                               x25_start_t2timer(sk);
                        }
                        break;
 
@@ -307,7 +291,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                case X25_RESET_REQUEST:
                        x25_write_internal(sk, X25_RESET_CONFIRMATION);
                case X25_RESET_CONFIRMATION:
-                       sk->protinfo.x25->timer     = 0;
+                       x25_stop_timer(sk);
                        sk->protinfo.x25->condition = 0x00;
                        sk->protinfo.x25->va        = 0;
                        sk->protinfo.x25->vr        = 0;
@@ -317,16 +301,8 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                        break;
 
                case X25_CLEAR_REQUEST:
-                       x25_clear_queues(sk);
                        x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
-                       sk->protinfo.x25->timer = 0;
-                       sk->protinfo.x25->state = X25_STATE_0;
-                       sk->state               = TCP_CLOSE;
-                       sk->err                 = 0;
-                       sk->shutdown           |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                = 1;
+                       x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
                        break;
 
                default:
@@ -344,8 +320,6 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
        if (sk->protinfo.x25->state == X25_STATE_0)
                return 0;
 
-       del_timer(&sk->timer);
-
        frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m);
 
        switch (sk->protinfo.x25->state) {
@@ -363,7 +337,7 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
                        break;
        }
 
-       x25_set_timer(sk);
+       x25_kick(sk);
 
        return queued;
 }
index f44c0a2c5b14f7c89f4db0333f917a0b503d76ce..1742d802f55734859cc3171b35fe7a69aa99eadb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     X.25 Packet Layer release 001
+ *     X.25 Packet Layer release 002
  *
  *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *     releases, misbehave and/or generally screw up. It might even work. 
@@ -14,6 +14,7 @@
  *
  *     History
  *     X.25 001        Jonathan Naylor Started coding.
+ *     X.25 002        Jonathan Naylor New timer architecture.
  */
 
 #include <linux/config.h>
 
 static struct x25_neigh *x25_neigh_list = NULL;
 
-static void x25_link_timer(unsigned long);
+static void x25_t20timer_expiry(unsigned long);
 
 /*
  *     Linux set/reset timer routines
  */
-static void x25_link_set_timer(struct x25_neigh *neigh)
+static void x25_start_t20timer(struct x25_neigh *neigh)
 {
-       unsigned long flags;
-
-       save_flags(flags); cli();
-       del_timer(&neigh->timer);
-       restore_flags(flags);
+       del_timer(&neigh->t20timer);
 
-       neigh->timer.data     = (unsigned long)neigh;
-       neigh->timer.function = &x25_link_timer;
-       neigh->timer.expires  = jiffies + (HZ / 1);
+       neigh->t20timer.data     = (unsigned long)neigh;
+       neigh->t20timer.function = &x25_t20timer_expiry;
+       neigh->t20timer.expires  = jiffies + neigh->t20;
 
-       add_timer(&neigh->timer);
+       add_timer(&neigh->t20timer);
 }
 
-/*
- *     X.25 Link TIMER 
- *
- *     This routine is called every second. Decrement timer by this
- *     amount - if expired then process the event.
- */
-static void x25_link_timer(unsigned long param)
+static void x25_t20timer_expiry(unsigned long param)
 {
        struct x25_neigh *neigh = (struct x25_neigh *)param;
 
-       if (neigh->t20timer == 0 || --neigh->t20timer > 0) {
-               x25_link_set_timer(neigh);
-               return;
-       }
-
-       /*
-        * T20 for a link has expired.
-        */
        x25_transmit_restart_request(neigh);
 
-       neigh->t20timer = neigh->t20;
+       x25_start_t20timer(neigh);
+}
 
-       x25_link_set_timer(neigh);
+static void x25_stop_t20timer(struct x25_neigh *neigh)
+{
+       del_timer(&neigh->t20timer);
 }
 
 /*
@@ -97,16 +83,14 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *neigh, unsigned sho
 
        switch (frametype) {
                case X25_RESTART_REQUEST:
-                       neigh->t20timer = 0;
-                       neigh->state    = X25_LINK_STATE_3;
-                       del_timer(&neigh->timer);
+                       x25_stop_t20timer(neigh);
+                       neigh->state = X25_LINK_STATE_3;
                        x25_transmit_restart_confirmation(neigh);
                        break;
 
                case X25_RESTART_CONFIRMATION:
-                       neigh->t20timer = 0;
-                       neigh->state    = X25_LINK_STATE_3;
-                       del_timer(&neigh->timer);
+                       x25_stop_t20timer(neigh);
+                       neigh->state = X25_LINK_STATE_3;
                        break;
 
                case X25_DIAGNOSTIC:
@@ -272,9 +256,8 @@ void x25_link_established(struct x25_neigh *neigh)
                        break;
                case X25_LINK_STATE_1:
                        x25_transmit_restart_request(neigh);
-                       neigh->state    = X25_LINK_STATE_2;
-                       neigh->t20timer = neigh->t20;
-                       x25_link_set_timer(neigh);
+                       neigh->state = X25_LINK_STATE_2;
+                       x25_start_t20timer(neigh);
                        break;
        }
 }
@@ -300,12 +283,12 @@ void x25_link_device_up(struct device *dev)
                return;
 
        skb_queue_head_init(&x25_neigh->queue);
-       init_timer(&x25_neigh->timer);
+
+       init_timer(&x25_neigh->t20timer);
 
        x25_neigh->dev      = dev;
        x25_neigh->state    = X25_LINK_STATE_0;
        x25_neigh->extended = 0;
-       x25_neigh->t20timer = 0;
        x25_neigh->t20      = sysctl_x25_restart_request_timeout;
 
        save_flags(flags); cli();
@@ -323,10 +306,9 @@ static void x25_remove_neigh(struct x25_neigh *x25_neigh)
        while ((skb = skb_dequeue(&x25_neigh->queue)) != NULL)
                kfree_skb(skb, FREE_WRITE);
 
-       del_timer(&x25_neigh->timer);
+       x25_stop_t20timer(x25_neigh);
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
 
        if ((s = x25_neigh_list) == x25_neigh) {
                x25_neigh_list = x25_neigh->next;
@@ -387,25 +369,22 @@ int x25_subscr_ioctl(unsigned int cmd, void *arg)
        struct x25_subscrip_struct x25_subscr;
        struct x25_neigh *x25_neigh;
        struct device *dev;
-       int err;
 
        switch (cmd) {
 
                case SIOCX25GSUBSCRIP:
-                       if ((err = verify_area(VERIFY_WRITE, arg, sizeof(struct x25_subscrip_struct))) != 0)
-                               return err;
                        if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
                                return -EINVAL;
                        if ((x25_neigh = x25_get_neigh(dev)) == NULL)
                                return -EINVAL;
                        x25_subscr.extended = x25_neigh->extended;
-                       copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct));
+                       if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct)))
+                               return -EFAULT;
                        break;
 
                case SIOCX25SSUBSCRIP:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_subscrip_struct))) != 0)
-                               return err;
-                       copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct));
+                       if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
+                               return -EFAULT;
                        if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
                                return -EINVAL;
                        if ((x25_neigh = x25_get_neigh(dev)) == NULL)
index 321baa5d6cf694b812ff351ef42d46de7ea67e90..aa8fc2c1bf4c68c931d1bf2c243b1b3818c76581 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     X.25 Packet Layer release 001
+ *     X.25 Packet Layer release 002
  *
  *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *     releases, misbehave and/or generally screw up. It might even work. 
@@ -14,6 +14,7 @@
  *
  *     History
  *     X.25 001        Jonathan Naylor Started coding.
+ *     X.25 002        Jonathan Naylor New timer architecture.
  */
 
 #include <linux/config.h>
@@ -129,7 +130,8 @@ void x25_kick(struct sock *sk)
        unsigned short end;
        int modulus;
 
-       del_timer(&sk->timer);
+       if (sk->protinfo.x25->state != X25_STATE_3)
+               return;
 
        /*
         *      Transmit interrupt data.
@@ -140,38 +142,39 @@ void x25_kick(struct sock *sk)
                x25_transmit_link(skb, sk->protinfo.x25->neighbour);
        }
 
+       if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY)
+               return;
+
+       if (skb_peek(&sk->write_queue) == NULL)
+               return;
+
        modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
        end     = (sk->protinfo.x25->va + sk->protinfo.x25->facilities.winsize_out) % modulus;
 
+       if (sk->protinfo.x25->vs == end)
+               return;
+
        /*
-        *      Transmit normal stream data.
+        * Transmit data until either we're out of data to send or
+        * the window is full.
         */
-       if (!(sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) &&
-           sk->protinfo.x25->vs != end                            &&
-           skb_peek(&sk->write_queue) != NULL) {
-               /*
-                * Transmit data until either we're out of data to send or
-                * the window is full.
-                */
 
-               skb = skb_dequeue(&sk->write_queue);
+       skb = skb_dequeue(&sk->write_queue);
 
-               do {
-                       /*
-                        * Transmit the frame.
-                        */
-                       x25_send_iframe(sk, skb);
+       do {
+               /*
+                * Transmit the frame.
+                */
+               x25_send_iframe(sk, skb);
 
-                       sk->protinfo.x25->vs = (sk->protinfo.x25->vs + 1) % modulus;
+               sk->protinfo.x25->vs = (sk->protinfo.x25->vs + 1) % modulus;
 
-               } while (sk->protinfo.x25->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+       } while (sk->protinfo.x25->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
 
-               sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
-               sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
-               sk->protinfo.x25->timer      = 0;
-       }
+       sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
+       sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
 
-       x25_set_timer(sk);
+       x25_stop_timer(sk);
 }
 
 /*
@@ -188,7 +191,8 @@ void x25_enquiry_response(struct sock *sk)
 
        sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
        sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
-       sk->protinfo.x25->timer      = 0;
+
+       x25_stop_timer(sk);
 }
 
 void x25_check_iframes_acked(struct sock *sk, unsigned short nr)
index 820c11cd4014628b794a820253d42f9786b4e1cf..9c3204537f7051c84bd1fd79f1f4ec6e09610095 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     X.25 Packet Layer release 001
+ *     X.25 Packet Layer release 002
  *
  *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *     releases, misbehave and/or generally screw up. It might even work. 
@@ -183,14 +183,12 @@ int x25_route_ioctl(unsigned int cmd, void *arg)
 {
        struct x25_route_struct x25_route;
        struct device *dev;
-       int err;
 
        switch (cmd) {
 
                case SIOCADDRT:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_route_struct))) != 0)
-                               return err;
-                       copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct));
+                       if (copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct)))
+                               return -EFAULT;
                        if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15)
                                return -EINVAL;
                        if ((dev = x25_dev_get(x25_route.device)) == NULL)
@@ -198,9 +196,8 @@ int x25_route_ioctl(unsigned int cmd, void *arg)
                        return x25_add_route(&x25_route.address, x25_route.sigdigits, dev);
 
                case SIOCDELRT:
-                       if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_route_struct))) != 0)
-                               return err;
-                       copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct));
+                       if (copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct)))
+                               return -EFAULT;
                        if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15)
                                return -EINVAL;
                        if ((dev = x25_dev_get(x25_route.device)) == NULL)
@@ -227,7 +224,8 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length, in
 
        for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) {
                len += sprintf(buffer + len, "%-15s  %-6d  %-5s\n",
-                       x25_route->address.x25_addr, x25_route->sigdigits,
+                       x25_route->address.x25_addr,
+                       x25_route->sigdigits,
                        (x25_route->dev != NULL) ? x25_route->dev->name : "???");
 
                pos = begin + len;
index 75e58af98cc2be69db698759a895dfa4c74f8d58..f2aff6d12b2508214bc77fff06b8eca96ceabd07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     X.25 Packet Layer release 001
+ *     X.25 Packet Layer release 002
  *
  *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *     releases, misbehave and/or generally screw up. It might even work. 
@@ -14,6 +14,7 @@
  *
  *     History
  *     X.25 001        Jonathan Naylor Started coding.
+ *     X.25 002        Jonathan Naylor Centralised disconnection processing.
  */
 
 #include <linux/config.h>
@@ -281,4 +282,25 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, i
        return X25_ILLEGAL;
 }
 
+void x25_disconnect(struct sock *sk, int reason, unsigned char cause, unsigned char diagnostic)
+{
+       x25_clear_queues(sk);
+       x25_stop_timer(sk);
+
+       sk->protinfo.x25->lci   = 0;
+       sk->protinfo.x25->state = X25_STATE_0;
+
+       sk->protinfo.x25->causediag.cause      = cause;
+       sk->protinfo.x25->causediag.diagnostic = diagnostic;
+
+       sk->state     = TCP_CLOSE;
+       sk->err       = reason;
+       sk->shutdown |= SEND_SHUTDOWN;
+
+       if (!sk->dead)
+               sk->state_change(sk);
+
+       sk->dead = 1;
+}
+
 #endif
index e625c41edb58818159dd8106a1badfb861fbfa77..90b6513c93c2e528eb96beab6ecb83d7defa655a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     X.25 Packet Layer release 001
+ *     X.25 Packet Layer release 002
  *
  *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *     releases, misbehave and/or generally screw up. It might even work. 
@@ -14,6 +14,8 @@
  *
  *     History
  *     X.25 001        Jonathan Naylor Started coding.
+ *     X.25 002        Jonathan Naylor New timer architecture.
+ *                                     Centralised disconnection processing.
  */
 
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <net/x25.h>
 
-static void x25_timer(unsigned long);
+static void x25_heartbeat_expiry(unsigned long);
+static void x25_timer_expiry(unsigned long);
 
-/*
- *     Linux set timer
- */
-void x25_set_timer(struct sock *sk)
+void x25_start_heartbeat(struct sock *sk)
 {
-       unsigned long flags;
-
-       save_flags(flags); cli();
        del_timer(&sk->timer);
-       restore_flags(flags);
 
        sk->timer.data     = (unsigned long)sk;
-       sk->timer.function = &x25_timer;
-       sk->timer.expires  = jiffies + (HZ / 1);
+       sk->timer.function = &x25_heartbeat_expiry;
+       sk->timer.expires  = jiffies + 5 * HZ;
 
        add_timer(&sk->timer);
 }
 
-/*
- *     X.25 TIMER 
- *
- *     This routine is called every second. Decrement timer by this
- *     amount - if expired then process the event.
- */
-static void x25_timer(unsigned long param)
+void x25_stop_heartbeat(struct sock *sk)
+{
+       del_timer(&sk->timer);
+}
+
+void x25_start_t2timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.x25->timer);
+
+       sk->protinfo.x25->timer.data     = (unsigned long)sk;
+       sk->protinfo.x25->timer.function = &x25_timer_expiry;
+       sk->protinfo.x25->timer.expires  = jiffies + sk->protinfo.x25->t2;
+
+       add_timer(&sk->protinfo.x25->timer);
+}
+
+void x25_start_t21timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.x25->timer);
+
+       sk->protinfo.x25->timer.data     = (unsigned long)sk;
+       sk->protinfo.x25->timer.function = &x25_timer_expiry;
+       sk->protinfo.x25->timer.expires  = jiffies + sk->protinfo.x25->t21;
+
+       add_timer(&sk->protinfo.x25->timer);
+}
+
+void x25_start_t22timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.x25->timer);
+
+       sk->protinfo.x25->timer.data     = (unsigned long)sk;
+       sk->protinfo.x25->timer.function = &x25_timer_expiry;
+       sk->protinfo.x25->timer.expires  = jiffies + sk->protinfo.x25->t22;
+
+       add_timer(&sk->protinfo.x25->timer);
+}
+
+void x25_start_t23timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.x25->timer);
+
+       sk->protinfo.x25->timer.data     = (unsigned long)sk;
+       sk->protinfo.x25->timer.function = &x25_timer_expiry;
+       sk->protinfo.x25->timer.expires  = jiffies + sk->protinfo.x25->t23;
+
+       add_timer(&sk->protinfo.x25->timer);
+}
+
+void x25_stop_timer(struct sock *sk)
+{
+       del_timer(&sk->protinfo.x25->timer);
+}
+
+unsigned long x25_display_timer(struct sock *sk)
+{
+       if (sk->protinfo.x25->timer.prev == NULL &&
+           sk->protinfo.x25->timer.next == NULL)
+               return 0;
+
+       return sk->protinfo.x25->timer.expires - jiffies;
+}
+
+static void x25_heartbeat_expiry(unsigned long param)
 {
        struct sock *sk = (struct sock *)param;
 
        switch (sk->protinfo.x25->state) {
+
                case X25_STATE_0:
                        /* Magic here: If we listen() and a new link dies before it
                           is accepted() it isn't 'dead' so doesn't get removed. */
                        if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
-                               del_timer(&sk->timer);
                                x25_destroy_socket(sk);
                                return;
                        }
@@ -89,30 +142,26 @@ static void x25_timer(unsigned long param)
                                sk->protinfo.x25->condition &= ~X25_COND_OWN_RX_BUSY;
                                sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
                                sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
-                               sk->protinfo.x25->timer      = 0;
                                x25_write_internal(sk, X25_RR);
+                               x25_stop_timer(sk);
                                break;
                        }
-                       /*
-                        * Check for frames to transmit.
-                        */
-                       x25_kick(sk);
-                       break;
-
-               default:
                        break;
        }
 
-       if (sk->protinfo.x25->timer == 0 || --sk->protinfo.x25->timer > 0) {
-               x25_set_timer(sk);
-               return;
-       }
+       x25_start_heartbeat(sk);
+}
+
+/*
+ *     Timer has expired, it may have been T2, T21, T22, or T23. We can tell
+ *     by the state machine state.
+ */
+static void x25_timer_expiry(unsigned long param)
+{
+       struct sock *sk = (struct sock *)param;
 
-       /*
-        * Timer has expired, it may have been T2, T21, T22, or T23. We can tell
-        * by the state machine state.
-        */
        switch (sk->protinfo.x25->state) {
+
                case X25_STATE_3:       /* T2 */
                        if (sk->protinfo.x25->condition & X25_COND_ACK_PENDING) {
                                sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
@@ -124,22 +173,13 @@ static void x25_timer(unsigned long param)
                case X25_STATE_4:       /* T22 */
                        x25_write_internal(sk, X25_CLEAR_REQUEST);
                        sk->protinfo.x25->state = X25_STATE_2;
-                       sk->protinfo.x25->timer = sk->protinfo.x25->t23;
+                       x25_start_t23timer(sk);
                        break;
 
                case X25_STATE_2:       /* T23 */
-                       x25_clear_queues(sk);
-                       sk->protinfo.x25->state = X25_STATE_0;
-                       sk->state               = TCP_CLOSE;
-                       sk->err                 = ETIMEDOUT;
-                       sk->shutdown           |= SEND_SHUTDOWN;
-                       if (!sk->dead)
-                               sk->state_change(sk);
-                       sk->dead                = 1;
+                       x25_disconnect(sk, ETIMEDOUT, 0, 0);
                        break;
        }
-
-       x25_set_timer(sk);
 }
 
 #endif