]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.71 1.3.71
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:38 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:38 +0000 (15:10 -0500)
223 files changed:
CREDITS
Documentation/Configure.help
Documentation/devices.tex
Documentation/devices.txt
Documentation/unicode.txt
MAGIC
Makefile
arch/alpha/kernel/entry.S
arch/alpha/kernel/irq.c
arch/alpha/kernel/ksyms.c
arch/alpha/math-emu/fp-emul.c
arch/i386/kernel/smp.c
arch/sparc/boot/bare.S
arch/sparc/config.in
arch/sparc/defconfig
arch/sparc/kernel/Makefile
arch/sparc/kernel/auxio.c [new file with mode: 0644]
arch/sparc/kernel/cpu.c [new file with mode: 0644]
arch/sparc/kernel/devices.c [new file with mode: 0644]
arch/sparc/kernel/entry.S
arch/sparc/kernel/etrap.S
arch/sparc/kernel/head.S
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq.c
arch/sparc/kernel/ksyms.c [new file with mode: 0644]
arch/sparc/kernel/probe.c
arch/sparc/kernel/process.c
arch/sparc/kernel/rtrap.S
arch/sparc/kernel/sclow.S [new file with mode: 0644]
arch/sparc/kernel/setup.c
arch/sparc/kernel/signal.c
arch/sparc/kernel/smp.c [new file with mode: 0644]
arch/sparc/kernel/sparc-stub.c
arch/sparc/kernel/sunos_asm.S
arch/sparc/kernel/sunos_ioctl.c
arch/sparc/kernel/switch.S
arch/sparc/kernel/sys_bsd.c [new file with mode: 0644]
arch/sparc/kernel/sys_sparc.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/kernel/systbls.S
arch/sparc/kernel/time.c
arch/sparc/kernel/traps.c
arch/sparc/kernel/windows.c [new file with mode: 0644]
arch/sparc/kernel/wof.S
arch/sparc/kernel/wuf.S
arch/sparc/lib/Makefile
arch/sparc/lib/memcpy.S [new file with mode: 0644]
arch/sparc/mm/Makefile
arch/sparc/mm/fault.c
arch/sparc/mm/init.c
arch/sparc/mm/loadmmu.c
arch/sparc/mm/s4cflsh.S [new file with mode: 0644]
arch/sparc/mm/s4cflush.S [deleted file]
arch/sparc/mm/s4ckflt.S [new file with mode: 0644]
arch/sparc/mm/s4clow.h [new file with mode: 0644]
arch/sparc/mm/s4cuflt.S [new file with mode: 0644]
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/mm/sun4c_vac.c [deleted file]
arch/sparc/prom/bootstr.c
arch/sparc/prom/console.c
arch/sparc/prom/devtree.c [new file with mode: 0644]
arch/sparc/prom/misc.c
arch/sparc/prom/tree.c
drivers/block/floppy.c
drivers/block/ll_rw_blk.c
drivers/block/loop.c
drivers/block/loop.h [deleted file]
drivers/block/md.c
drivers/cdrom/cm206.c
drivers/cdrom/mcd.c
drivers/cdrom/mcdx.c
drivers/char/apm_bios.c
drivers/char/console.c
drivers/char/cyclades.c
drivers/char/keyboard.c
drivers/char/selection.h
drivers/char/serial.c
drivers/isdn/teles/card.c
drivers/net/3c503.c
drivers/net/Config.in
drivers/net/arcnet.c
drivers/net/eexpress.c
drivers/net/eth82586.h [new file with mode: 0644]
drivers/net/lance.c
drivers/net/ppp.c
drivers/net/slip.c
drivers/net/sunlance.c
drivers/net/tunnel.c [deleted file]
drivers/net/wavelan.c
drivers/scsi/ultrastor.c
drivers/sound/.version
drivers/sound/CHANGELOG
drivers/sound/Config.std [new file with mode: 0644]
drivers/sound/Makefile
drivers/sound/Readme
drivers/sound/Readme.cards
drivers/sound/Readme.linux
drivers/sound/ad1848.c
drivers/sound/audio.c
drivers/sound/configure.c
drivers/sound/cs4232.c
drivers/sound/dev_table.h
drivers/sound/dmabuf.c
drivers/sound/gus_wave.c
drivers/sound/hex2hex.h
drivers/sound/opl3.c
drivers/sound/os.h
drivers/sound/pas2_pcm.c
drivers/sound/sb16_dsp.c
drivers/sound/sb16_midi.c
drivers/sound/sb_card.c
drivers/sound/sb_dsp.c
drivers/sound/sound_calls.h
drivers/sound/sound_switch.c
drivers/sound/soundvers.h
drivers/sound/sscape.c
fs/Makefile
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/binfmt_script.c [new file with mode: 0644]
fs/block_dev.c
fs/buffer.c
fs/exec.c
fs/ncpfs/dir.c
fs/ncpfs/file.c
fs/ncpfs/inode.c
fs/ncpfs/ioctl.c
fs/ncpfs/mmap.c
fs/ncpfs/ncplib_kernel.c
fs/ncpfs/ncplib_kernel.h
fs/ncpfs/sock.c
fs/super.c
include/asm-alpha/system.h
include/asm-alpha/unistd.h
include/asm-i386/smp.h
include/asm-i386/system.h
include/asm-sparc/asi.h
include/asm-sparc/auxio.h
include/asm-sparc/bitops.h
include/asm-sparc/cypress.h
include/asm-sparc/delay.h
include/asm-sparc/dma.h
include/asm-sparc/fbio.h [new file with mode: 0644]
include/asm-sparc/fcntl.h
include/asm-sparc/floppy.h
include/asm-sparc/head.h
include/asm-sparc/iommu.h [new file with mode: 0644]
include/asm-sparc/irq.h
include/asm-sparc/kbio.h [new file with mode: 0644]
include/asm-sparc/kdebug.h
include/asm-sparc/kgdb.h
include/asm-sparc/memreg.h
include/asm-sparc/mman.h
include/asm-sparc/mmu_context.h [new file with mode: 0644]
include/asm-sparc/oplib.h
include/asm-sparc/page.h
include/asm-sparc/pgtable.h
include/asm-sparc/pgtsrmmu.h
include/asm-sparc/pgtsun4c.h
include/asm-sparc/processor.h
include/asm-sparc/psr.h
include/asm-sparc/ptrace.h
include/asm-sparc/ross.h
include/asm-sparc/sbus.h
include/asm-sparc/segment.h
include/asm-sparc/sigcontext.h
include/asm-sparc/signal.h
include/asm-sparc/smp.h [new file with mode: 0644]
include/asm-sparc/smp_lock.h [new file with mode: 0644]
include/asm-sparc/string.h
include/asm-sparc/swift.h [new file with mode: 0644]
include/asm-sparc/system.h
include/asm-sparc/termios.h
include/asm-sparc/timer.h
include/asm-sparc/tsunami.h
include/asm-sparc/unistd.h
include/asm-sparc/user.h
include/asm-sparc/vac-ops.h
include/asm-sparc/vaddrs.h
include/asm-sparc/viking.h
include/asm-sparc/vuid_event.h [new file with mode: 0644]
include/asm-sparc/winmacro.h
include/linux/binfmts.h
include/linux/interrupt.h
include/linux/loop.h [new file with mode: 0644]
include/linux/major.h
include/linux/mcdx.h
include/linux/md.h
include/linux/ncp.h
include/linux/ncp_fs.h
include/linux/ncp_fs_i.h
include/linux/ncp_fs_sb.h
include/linux/ncp_mount.h
include/linux/netdevice.h
include/linux/skbuff.h
include/linux/socket.h
include/linux/tqueue.h
include/linux/un.h
include/net/af_unix.h
include/net/ax25.h
include/net/netlink.h
kernel/ksyms.c
kernel/printk.c
kernel/sched.c
kernel/softirq.c
mm/kmalloc.c
net/ax25/ax25_subr.c
net/core/dev.c
net/core/sock.c
net/ipv4/arp.c
net/ipv4/tcp_input.c
net/ipx/af_ipx.c
net/protocols.c
net/unix/Makefile
net/unix/af_unix.c
net/unix/garbage.c [new file with mode: 0644]
scripts/Menuconfig
scripts/README.Menuconfig
scripts/lxdialog/Makefile
scripts/lxdialog/checklist.c
scripts/lxdialog/menubox.c
scripts/lxdialog/yesno.c

diff --git a/CREDITS b/CREDITS
index 637c6fe41fd4c0c9c99c9f04c9ec326b5a49cb8a..b8006633e3f02f8a3065baf02268af250afe8799 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -344,6 +344,13 @@ S: 1123 North Oak Park Avenue
 S: Oak Park, Illinois 60302
 S: USA
 
+N: Bob Frey
+E: bobf@advansys.com
+D: AdvanSys SCSI driver
+S: 1150 Ringwood Court
+S: San Jose, California 95131
+S: USA
+
 N: Nigel Gamble
 E: nigel@nrg.org
 E: nigel@sgi.com
@@ -609,6 +616,10 @@ S: Am Muehlenweg 38
 S: D53424 Remagen
 S: Germany
 
+N: Martin von Loewis
+E: loewis@informatik.hu-berlin.de
+D: script binary format
+
 N: Mark Lord
 E: mlord@pobox.com
 D: Author of IDE driver (ide.c), hd.c support
index 978023bb820de7804f0d24aa3033e13b6c97fe19..29bbb3367036429ca534ae4bd76df1033c155f0f 100644 (file)
@@ -1654,22 +1654,45 @@ CONFIG_NET_ISA
   linux, read the Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
-Arcnet support
+ARCnet support
 CONFIG_ARCNET
   If you have a network card of this type, say Y and check out the
-  beautiful poetry in Documentation/networking/arcnet.txt in the
-  kernel source. If you get this driver to work or not, either way,
-  send mail to the author. You might also want to have a look at the
-  Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO (even though arcnet is no true
-  ethernet). This driver is also available as a module ( = code which
-  can be inserted in and removed from the running kernel whenever you
-  want). If you want to compile it as a module, say M here and read
-  Documentation/modules.txt as well as
+  (arguably) beautiful poetry in Documentation/networking/arcnet.txt. 
+  You might also want to have a look at the Ethernet-HOWTO, available
+  via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO
+  (even though ARCnet is not really ethernet). This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). If you want to compile it
+  as a module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  
+Enable arc0e (ARCnet "ether-encap" packet format)
+CONFIG_ARCNET_ETH
+  This allows you to use "ethernet encapsulation" with your ARCnet card
+  via the virtual arc0e device.  You only need arc0e if you want to
+  talk to nonstandard ARCnet software, specifically, DOS/Windows-style
+  "NDIS" drivers.  You do not need to enable this option to communicate
+  with industry-standard RFC1201 implementations, like the arcether.com
+  packet driver or most DOS/Windows ODI drivers.  RFC1201 is included
+  automatically as the arc0 device.  Please read the ARCnet
+  documentation in Documentation/networking/arcnet.txt for more
+  information about using arc0e and arc0s.
+
+Enable arc0s (ARCnet RFC1051 packet format)
+CONFIG_ARCNET_1051
+  This allows you to use RFC1051 with your ARCnet card via the virtual
+  arc0s device.  You only need arc0s if you want to talk to ARCnet
+  software complying with the "old" standard, specifically, the DOS
+  arcnet.com packet driver, Amigas running AmiTCP, and some variants of
+  NetBSD.  You do not need to enable this option to communicate with
+  industry-standard RFC1201 implementations, like the arcether.com
+  packet driver or most DOS/Windows ODI drivers.  RFC1201 is included
+  automatically as the arc0 device.  Please read the ARCnet
+  documentation in Documentation/networking/arcnet.txt for more
+  information about using arc0e and arc0s.
 
 Cabletron E21xx support
 CONFIG_E2100
index 13062aa4f4af1c2e247ef80bef33b475606a0bcd..add0332d4b34184be4eb7a85d730b6160a97a0cd 100644 (file)
@@ -41,8 +41,8 @@ foo \kill}%
  {\end{tabbing}}
 %
 \title{{\bf Linux Allocated Devices}}
-\author{Maintained by H. Peter Anvin $<$hpa@storm.net$>$}
-\date{Last revised: February 24, 1996}
+\author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
+\date{Last revised: March 2, 1996}
 \maketitle
 %
 \noindent
@@ -88,12 +88,13 @@ an unreasonable effort.
 \major{ 5}{}{char }{Alternate TTY devices}
 \major{ 6}{}{char }{Parallel printer devices}
 \major{ 7}{}{char }{Virtual console access devices}
-\major{  }{}{block}{Loopback devices}
 \major{ 8}{}{block}{SCSI disk devices}
 \major{ 9}{}{char }{SCSI tape devices}
 \major{  }{}{block}{Metadisk (RAID) devices}
 \major{10}{}{char }{Non-serial mice, misc features}
-\major{11}{}{block}{SCSI CD-ROM devices}
+\major{  }{}{block}{Loopback devices}
+\major{11}{}{char }{Raw keyboard device}
+\major{  }{}{block}{SCSI CD-ROM devices}
 \major{12}{}{char }{QIC-02 tape}
 \major{  }{}{block}{MSCDEX CD-ROM callback support}
 \major{13}{}{char }{PC speaker}
@@ -352,17 +353,6 @@ Not all computers have the {\hex 0x3bc} parallel port, hence the
 \noindent
 NOTE: These devices permit both read and write access.
 
-\major{  }{}{block}{Loopback devices}
-       \minor{0}{/dev/loop0}{First loopback device}
-       \minor{1}{/dev/loop1}{Second loopback device}
-       \minordots
-\end{devicelist}
-
-\noindent
-The loopback devices are used to mount filesystems not associated with
-block devices.  The binding to the loopback devices is usually handled
-by mount(1).
-
 \begin{devicelist}
 \major{ 8}{}{block}{SCSI disk devices}
        \minor{0}{/dev/sda}{First SCSI disk whole disk}
@@ -403,18 +393,37 @@ physical disks.
        \minor{2}{/dev/inportbm}{Microsoft Inport bus mouse}
        \minor{3}{/dev/atibm}{ATI XL bus mouse}
        \minor{4}{/dev/jbm}{J-mouse}
-       \minor{4}{/dev/amigamouse}{Amiga Mouse (68k/Amiga)}
-       \minor{5}{/dev/atarimouse}{Atari Mouse}
+       \minor{4}{/dev/amigamouse}{Amiga mouse (68k/Amiga)}
+       \minor{5}{/dev/atarimouse}{Atari mouse}
+       \minor{6}{/dev/sunmouse}{Sun mouse}
        \minor{128}{/dev/beep}{Fancy beep device}
        \minor{129}{/dev/modreq}{Kernel module load request}
        \minor{130}{/dev/watchdog}{Watchdog timer port}
        \minor{131}{/dev/temperature}{Machine internal temperature}
        \minor{132}{/dev/hwtrap}{Hardware fault trap}
        \minor{133}{/dev/exttrp}{External device trap}
+\\
+\major{  }{}{block}{Loopback devices}
+       \minor{0}{/dev/loop0}{First loopback device}
+       \minor{1}{/dev/loop1}{Second loopback device}
+       \minordots
+\end{devicelist}
+
+\noindent
+The loopback devices are used to mount filesystems not associated with
+block devices.  The binding to the loopback devices is usually handled
+by mount(1).
+
+\begin{devicelist}
+\major{11}{}{char }{Raw keyboard device}
+       \minor{0}{/dev/kbd}{Raw keyboard device}
 \end{devicelist}
 
+\noindent
+The raw keyboard device is used on Linux/SPARC only.
+
 \begin{devicelist}
-\major{11}{}{block}{SCSI CD-ROM devices}
+\major{  }{}{block}{SCSI CD-ROM devices}
        \minor{0}{/dev/sr0}{First SCSI CD-ROM}
        \minor{1}{/dev/sr1}{Second SCSI CD-ROM}
        \minordots
@@ -693,12 +702,12 @@ disk (same as SCSI.)
 
 \begin{devicelist}
 \major{29}{}{char }{Universal frame buffer}
-       \minor{0}{/dev/fb0current}{First frame buffer}
+       \minor{0}{/dev/fb0}{First frame buffer}
        \minor{1}{/dev/fb0autodetect}{}
        \minor{24}{/dev/fb0user0}{}
        \minordots
        \minor{31}{/dev/fb0user7}{}
-       \minor{32}{/dev/fb1current}{Second frame buffer}
+       \minor{32}{/dev/fb1}{Second frame buffer}
        \minor{33}{/dev/fb1autodetect}{}
        \minor{56}{/dev/fb1user0}{}
        \minordots
@@ -708,13 +717,15 @@ disk (same as SCSI.)
 
 \noindent
 The universal frame buffer device is currently supported only on
-Linux/68k.  The {\file current} device accesses the frame buffer at
-current resolution; the {\file autodetect} one at bootup (default)
-resolution.  Minor numbers 2--23 within each frame buffer assignment
-are used for specific device-dependent resolutions.  There appears to
-be no standard naming for these devices.  Finally, 24--31 within each
-device are reserved for user-selected modes, usually entered at boot
-time.
+Linux/68k and Linux/SPARC.  The plain device accesses the frame
+buffer at current resolution (Linux/68k calls this file {\file
+current}, e.g. {\file /dev/fb0current}); the {\file autodetect} one at
+bootup (default) resolution.  Minor numbers 2--23 within each frame
+buffer assignment are used for specific device-dependent resolutions.
+There appears to be no standard naming for these devices.  Finally,
+24--31 within each device are reserved for user-selected modes,
+usually entered at boot time.  Currently only Linux/68k uses the
+mode-specific devices.
 
 \begin{devicelist}
 \major{  }{}{block}{Aztech/Orchid/Okano/Wearnes CD-ROM}
@@ -1057,7 +1068,7 @@ point to the ``cooked'' devices ({\file /dev/st*} and {\file
 /dev/scanner} should point to the appropriate generic SCSI devices
 ({\file /dev/sg*}.)
 
-{\file /dev/mouse} may point to a dialout (alternate) TTY device, a
+{\file /dev/mouse} may point to a primary serial TTY device, a
 hardware mouse device, or a socket for a mouse driver program
 (e.g. {\file /dev/gpmdata}.)
 
index 0932f2fe82c0aa2c6790f849c0d9e6324e6a319a..48b40b9e3aaeac7f3c56e7a865c45f624025b6f6 100644 (file)
@@ -1,8 +1,8 @@
                       LINUX ALLOCATED DEVICES
 
-            Maintained by H. Peter Anvin <hpa@storm.net>
+            Maintained by H. Peter Anvin <hpa@zytor.com>
 
-                  Last revised: February 24, 1996
+                    Last revised: March 2, 1996
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -131,7 +131,7 @@ an unreasonable effort.
                  1 = /dev/hd?1         First partition
                  2 = /dev/hd?2         Second partition
                    ...
-                63 = /dev/hd?63        63rd logical partition
+                63 = /dev/hd?63        63rd partition
 
                For Linux/i386, partitions 1-4 are the primary
                partitions, and 5 and above are logical partitions.
@@ -187,15 +187,6 @@ an unreasonable effort.
        
                NOTE: These devices permit both read and write access.
 
-    block      Loopback devices
-                 0 = /dev/loop0        First loopback device
-                 1 = /dev/loop1        Second loopback device
-                     ...
-
-               The loopback devices are used to mount filesystems not
-               associated with block devices.  The binding to the
-               loopback devices is usually handled by mount(1).
-
   8 block      SCSI disk devices
                  0 = /dev/sda          First SCSI disk whole disk
                 16 = /dev/sdb          Second SCSI disk whole disk
@@ -228,8 +219,9 @@ an unreasonable effort.
                  2 = /dev/inportbm     Microsoft Inport bus mouse
                  3 = /dev/atibm        ATI XL bus mouse
                  4 = /dev/jbm          J-mouse
-                 4 = /dev/amigamouse   Amiga Mouse (68k/Amiga)
-                 5 = /dev/atarimouse   Atari Mouse
+                 4 = /dev/amigamouse   Amiga mouse (68k/Amiga)
+                 5 = /dev/atarimouse   Atari mouse
+                 6 = /dev/sunmouse     Sun mouse
                128 = /dev/beep         Fancy beep device
                129 = /dev/modreq       Kernel module load request
                130 = /dev/watchdog     Watchdog timer port
@@ -237,7 +229,21 @@ an unreasonable effort.
                132 = /dev/hwtrap       Hardware fault trap
                133 = /dev/exttrp       External device trap
 
- 11 block      SCSI CD-ROM devices
+    block      Loopback devices
+                 0 = /dev/loop0        First loopback device
+                 1 = /dev/loop1        Second loopback device
+                     ...
+
+               The loopback devices are used to mount filesystems not
+               associated with block devices.  The binding to the
+               loopback devices is usually handled by mount(1).
+
+ 11 char       Raw keyboard device
+                 0 = /dev/kbd          Raw keyboard device
+
+               The raw keyboard device is used on Linux/SPARC only.
+
+    block      SCSI CD-ROM devices
                  0 = /dev/sr0          First SCSI CD-ROM
                  1 = /dev/sr1          Second SCSI CD-ROM
                      ...
@@ -450,28 +456,32 @@ an unreasonable effort.
                partitions is 15, like SCSI.
 
  29 char       Universal frame buffer
-                 0 = /dev/fb0current   First frame buffer
+                 0 = /dev/fb0          First frame buffer
                  1 = /dev/fb0autodetect
                 24 = /dev/fb0user0
                      ...
                 31 = /dev/fb0user7
-                32 = /dev/fb1current   Second frame buffer
+                32 = /dev/fb1          Second frame buffer
                 33 = /dev/fb1autodetect
                 56 = /dev/fb1user0
                      ...
                 63 = /dev/fb1user7
-    block      Aztech/Orchid/Okano/Wearnes CD-ROM
-                 0 = /dev/aztcd        Aztech CD-ROM
 
                The universal frame buffer device is currenly only
-               supported on Linux/68k.  The "current" device accesses
-               the fame buffer at current resolution; the
-               "autodetect" one at bootup (default) resolution.
-               Minor numbers 2-23 within each frame buffer assignment
-               are used for specific device-dependent resolutions.
-               There appears to be no standard naming for these devices.
-               Finally, 2-31 within each device are reserved for
-               user-selected modes, usually entered at boot time.
+               supported on Linux/68k and Linux/SPARC.  The plain
+               device accesses the frame buffer at current resolution
+               (Linux/68k calls this device "current",
+               e.g. /dev/fb0current); the "autodetect" one at bootup
+               (default) resolution.  Minor numbers 2-23 within each
+               frame buffer assignment are used for specific
+               device-dependent resolutions.  There appears to be no
+               standard naming for these devices.  Finally, 2-31
+               within each device are reserved for user-selected
+               modes, usually entered at boot time.  Currently only
+               Linux/68k uses the mode-specific devices.
+
+    block      Aztech/Orchid/Okano/Wearnes CD-ROM
+                 0 = /dev/aztcd        Aztech CD-ROM
 
  30 char       iBCS-2 compatibility devices
                  0 = /dev/socksys      Socket access
@@ -615,6 +625,7 @@ an unreasonable effort.
                 49 = /dev/ml16pb-c0    Second card, first counter/timer
                 50 = /dev/ml16pb-c1    Second card, second counter/timer
                 51 = /dev/ml16pb-c2    Second card, third counter/timer
+                     ...
 
  40            UNALLOCATED
 
@@ -732,8 +743,8 @@ For SCSI devices, /dev/tape and /dev/cdrom should point to the
 /dev/cdwriter and /dev/scanner should point to the appropriate generic
 SCSI devices (/dev/sg*).
 
-/dev/mouse may point to a dialout (alternate) TTY device, a hardware
-mouse device, or a socket for a mouse driver program (e.g. /dev/gpmdata).
+/dev/mouse may point to a primary serial TTY device, a hardware mouse
+device, or a socket for a mouse driver program (e.g. /dev/gpmdata).
 
        Sockets and pipes
 
index 4a9709e903334867d0887b5ecd469abffbf2454c..ce2397cbfb4b55c6be789b5f94437c93400b3f68 100644 (file)
@@ -53,7 +53,7 @@ Klingon language support
 
 Unfortunately, Unicode/ISO 10646 does not allocate code points for the
 language Klingon, probably fearing the potential code point explosion
-if many fictional lanugages were submitted for inclusion.  There are
+if many fictional languages were submitted for inclusion.  There are
 also political reasons (the Japanese, for example, are not too happy
 about the whole 16-bit concept to begin with.)  However, with Linux
 being a hacker-driven OS it seems this is a brilliant linguistic hack
diff --git a/MAGIC b/MAGIC
index 2764ec62a57bd1ca894b41c674199d42241573dc..157941bcf5a7219755aeca3e78fc03fa4422e30b 100644 (file)
--- a/MAGIC
+++ b/MAGIC
@@ -80,6 +80,7 @@ Ioctl Include File            Comments
 'C'    linux/soundcard.h
 'I'    linux/isdn.h
 'K'    linux/kd.h
+'L'    linux/loop.h
 'M'    linux/soundcard.h
 'P'    linux/soundcard.h
 'Q'    linux/soundcard.h
index 666a4837232837c44da7a963c2a2471e76f8fbb7..b64822f187ab75226ee52e29a61d59e959d30aad 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 70
+SUBLEVEL = 71
 
 ARCH = i386
 
@@ -196,7 +196,6 @@ xconfig: symlinks
 menuconfig: include/linux/version.h symlinks 
        $(MAKE) -C scripts/lxdialog all
        $(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in
-       
 
 config: symlinks
        $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
@@ -314,7 +313,7 @@ endif
 
 clean: archclean
        rm -f kernel/ksyms.lst include/linux/compile.h
-       rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog' -print`
+       rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print`
        rm -f core `find . -type f -name 'core' -print`
        rm -f vmlinux System.map
        rm -f .tmp* drivers/sound/configure
@@ -329,7 +328,7 @@ mrproper: clean
        rm -f .version .config* config.in config.old
        rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
        rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
-       rm -f .menuconfig.in
+       rm -f .menuconfig .menuconfig.log
        rm -f include/asm
        rm -f .depend `find . -name .depend -print`
        rm -f .hdepend
index 90d15130b8792d3203b67479ede824626e645f63..24150570835d4a075a9459c0d48fe1e485d1ee98 100644 (file)
@@ -639,7 +639,7 @@ sys_call_table:
        .quad sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
 /*100*/        .quad osf_getpriority, sys_send, sys_recv, sys_sigreturn, sys_bind
        .quad sys_setsockopt, sys_listen, do_entSys, do_entSys, do_entSys
-       .quad do_entSys, sys_sigsuspend, do_entSys, do_entSys, do_entSys
+       .quad do_entSys, sys_sigsuspend, do_entSys, sys_recvmsg, sys_sendmsg
        .quad do_entSys, sys_gettimeofday, sys_getrusage, sys_getsockopt, do_entSys
        .quad sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
        .quad sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
@@ -686,5 +686,5 @@ sys_call_table:
        .quad sys_setfsuid, sys_setfsgid, sys_ustat, sys_statfs, sys_fstatfs
        .quad sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler, sys_sched_yield
        .quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname
-       .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+       .quad sys_nanosleep, do_entSys, do_entSys, do_entSys, do_entSys
        .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
index aa8e44c1f4de4ba09ab1379bf13dfb835c1b3453..690bd01a840b6a2288170cbd29eb7d0f3a260c5a 100644 (file)
@@ -32,85 +32,95 @@ static unsigned char cache_21 = 0xff;
 static unsigned char cache_A1 = 0xff;
 
 #if NR_IRQS == 33
-  static unsigned char cache_804 = 0xef;
-  static unsigned char cache_805 = 0xff;
-  static unsigned char cache_806 = 0xff;
+  static unsigned int  cache_804 = 0x00ffffef;
 #elif NR_IRQS == 32
   static unsigned char cache_26 = 0xdf;
   static unsigned char cache_27 = 0xff;
 #endif
 
-void disable_irq(unsigned int irq_nr)
+static void mask_irq(int irq)
 {
-       unsigned long flags;
-       unsigned char mask;
+       unsigned long mask;
 
-       save_flags(flags);
-       cli();
-       mask = 1 << (irq_nr & 7);
-
-       if (irq_nr < 8) {
-               cache_21 |= mask;
-               outb(cache_21,0x21);
-       } else if (irq_nr < 16) {
-               cache_A1 |= mask;
-               outb(cache_A1,0xA1);
+       if (irq < 16) {
+               mask = 1 << (irq & 7);
+               if (irq < 8) {
+                       cache_21 |= mask;
+                       outb(cache_21, 0x21);
+               } else {
+                       cache_A1 |= mask;
+                       outb(cache_A1, 0xA1);
+               }
 #if NR_IRQS == 33
-       } else if (irq_nr < 24) {
-               cache_804 |= mask;
-               outb(cache_804, 0x804);
-       } else if (irq_nr < 32) {
-               cache_805 |= mask;
-               outb(cache_805, 0x805);
        } else {
-               cache_806 |= mask;
-               outb(cache_806, 0x806);
-#elif NR_IRQS == 32 
-       } else if (irq_nr < 24) {
-               cache_26 |= mask;
-               outb(cache_26, 0x26);
+               mask = 1 << (irq - 16);
+               cache_804 |= mask;
+               outl(cache_804, 0x804);
+#elif NR_IRQS == 32
        } else {
-               cache_27 |= mask;
-               outb(cache_27, 0x27);
+               mask = 1 << (irq & 7);
+               if (irq < 24) {
+                       cache_26 |= mask;
+                       outb(cache_26, 0x26);
+               } else {
+                       cache_27 |= mask;
+                       outb(cache_27, 0x27);
+               }
 #endif
        }
-       restore_flags(flags);
 }
 
-void enable_irq(unsigned int irq_nr)
+static void unmask_irq(unsigned long irq)
 {
-       unsigned long flags;
-       unsigned char mask;
-
-       mask = ~(1 << (irq_nr & 7));
-       save_flags(flags);
-       cli();
+       unsigned long mask;
 
-       if (irq_nr < 8) {
-               cache_21 &= mask;
-               outb(cache_21,0x21);
-       } else if (irq_nr < 16) {
-               cache_A1 &= mask;
-               outb(cache_A1,0xA1);
+       if (irq < 16) {
+               mask = ~(1 << (irq & 7));
+               if (irq < 8) {
+                       cache_21 &= mask;
+                       outb(cache_21, 0x21);
+               } else {
+                       cache_A1 &= mask;
+                       outb(cache_A1, 0xA1);
+               }
 #if NR_IRQS == 33
-       } else if (irq_nr < 24) {
-               cache_804 &= mask;
-               outb(cache_804, 0x804);
-       } else if (irq_nr < 32) {
-               cache_805 &= mask;
-               outb(cache_805, 0x805);
        } else {
-               cache_806 &= mask;
-               outb(cache_806, 0x806);
+               mask = ~(1 << (irq - 16));
+               cache_804 &= mask;
+               outl(cache_804, 0x804);
 #elif NR_IRQS == 32
-       } else if (irq_nr < 24) {
-               cache_26 &= mask;
-               outb(cache_26, 0x26);
        } else {
-               cache_27 &= mask;
-               outb(cache_27, 0x27);
+               mask = ~(1 << (irq & 7));
+
+               if (irq < 24) {
+                       cache_26 &= mask;
+                       outb(cache_26, 0x26);
+               } else {
+                       cache_27 &= mask;
+                       outb(cache_27, 0x27);
+               }
 #endif
        }
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       mask_irq(irq_nr);
+       restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+       unsigned long flags, mask;
+
+       mask = ~(1 << (irq_nr & 7));
+       save_flags(flags);
+       cli();
+       unmask_irq(irq_nr);
        restore_flags(flags);
 }
 
@@ -125,7 +135,7 @@ int get_irq_list(char *buf)
        struct irqaction * action;
 
        for (i = 0 ; i < NR_IRQS ; i++) {
-               action = *(i + irq_action);
+               action = irq_action[i];
                if (!action) 
                        continue;
                len += sprintf(buf+len, "%2d: %8d %c %s",
@@ -156,69 +166,6 @@ static inline void ack_irq(int irq)
        }
 }
 
-static inline void mask_irq(int irq)
-{
-       unsigned char mask;
-
-       mask = 1 << (irq & 7);
-       if (irq < 8) {
-               cache_21 |= mask;
-               outb(cache_21, 0x21);
-       } else if (irq < 16) {
-               cache_A1 |= mask;
-               outb(cache_A1, 0xA1);
-#if NR_IRQS == 33
-       } else if (irq < 24) {
-               cache_804 |= mask;
-               outb(cache_804, 0x804);
-       } else if (irq < 32) {
-               cache_805 |= mask;
-               outb(cache_805, 0x805);
-       } else {
-               cache_806 |= mask;
-               outb(cache_806, 0x806);
-#elif NR_IRQS == 32
-       } else if (irq < 24) {
-               cache_26 |= mask;
-               outb(cache_26, 0x26);
-       } else {
-               cache_27 |= mask;
-               outb(cache_27, 0x27);
-#endif
-       }
-}
-
-static inline void unmask_irq(unsigned long irq)
-{
-       unsigned char mask = ~(1 << (irq & 7));
-
-       if (irq < 8) {
-               cache_21 &= mask;
-               outb(cache_21, 0x21);
-       } else if (irq < 16) {
-               cache_A1 &= mask;
-               outb(cache_A1, 0xA1);
-#if NR_IRQS == 33
-       } else if (irq < 24) {
-               cache_804 &= mask;
-               outb(cache_804, 0x804);
-       } else if (irq < 32) {
-               cache_805 &= mask;
-               outb(cache_805, 0x805);
-       } else {
-               cache_806 &= mask;
-               outb(cache_806, 0x806);
-#elif NR_IRQS == 32
-       } else if (irq < 24) {
-               cache_26 &= mask;
-               outb(cache_26, 0x26);
-       } else {
-               cache_27 &= mask;
-               outb(cache_27, 0x27);
-#endif
-       }
-}
-
 int request_irq(unsigned int irq, 
                void (*handler)(int, void *, struct pt_regs *),
                unsigned long irqflags, 
@@ -235,7 +182,7 @@ int request_irq(unsigned int irq,
                return -EINVAL;
        if (!handler)
            return -EINVAL;
-       action = *(irq + irq_action);
+       action = irq_action[irq];
        if (action) {
            if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
                for (tmp = action; tmp->next; tmp = tmp->next);
@@ -265,7 +212,7 @@ int request_irq(unsigned int irq,
        if (tmp) {
            tmp->next = action;
        } else {
-           *(irq + irq_action) = action;
+           irq_action[irq] = action;
            enable_irq(irq);
            if (irq >= 8 && irq < 16) {
                enable_irq(2);  /* ensure cascade is enabled too */
@@ -278,7 +225,7 @@ int request_irq(unsigned int irq,
 
 void free_irq(unsigned int irq, void *dev_id)
 {
-       struct irqaction * action = *(irq + irq_action);
+       struct irqaction * action = irq_action[irq];
        struct irqaction * tmp = NULL;
        unsigned long flags;
 
@@ -286,7 +233,7 @@ void free_irq(unsigned int irq, void *dev_id)
                printk("Trying to free IRQ%d\n", irq);
                return;
        }
-       if (!action->handler) {
+       if (!action || !action->handler) {
                printk("Trying to free free IRQ%d\n", irq);
                return;
        }
@@ -308,11 +255,11 @@ void free_irq(unsigned int irq, void *dev_id)
        if (action && tmp) {
            tmp->next = action->next;
        } else {
-           *(irq + irq_action) = action->next;
+           irq_action[irq] = action->next;
        }
        kfree_s(action, sizeof(struct irqaction));
 
-       if (!(*(irq + irq_action))) {
+       if (!irq_action[irq]) {
            mask_irq(irq);
        }
 
@@ -325,7 +272,7 @@ static inline void handle_nmi(struct pt_regs * regs)
        printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
 }
 
-static void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
+static void unexpected_irq(int irq, struct pt_regs * regs)
 {
        struct irqaction *action;
        int i;
@@ -334,7 +281,7 @@ static void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
        printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
        printk("Expecting: ");
        for (i = 0; i < 16; i++)
-               if ((action = *(i + irq_action)))
+               if ((action = irq_action[i]))
                        while (action->handler) {
                                printk("[%s:%d] ", action->name, i);
                                action = action->next;
@@ -352,17 +299,17 @@ static void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
 
 static inline void handle_irq(int irq, void *dev_id, struct pt_regs * regs)
 {
-       struct irqaction * action = *(irq + irq_action);
+       struct irqaction * action = irq_action[irq];
 
        kstat.interrupts[irq]++;
        if (!action) {
-           unexpected_irq(irq, action->dev_id, regs);
+           unexpected_irq(irq, regs);
            return;
        }
-       while (action) {
+       do {
            action->handler(irq, action->dev_id, regs);
            action = action->next;
-       }
+       } while (action);
 }
 
 static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
@@ -375,17 +322,17 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
        }
 
        kstat.interrupts[irq]++;
-       action = *(irq_action + irq);
-       if (action->flags & SA_SAMPLE_RANDOM)
-               add_interrupt_randomness(irq);
-       /* quick interrupts get executed with no extra overhead */
-       if (action->flags & SA_INTERRUPT) {
-               while (action) {
-                       action->handler(irq, action->dev_id, regs);
-                       action = action->next;
-               }
-               ack_irq(ack);
-               return;
+       action = irq_action[irq];
+       if (action) {
+               /* quick interrupts get executed with no extra overhead */
+               if (action->flags & SA_INTERRUPT) {
+                       while (action) {
+                               action->handler(irq, action->dev_id, regs);
+                               action = action->next;
+                       }
+                       ack_irq(ack);
+                       return;
+               }
        }
        /*
         * For normal interrupts, we mask it out, and then ACK it.
@@ -400,9 +347,11 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
        ack_irq(ack);
        if (!action)
                return;
+       if (action->flags & SA_SAMPLE_RANDOM)
+               add_interrupt_randomness(irq);
        while (action) {
-           action->handler(irq, action->dev_id, regs);
-           action = action->next;
+               action->handler(irq, action->dev_id, regs);
+               action = action->next;
        }
        unmask_irq(ack);
 }
@@ -609,8 +558,8 @@ unsigned long probe_irq_on(void)
        unsigned int i;
 
        for (i = NR_IRQS - 1; i > 0; i--) {
-               action = *(i + irq_action);
-               if (!action->handler) {
+               action = irq_action[i];
+               if (!action) {
                        enable_irq(i);
                        irqs |= (1 << i);
                }
@@ -623,9 +572,7 @@ unsigned long probe_irq_on(void)
        /* now filter out any obviously spurious interrupts */
        irqmask = (((unsigned long)cache_A1)<<8) | (unsigned long) cache_21;
 #if NR_IRQS == 33
-       irqmask |= ((((unsigned long)cache_804)<<16) |
-                   (((unsigned long)cache_805)<<24) |
-                   (((unsigned long)cache_806)<<24));
+       irqmask |= (unsigned long) cache_804 << 16;
 #elif NR_IRQS == 32
        irqmask |= ((((unsigned long)cache_26)<<16) |
                    (((unsigned long)cache_27)<<24));
@@ -646,9 +593,7 @@ int probe_irq_off(unsigned long irqs)
        
        irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 #if NR_IRQS == 33
-       irqmask |= ((((unsigned long)cache_804)<<16) |
-                   (((unsigned long)cache_805)<<24) |
-                   (((unsigned long)cache_806)<<24));
+       irqmask |= (unsigned long) cache_804 << 16;
 #elif NR_IRQS == 32
        irqmask |= ((((unsigned long)cache_26)<<16) |
                    (((unsigned long)cache_27)<<24));
@@ -729,9 +674,7 @@ void init_IRQ(void)
        dma_outb(0, DMA1_CLR_MASK_REG);
        dma_outb(0, DMA2_CLR_MASK_REG);
 #if NR_IRQS == 33
-       outb(cache_804, 0x804);
-       outb(cache_805, 0x805);
-       outb(cache_806, 0x806);
+       outl(cache_804, 0x804);
 #elif NR_IRQS == 32
        outb(cache_26, 0x26);
        outb(cache_27, 0x27);
index ed371e347d1417be56107b85f269fcd631a5c933..7ad09542e905566f401b2d718eb2a9ea3b6fc231 100644 (file)
@@ -49,6 +49,8 @@ static struct symbol_table arch_symbol_table = {
        X(strncpy),
        X(strnlen),
        X(strstr),
+       X(strtok),
+       X(strchr),
        X(hwrpb),
        X(memcmp),
        X(memmove),
@@ -72,6 +74,9 @@ static struct symbol_table arch_symbol_table = {
        XNOVERS(__remlu),
        XNOVERS(__remq),
        XNOVERS(__remqu),
+       XNOVERS(memcpy),
+       XNOVERS(memset),
+       /* these shouldn't be necessary---they should be versioned: */
        XNOVERS(__memcpy),
        XNOVERS(__memset),
 #include <linux/symtab_end.h>
index 4cc4d66e8a524ee5d8df86b82887204feeb6fdb4..0c0a5ac08b0382bdf0ca02213d72d84307c9c487 100644 (file)
  */
 #define FLTI_FUNC_ADDS                 0x000
 #define FLTI_FUNC_ADDT                 0x020
-#define FLTI_FUNC_CMPTEQ               0x0a5
-#define FLTI_FUNC_CMPTLT               0x0a6
-#define FLTI_FUNC_CMPTLE               0x0a7
-#define FLTI_FUNC_CMPTUN               0x0a4
+#define FLTI_FUNC_CMPTEQ               0x025
+#define FLTI_FUNC_CMPTLT               0x026
+#define FLTI_FUNC_CMPTLE               0x027
+#define FLTI_FUNC_CMPTUN               0x024
 #define FLTI_FUNC_CVTTS_or_CVTST       0x02c
 #define FLTI_FUNC_CVTTQ                        0x02f
 #define FLTI_FUNC_CVTQS                        0x03c
@@ -288,8 +288,8 @@ alpha_fp_emul (unsigned long pc)
                break;
 
              default:
-               printk("alpha_fp_emul: unexpected function code %#lx at %#lx",
-                      opcode, pc);
+               printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n",
+                      func & 0x3f, pc);
                return 0;
        }
        /*
index 3ac62a6e8770aaa07c19146f3865f94e19a19a23..ed2bd10f046de291947204fd6f748de9b7d98285 100644 (file)
@@ -7,8 +7,8 @@
  *     Much of the core SMP work is based on previous work by Thomas Radke, to
  *     whom a great many thanks are extended.
  *
- *     Thanks to Intel for testing against several Pentium and Pentium Pro
- *     MP machines.
+ *     Thanks to Intel for making available several different Pentium and
+ *     Pentium Pro MP machines.
  *
  *     This code is released under the GNU public license version 2 or
  *     later.
@@ -543,7 +543,7 @@ void smp_boot_cpus(void)
         *      Map the local APIC into kernel space
         */
 
-       apic_reg = vremap(0xFEE00000,4096);
+       apic_reg = vremap(apic_addr,4096);
        
        if(apic_reg == NULL)
                panic("Unable to map local apic.\n");
@@ -638,17 +638,19 @@ void smp_boot_cpus(void)
                         *      Install a writable page 0 entry.
                         */
                         
+                       cfg=pg0[0];
+                       
                        CMOS_WRITE(0xa, 0xf);
                        pg0[0]=7;
                        local_invalidate();
-                       *((volatile unsigned short *) 0x467) = ((unsigned long)stack)>>4;
-                       *((volatile unsigned short *) 0x469) = 0;
+                       *((volatile unsigned short *) 0x469) = ((unsigned long)stack)>>4;
+                       *((volatile unsigned short *) 0x467) = 0;
                        
                        /*
                         *      Protect it again
                         */
                         
-                       pg0[0]= pte_val(mk_pte(0, PAGE_READONLY));
+                       pg0[0]= cfg;
                        local_invalidate();
 
                        /*
@@ -1048,7 +1050,7 @@ void smp_invalidate(void)
  *     Reschedule call back
  */
 
-void smp_reschedule_irq(int cpl, void *dev_id, struct pt_regs *regs)
+void smp_reschedule_irq(int cpl, struct pt_regs *regs)
 {
 #ifdef DEBUGGING_SMP_RESCHED
        static int ct=0;
index 88c7b628e757f08670dfbc54c5696b5be3427b1f..ef0bbfda6daf061814028defdf5548900a091506 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bare.S,v 1.2 1995/11/25 00:57:39 davem Exp $
+/* $Id: bare.S,v 1.3 1995/11/27 02:42:50 davem Exp $
  * base.S:      Ugly low-level boot program entry code.  The job of this
  *              module is to parse the boot flags, try to mount the remote
  *              root filesystem and load the kernel into virtual memory.
@@ -51,7 +51,7 @@ C_LABEL(b_block_cksum):
 start_of_execution:
        sethi   %hi(C_LABEL(first_adr_in_text)), %o1            ! This is our top
        or      %o1, %lo(C_LABEL(first_adr_in_text)), %o1       ! of stack too.
-       sub     %o1, STACKFRAME_SZ, %o1
+       sub     %o1, REGWIN_SZ, %o1
        add     %o1, 0x7, %o1
        andn    %o1, 0x7, %o1
        save    %o1, 0x0, %sp                                   ! save is an add
index a8c65c78d8207834fad35c1fa745820fdaebc864..fceee826085c482bad51583aaeaed757f4e7b0fc 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.5 1995/11/25 00:57:32 davem Exp $
+# $Id: config.in,v 1.8 1996/03/01 07:15:47 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -10,14 +10,16 @@ comment 'General setup'
 # Global things across all Sparc machines.
 define_bool CONFIG_SBUS y
 define_bool CONFIG_SUN_MOUSE y
+define_bool CONFIG_SERIAL y
 define_bool CONFIG_SUN_SERIAL y
 define_bool CONFIG_SUN_KEYBOARD y
 define_bool CONFIG_SUN_CONSOLE y
+define_bool CONFIG_NET_ALIAS n
+define_bool CONFIG_BINFMT_AOUT y
 
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-tristate 'Kernel support for A.OUT binaries' CONFIG_BINFMT_AOUT
 endmenu
 
 source drivers/block/Config.in
index 12220c708db486b1714ee1dfc6e45e59841f73f1..8e333e98b45c333440aa8b5a0870258b4e5a31ac 100644 (file)
@@ -10,13 +10,14 @@ CONFIG_SUN_MOUSE=y
 CONFIG_SUN_SERIAL=y
 CONFIG_SUN_KEYBOARD=y
 CONFIG_SUN_CONSOLE=y
+# CONFIG_NET_ALIAS is not set
+CONFIG_BINFMT_AOUT=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BINFMT_ELF is not set
-CONFIG_BINFMT_AOUT=y
 
 #
-# block devices
+# Floppy, IDE, and other block devices
 #
 # CONFIG_BLK_DEV_FD is not set
 
@@ -38,6 +39,10 @@ CONFIG_INET=y
 # CONFIG_TCP_NAGLE_OFF is not set
 CONFIG_IP_NOSR=y
 # CONFIG_SKB_LARGE is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_AX25 is not set
@@ -52,8 +57,8 @@ CONFIG_SCSI=y
 # SCSI support type (disk, tape, CDrom)
 #
 CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_BLK_DEV_SR is not set
 # CONFIG_CHR_DEV_SG is not set
 
 #
@@ -79,19 +84,22 @@ CONFIG_SUNLANCE=y
 #
 # Filesystems
 #
+# CONFIG_QUOTA is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_XIA_FS is not set
-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=y
-CONFIG_ISO9660_FS=y
+# CONFIG_SMB_FS is not set
+# CONFIG_ISO9660_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
-# CONFIG_SMB_FS is not set
 
 #
 # Kernel hacking
index bcf0c41656b7eb7679b5a0f5c63c120456d0b369..99b901345a5b34ec713d084e138b1e3d6433e822 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.18 1995/11/25 00:57:48 davem Exp $
+# $Id: Makefile,v 1.22 1996/03/01 07:15:52 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 .S.o:
        $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
-OBJS  = entry.o wof.o wuf.o etrap.o rtrap.o switch.o traps.o irq.o \
-       process.o signal.o ioport.o setup.o idprom.o probe.o mp.o  \
-       c_mp.o sys_sparc.o sunos_asm.o sparc-stub.o systbls.o      \
-       sys_sunos.o sunos_ioctl.o time.o
+all: kernel.o head.o
+
+O_TARGET := kernel.o
+O_OBJS   := entry.o wof.o wuf.o etrap.o rtrap.o switch.o traps.o irq.o  \
+           process.o signal.o ioport.o setup.o idprom.o mp.o c_mp.o    \
+           sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o  \
+           sunos_ioctl.o time.o windows.o cpu.o auxio.o devices.o ksyms.o \
+           sclow.o
 
 all: kernel.o head.o
 
 head.o: head.S
        $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
 
-kernel.o: $(OBJS)
-       $(LD) -r -o kernel.o $(OBJS)
-       sync
-
-dep:
-       $(CPP) -M *.c > .depend
-
 include $(TOPDIR)/Rules.make
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
new file mode 100644 (file)
index 0000000..ba37f42
--- /dev/null
@@ -0,0 +1,40 @@
+/* auxio.c: Probing for the Sparc AUXIO register at boot time.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/oplib.h>
+#include <asm/io.h>
+
+/* Probe and map in the Auxiliary I/O register */
+unsigned char *auxio_register;
+
+void
+auxio_probe(void)
+{
+       int node, auxio_nd;
+       struct linux_prom_registers auxregs[1];
+
+       node = prom_getchild(prom_root_node);
+       auxio_nd = prom_searchsiblings(node, "auxiliary-io");
+       if(!auxio_nd) {
+               node = prom_searchsiblings(node, "obio");
+               node = prom_getchild(node);
+               auxio_nd = prom_searchsiblings(node, "auxio");
+               if(!auxio_nd) {
+                       prom_printf("Cannot find auxio node, cannot continue...\n");
+                       prom_halt();
+               }
+       }
+       prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs));
+       prom_apply_obio_ranges(auxregs, 0x1);
+       /* Map the register both read and write */
+       auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0,
+                                                         auxregs[0].reg_size,
+                                                         "auxilliaryIO",
+                                                         auxregs[0].which_io, 0x0);
+       /* Fix the address on sun4m and sun4c. */
+       if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
+          sparc_cpu_model == sun4c)
+               auxio_register = (unsigned char *) ((int)auxio_register | 3);
+}
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
new file mode 100644 (file)
index 0000000..0233c39
--- /dev/null
@@ -0,0 +1,156 @@
+/* cpu.c: Dinky routines to look for the kind of Sparc cpu
+ *        we are on.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/oplib.h>
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/mbus.h>
+
+struct cpu_iu_info {
+  int psr_impl;
+  int psr_vers;
+  char* cpu_name;   /* should be enough I hope... */
+};
+
+struct cpu_fp_info {
+  int psr_impl;
+  int fp_vers;
+  char* fp_name;
+};
+
+/* In order to get the fpu type correct, you need to take the IDPROM's
+ * machine type value into consideration too.  I will fix this.
+ */
+struct cpu_fp_info linux_sparc_fpu[] = {
+  { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
+  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
+  { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
+  /* SparcStation SLC, SparcStation1 */
+  { 0, 3, "Weitek WTL3170/2"},
+  /* SPARCstation-5 */
+  { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
+  { 0, 5, "reserved"},
+  { 0, 6, "reserved"},
+  { 0, 7, "No FPU"},
+  { 1, 0, "ROSS HyperSparc combined IU/FPU"},
+  { 1, 1, "Lsi Logic L64814"},
+  { 1, 2, "Texas Instruments TMS390-C602A"},
+  { 1, 3, "Cypress CY7C602 FPU"},
+  { 1, 4, "reserved"},
+  { 1, 5, "reserved"},
+  { 1, 6, "reserved"},
+  { 1, 7, "No FPU"},
+  { 2, 0, "BIT B5010 or B5110/20 or B5210"},
+  { 2, 1, "reserved"},
+  { 2, 2, "reserved"},
+  { 2, 3, "reserved"},
+  { 2, 4, "reserved"},
+  { 2, 5, "reserved"},
+  { 2, 6, "reserved"},
+  { 2, 7, "No FPU"},
+  /* SuperSparc 50 module */
+  { 4, 0, "SuperSparc on-chip FPU"},
+  /* SparcClassic */
+  { 4, 4, "TI MicroSparc on chip FPU"},
+  { 5, 0, "Matsushita MN10501"},
+  { 5, 1, "reserved"},
+  { 5, 2, "reserved"},
+  { 5, 3, "reserved"},
+  { 5, 4, "reserved"},
+  { 5, 5, "reserved"},
+  { 5, 6, "reserved"},
+  { 5, 7, "No FPU"},
+};
+
+#define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
+
+struct cpu_iu_info linux_sparc_chips[] = {
+  /* Sun4/100, 4/200, SLC */
+  { 0, 0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"},
+  /* borned STP1012PGA */
+  { 0, 4, "Fujitsu  MB86904"},
+  /* SparcStation2, SparcServer 490 & 690 */
+  { 1, 0, "LSI Logic Corporation - L64811"},
+  /* SparcStation2 */
+  { 1, 1, "Cypress/ROSS CY7C601"},
+  /* Embedded controller */
+  { 1, 3, "Cypress/ROSS CY7C611"},
+  /* Ross Technologies HyperSparc */
+  { 1, 0xf, "ROSS HyperSparc RT620"},
+  { 1, 0xe, "ROSS HyperSparc RT625"},
+  /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
+  /* Someone please write the code to support this beast! ;) */
+  { 2, 0, "Bipolar Integrated Technology - B5010"},
+  { 3, 0, "LSI Logic Corporation - unknown-type"},
+  { 4, 0, "Texas Instruments, Inc. - SuperSparc 50"},
+  /* SparcClassic  --  borned STP1010TAB-50*/
+  { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
+  { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
+  { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
+  { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
+  { 4, 5, "Texas Instruments, Inc. - unknown"},
+  { 5, 0, "Matsushita - MN10501"},
+  { 6, 0, "Philips Corporation - unknown"},
+  { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
+  /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
+  { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
+  { 9, 0, "Fujitsu #3"},
+  { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+};
+
+#define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
+
+char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+
+unsigned int fsr_storage;
+
+void
+cpu_probe(void)
+{
+       int psr_impl, psr_vers, fpu_vers;
+       int i, cpuid;
+
+       cpuid = get_cpuid();
+
+       psr_impl = ((get_psr()>>28)&0xf);
+       psr_vers = ((get_psr()>>24)&0xf);
+
+       fpu_vers = ((get_fsr()>>17)&0x7);
+
+       for(i = 0; i<NSPARCCHIPS; i++) {
+               if(linux_sparc_chips[i].psr_impl == psr_impl)
+                       if(linux_sparc_chips[i].psr_vers == psr_vers) {
+                               sparc_cpu_type[cpuid] = linux_sparc_chips[i].cpu_name;
+                               break;
+                       }
+       }
+
+       if(i==NSPARCCHIPS)
+               printk("DEBUG: psr.impl = 0x%x   psr.vers = 0x%x\n", psr_impl, 
+                           psr_vers);
+
+       for(i = 0; i<NSPARCFPU; i++) {
+               if(linux_sparc_fpu[i].psr_impl == psr_impl)
+                       if(linux_sparc_fpu[i].fp_vers == fpu_vers) {
+                               sparc_fpu_type[cpuid] = linux_sparc_fpu[i].fp_name;
+                               break;
+                       }
+       }
+
+       if(i == NSPARCFPU) {
+               printk("DEBUG: psr.impl = 0x%x  fsr.vers = 0x%x\n", psr_impl,
+                           fpu_vers);
+               sparc_fpu_type[cpuid] = linux_sparc_fpu[31].fp_name;
+       }
+}
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
new file mode 100644 (file)
index 0000000..4d7c61b
--- /dev/null
@@ -0,0 +1,61 @@
+/* devices.c: Initial scan of the prom device tree for important
+ *            Sparc device nodes which we need to find.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/page.h>
+#include <asm/oplib.h>
+#include <asm/mp.h>
+#include <asm/system.h>
+
+struct prom_cpuinfo linux_cpus[NCPUS];
+int linux_num_cpus;
+
+extern void cpu_probe(void);
+extern void auxio_probe(void);
+
+unsigned long
+device_scan(unsigned long mem_start)
+{
+       char node_str[128];
+       int nd, prom_node_cpu, thismid;
+       int cpu_nds[NCPUS];  /* One node for each cpu */
+       int cpu_ctr = 0;
+
+       prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+       if(strcmp(node_str, "cpu") == 0) {
+               cpu_nds[0] = prom_root_node;
+               cpu_ctr++;
+       } else {
+               int scan;
+               scan = prom_getchild(prom_root_node);
+               nd = 0;
+               while((scan = prom_getsibling(scan)) != 0) {
+                       prom_getstring(scan, "device_type", node_str, sizeof(node_str));
+                       if(strcmp(node_str, "cpu") == 0) {
+                               cpu_nds[cpu_ctr] = scan;
+                               linux_cpus[cpu_ctr].prom_node = scan;
+                               prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+                               linux_cpus[cpu_ctr].mid = thismid;
+                               cpu_ctr++;
+                       }
+               };
+               if(cpu_ctr == 0) {
+                       printk("No CPU nodes found, cannot continue.\n");
+                       /* Probably a sun4d or sun4e, Sun is trying to trick us ;-) */
+                       halt();
+               }
+               printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
+       };
+       prom_node_cpu = cpu_nds[0];
+
+       linux_num_cpus = cpu_ctr;
+
+       cpu_probe();
+       auxio_probe();
+
+       return mem_start;
+}
index f9f56d465ab2fdd2cd09cdb74d974ef2aa5b8dba..1184a0de5bda86ff445135aab123324b289212f2 100644 (file)
@@ -1,10 +1,11 @@
-/* $Id: entry.S,v 1.65 1995/11/25 14:36:22 zaitcev Exp $
+/* $Id: entry.S,v 1.79 1996/03/01 07:15:54 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/config.h>
+#include <linux/errno.h>
 
 #include <asm/head.h>
 #include <asm/asi.h>
@@ -18,7 +19,6 @@
 #include <asm/page.h>
 #include <asm/winmacro.h>
 #include <asm/signal.h>
-#include <asm/errno.h>
 
 #define NR_SYSCALLS 255      /* Each OS is different... */
 
@@ -72,11 +72,11 @@ C_LABEL(trap_low):
        /* Make sure kgdb sees the same state we just saved. */
        LOAD_PT_GLOBALS(sp)
        LOAD_PT_INS(sp)
-       ld      [%sp + STACKFRAME_SZ + PT_Y], %l4
-       ld      [%sp + STACKFRAME_SZ + PT_WIM], %l3
-       ld      [%sp + STACKFRAME_SZ + PT_PSR], %l0
-       ld      [%sp + STACKFRAME_SZ + PT_PC], %l1
-       ld      [%sp + STACKFRAME_SZ + PT_NPC], %l2
+       ld      [%sp + REGWIN_SZ + PT_Y], %l4
+       ld      [%sp + REGWIN_SZ + PT_WIM], %l3
+       ld      [%sp + REGWIN_SZ + PT_PSR], %l0
+       ld      [%sp + REGWIN_SZ + PT_PC], %l1
+       ld      [%sp + REGWIN_SZ + PT_NPC], %l2
        rd      %tbr, %l5       /* Never changes... */
 
        /* Make kgdb exception frame. */        
@@ -95,13 +95,12 @@ C_LABEL(trap_low):
        WRITE_PAUSE
 
        call    C_LABEL(handle_exception)
-        add    %sp, STACKFRAME_SZ, %o0 ! Pass address of registers
+        add    %sp, REGWIN_SZ, %o0     ! Pass address of registers
 
        /* Load new kgdb register set. */
        LOAD_KGDB_GLOBALS(sp)
        LOAD_KGDB_INS(sp)
        LOAD_KGDB_SREGS(sp, l0, l2)
-       ld      [%sp + STACKFRAME_SZ + KGDB_WIM], %l6
        wr      %l0, 0x0, %y
 
        sethi   %hi(in_trap_handler), %l4
@@ -117,9 +116,8 @@ C_LABEL(trap_low):
        STORE_PT_INS(sp)
        STORE_PT_GLOBALS(sp)
        STORE_PT_YREG(sp, g2)
-       STORE_PT_PRIV(sp, l1, l2, l3, l6)
+       STORE_PT_PRIV(sp, l1, l2, l3)
 
-       /* Cross your fingers... */
        RESTORE_ALL
 
 
@@ -228,19 +226,20 @@ floppy_tdone:
        sethi   %hi(C_LABEL(pdma_size)), %l5
        st      %l6, [%l5 + %lo(C_LABEL(pdma_size))]
        /* Flip terminal count pin */
-       sethi   %hi(AUXIO_VADDR), %l4
-       ldub    [%l4 + %lo(AUXIO_VADDR) + 0x3], %l5
+       set     C_LABEL(auxio_register), %l4
+       ld      [%l4], %l4
+       ldub    [%l4], %l5
        or      %l5, 0xf4, %l5
-       stb     %l5, [%l4 + %lo(AUXIO_VADDR) + 0x3]
+       stb     %l5, [%l4]
 
        /* Kill some time so the bits set */
        WRITE_PAUSE
        WRITE_PAUSE
 
-       ldub    [%l4 + %lo(AUXIO_VADDR) + 0x3], %l5
+       ldub    [%l4], %l5
        andn    %l5, 0x04, %l5
        or      %l5, 0xf0, %l5
-       stb     %l5, [%l4 + %lo(AUXIO_VADDR) + 0x3]
+       stb     %l5, [%l4]
 
        /* Prevent recursion */
        sethi   %hi(C_LABEL(doing_pdma)), %l4
@@ -287,7 +286,7 @@ floppy_dosoftint:
 
        mov     11, %o0                 ! floppy irq level
        call    C_LABEL(floppy_interrupt)
-        add    %sp, STACKFRAME_SZ, %o1 ! struct pt_regs *regs
+        add    %sp, REGWIN_SZ, %o1     ! struct pt_regs *regs
 
        RESTORE_ALL
        
@@ -297,6 +296,7 @@ floppy_dosoftint:
        .globl  bad_trap_handler
 bad_trap_handler:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
 
@@ -304,6 +304,7 @@ bad_trap_handler:
        mov     %l0, %o1                ! psr
        call    C_LABEL(do_hw_interrupt)
         mov    %l1, %o2                ! pc
+
        RESTORE_ALL
        
 /* For now all IRQ's not registered get sent here. handler_irq() will
@@ -333,7 +334,7 @@ real_irq_entry:
 
        mov     %l7, %o0                ! irq level
        call    C_LABEL(handler_irq)
-        add    %sp, STACKFRAME_SZ, %o1 ! pt_regs ptr
+        add    %sp, REGWIN_SZ, %o1     ! pt_regs ptr
 
 rie_checkbh:
        sethi   %hi(C_LABEL(intr_count)), %l4
@@ -341,6 +342,7 @@ rie_checkbh:
        subcc   %l5, 0x1, %l5
        bne     2f      /* IRQ within IRQ, get out of here... */
         nop
+
        sethi   %hi(C_LABEL(bh_active)), %l3
        ld      [%l3 + %lo(C_LABEL(bh_active))], %g2
        sethi   %hi(C_LABEL(bh_mask)), %l3
@@ -348,64 +350,23 @@ rie_checkbh:
        andcc   %g2, %g3, %g0
        be      2f
         nop
+
+       /* do_bottom_half must run at normal kernel priority, ie. all
+        * IRQ's on.
+        */
+       rd      %psr, %g4
+       andn    %g4, PSR_PIL, %g4
+       wr      %g4, 0x0, %psr
+       WRITE_PAUSE
        call    C_LABEL(do_bottom_half) 
         nop
+
        /* Try again... */
        b       rie_checkbh
         nop
        
 2:
        st      %l5, [%l4 + %lo(C_LABEL(intr_count))]
-       RESTORE_ALL
-
-/* Soft IRQ's are handled just like hard IRQ's except that we
- * need to clear the IRQ line ourselves (in the interrupt reg)
- * and we don't take care of bottom-half handlers here.  We'll
- * just deal with it at the next clock tick, and since software
- * IRQ's relatively don't happen that often....
- * XXX BIG XXX Turn the software IRQ bit we need to clear into
- * XXX BIG XXX an element reference in an array that we can set
- * XXX BIG XXX a boot time based upon arch type
- * XXX BIG XXX OR... rewrite the appropriate IRQ trap table
- * XXX BIG XXX entries once the arch is detected (sun4/4c or sun4m)
- *
- * XXX EVEN BIGGER XXX Linux has bh_handlers for software interrupts
- * XXX EVEN BIGGER XXX so we do not even have to worry about this
- * XXX EVEN BIGGER XXX brain damaged software interrupt mechanism.
- */
-
-       .align  4
-       .globl  soft_irq_entry
-soft_irq_entry:
-       SAVE_ALL
-
-       /* We have tucked the bit to clear in the int reg into
-        * %l4, take care of it now before we do anything else.
-        */
-       sethi   %hi(INTREG_VADDR), %l5
-       ldsb    [%l5 + %lo(INTREG_VADDR)], %l6
-       andn    %l6, %l4, %l6
-       stb     %l6, [%l5 + %lo(INTREG_VADDR)]
-
-       /* start atomic operation with respect to software interrupts */
-       sethi   %hi(C_LABEL(intr_count)), %l4
-       ld      [%l4 + %lo(C_LABEL(intr_count))], %l5
-       add     %l5, 0x1, %l5
-       st      %l5, [%l4 + %lo(C_LABEL(intr_count))]
-
-       or      %l0, PSR_PIL, %l4
-       wr      %l4, 0x0, %psr          ! grrr!
-       wr      %l4, PSR_ET, %psr       ! double grrr!
-
-       mov     %l7, %o0        
-       add     %sp, STACKFRAME_SZ, %o1
-       call    C_LABEL(handler_irq)
-        nop
-
-       sethi   %hi(C_LABEL(intr_count)), %l4
-       ld      [%l4 + %lo(C_LABEL(intr_count))], %l5
-       subcc   %l5, 0x1, %l5
-       st      %l5, [%l4 + %lo(C_LABEL(intr_count))]
 
        RESTORE_ALL
 
@@ -416,10 +377,11 @@ soft_irq_entry:
        .globl  bad_instruction
 bad_instruction:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(do_illegal_instruction)
@@ -430,14 +392,16 @@ bad_instruction:
        .globl  priv_instruction
 priv_instruction:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(do_priv_instruction)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles unaligned data accesses.
@@ -446,14 +410,16 @@ priv_instruction:
        .globl  mna_handler
 mna_handler:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(do_memaccess_unaligned)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles floating point disabled traps. */
@@ -461,29 +427,44 @@ mna_handler:
        .globl  fpd_trap_handler
 fpd_trap_handler:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(do_fpd_trap)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles Floating Point Exceptions. */
        .align  4
        .globl  fpe_trap_handler
 fpe_trap_handler:
+       set     fpsave_magic, %l5
+       cmp     %l1, %l5
+       bne     1f
+        sethi  %hi(fpsave_catch), %l5
+       or      %l5, %lo(fpsave_catch), %l5
+       wr      %l0, 0x0, %psr
+       WRITE_PAUSE
+       jmp     %l5
+        rett   %l5 + 4
+
+1:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(do_fpe_trap)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles Tag Overflow Exceptions. */
@@ -491,14 +472,16 @@ fpe_trap_handler:
        .globl  do_tag_overflow
 do_tag_overflow:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(handle_tag_overflow)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles Watchpoint Exceptions. */
@@ -506,14 +489,16 @@ do_tag_overflow:
        .globl  do_watchpoint
 do_watchpoint:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(handle_watchpoint)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles Register Access Exceptions. */
@@ -521,14 +506,16 @@ do_watchpoint:
        .globl  do_reg_access
 do_reg_access:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(handle_reg_access)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles Co-Processor Disabled Exceptions. */
@@ -536,14 +523,16 @@ do_reg_access:
        .globl  do_cp_disabled
 do_cp_disabled:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(handle_cp_disabled)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles Unimplemented FLUSH Exceptions. */
@@ -551,14 +540,16 @@ do_cp_disabled:
        .globl  do_bad_flush
 do_bad_flush:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(handle_bad_flush)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles Co-Processor Exceptions. */
@@ -566,14 +557,16 @@ do_bad_flush:
        .globl  do_cp_exception
 do_cp_exception:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(handle_cp_exception)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        /* This routine handles Hardware Divide By Zero Exceptions. */
@@ -581,14 +574,16 @@ do_cp_exception:
        .globl  do_hw_divzero
 do_hw_divzero:
        SAVE_ALL
+
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
 
-       add     %sp, STACKFRAME_SZ, %o0
+       add     %sp, REGWIN_SZ, %o0
        mov     %l1, %o1
        mov     %l2, %o2
        call    C_LABEL(handle_hw_divzero)
         mov    %l0, %o3
+
        RESTORE_ALL
 
        .align  4
@@ -599,15 +594,24 @@ do_flush_windows:
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
 
+       andcc   %l0, PSR_PS, %g0
+       bne     dfw_kernel
+        nop
+
        call    C_LABEL(flush_user_windows)
         nop
 
        /* Advance over the trap instruction. */
-       ld      [%sp + STACKFRAME_SZ + PT_NPC], %l1
+       ld      [%sp + REGWIN_SZ + PT_NPC], %l1
        add     %l1, 0x4, %l2
-       st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
-       st      %l2, [%sp + STACKFRAME_SZ + PT_NPC]
+       st      %l1, [%sp + REGWIN_SZ + PT_PC]
+       st      %l2, [%sp + REGWIN_SZ + PT_NPC]
+
+       RESTORE_ALL
 
+       /* We get these for debugging routines using __builtin_return_address() */
+dfw_kernel:
+       FLUSH_ALL_KERNEL_WINDOWS
        RESTORE_ALL
 
        /* The getcc software trap.  The user wants the condition codes from
@@ -635,6 +639,7 @@ setcc_trap_handler:
        andn    %l0, %l5, %l0   ! clear ICC bits in current %psr
        and     %l4, %l5, %l4   ! clear non-ICC bits in user value
        or      %l4, %l0, %l4   ! or them in... mix mix mix
+
        wr      %l4, 0x0, %psr  ! set new %psr
        WRITE_PAUSE             ! TI scumbags...
 
@@ -642,9 +647,10 @@ setcc_trap_handler:
        rett    %l2 + 0x4       ! like this...
 
        .align  4
-       .globl  linux_trap_nmi
-linux_trap_nmi:
+       .globl  linux_trap_nmi_sun4c
+linux_trap_nmi_sun4c:
        SAVE_ALL
+
        /* Ugh, we need to clear the IRQ line.  This is now
         * a very sun4c specific trap hanler...
         */
@@ -673,20 +679,116 @@ linux_trap_nmi:
        sub     %o0, 0x4, %o0
        lda     [%o0] ASI_CONTROL, %o3  ! async error
        call    C_LABEL(sparc_lvl15_nmi)
-        add    %sp, STACKFRAME_SZ, %o0
+        add    %sp, REGWIN_SZ, %o0
 
        RESTORE_ALL
 
+#if 0 /* WIP */
+       /* Inter-Processor Interrupts on the Sun4m. */
+       .align  4
+       .globl  sun4m_ipi
+sun4m_ipi:
+       SAVE_ALL_IPI4M
+
+       set     MAILBOX_ADDRESS, %l4
+       ldub    [%l4], %l5
+       subcc   %l5, MBOX_STOPCPU, %g0
+       bne,a   1f
+        subcc  %l5, MBOX_STOPCPU2, %g0
+
+       call    C_LABEL(prom_stopcpu)
+        mov    0, %o0
+       ba,a    2f      
+
+1:
+       bne,a   1f
+        subcc  %l5, MBOX_IDLECPU, %g0
+
+       call    C_LABEL(prom_stopcpu)
+        mov    0, %o0
+       ba,a    2f      
+
+1:
+       bne,a   1f
+        subcc  %l5, MBOX_IDLECPU2, %g0
+
+       call    C_LABEL(prom_idlecpu)
+        mov    0, %o0
+       ba,a    2f      
+
+1:
+       bne,a   2f
+        nop
+
+       call    C_LABEL(prom_idlecpu)
+        mov    0, %o0
+       ba,a    2f      
+
+2:
+       call    C_LABEL(smp_callin)
+
+       RESTORE_ALL_IPI4M
+#endif
+
        .align  4
-       .globl  sparc_fault
-sparc_fault:
+       .globl  sun4c_fault
+sun4c_fault:
        SAVE_ALL
-       rd      %tbr, %o1
+
+       /* XXX This needs to be scheduled better */
+       sethi   %hi(AC_SYNC_ERR), %l4
+       add     %l4, 0x4, %l5           ! AC_SYNC_VA in %l5
+       lda     [%l5] ASI_CONTROL, %o3          /* Address */
+       lda     [%l4] ASI_CONTROL, %l6
+       srl     %l6, 15, %l6
+       and     %l6, 1, %o2     /* Write? */
+
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
 
+       mov     %l7, %o1                        /* Text fault? */
        call    C_LABEL(do_sparc_fault)
-        add    %sp, STACKFRAME_SZ, %o0
+        add    %sp, REGWIN_SZ, %o0             /* pt_regs */
+
+       RESTORE_ALL
+
+       .align  4
+       .globl  C_LABEL(srmmu_fault)
+C_LABEL(srmmu_fault):
+       /* Slot 1 */
+       mov     0x400, %l5
+       mov     0x300, %l4
+
+       /* Slot 2 */
+       lda     [%l5] ASI_M_MMUREGS, %l6        ! read sfar first
+       lda     [%l4] ASI_M_MMUREGS, %l5        ! read sfsr last
+
+       /* Slot 3 */
+       andn    %l6, 0xfff, %l6
+       srl     %l5, 6, %l5                     ! and encode all info into l7
+
+       /* Slot 4 */
+       and     %l5, 2, %l5
+       or      %l5, %l6, %l6
+
+       /* Slot 5 */
+       or      %l6, %l7, %l7                   ! l7 = [addr,write,txtfault]
+
+       SAVE_ALL
+
+       mov     %l7, %o1
+       mov     %l7, %o2
+       and     %o1, 1, %o1             ! arg2 = text_faultp
+       mov     %l7, %o3
+       and     %o2, 2, %o2             ! arg3 = writep
+       andn    %o3, 0xfff, %o3         ! arg4 = faulting address
+
+       wr      %l0, PSR_ET, %psr
+       WRITE_PAUSE
+
+       call    C_LABEL(do_sparc_fault)
+        add    %sp, REGWIN_SZ, %o0     ! arg1 = pt_regs ptr
+
        RESTORE_ALL
 
        /* SunOS uses syscall zero as the 'indirect syscall' it looks
@@ -695,9 +797,9 @@ sparc_fault:
         */
        .globl  C_LABEL(sunos_indir)
 C_LABEL(sunos_indir):
-       ld      [%sp + STACKFRAME_SZ + PT_I0], %g1
+       ld      [%sp + REGWIN_SZ + PT_I0], %g1
        cmp     %g1, NR_SYSCALLS
-       bleu,a  1f
+       blu,a   1f
         sll    %g1, 0x2, %g1
 
        set     C_LABEL(sunos_nosys), %l6
@@ -709,21 +811,31 @@ C_LABEL(sunos_indir):
        ld      [%l7 + %g1], %l6
 
 2:     
-       ld      [%sp + STACKFRAME_SZ + PT_I1], %o0
-       ld      [%sp + STACKFRAME_SZ + PT_I2], %o1
-       ld      [%sp + STACKFRAME_SZ + PT_I3], %o2
-       ld      [%sp + STACKFRAME_SZ + PT_I4], %o3
+       ld      [%sp + REGWIN_SZ + PT_I1], %o0
+       ld      [%sp + REGWIN_SZ + PT_I2], %o1
+       ld      [%sp + REGWIN_SZ + PT_I3], %o2
+       ld      [%sp + REGWIN_SZ + PT_I4], %o3
        call    %l6
-        ld     [%sp + STACKFRAME_SZ + PT_I5], %o4
+        ld     [%sp + REGWIN_SZ + PT_I5], %o4
 
        b       scall_store_args                /* so stupid... */
         nop
 
+#if 0 /* work in progress */
+       .align 4
+       .globl  C_LABEL(sys_ptrace)
+C_LABEL(sys_ptrace):
+       call    C_LABEL(do_ptrace)
+        add    %sp, REGWIN_SZ, %o0
+
+       RESTORE_ALL
+#endif
+
        .align  4
        .globl  C_LABEL(sys_execve)
 C_LABEL(sys_execve):
        call    C_LABEL(sparc_execve)
-        add    %sp, STACKFRAME_SZ, %o0         ! pt_regs *regs arg
+        add    %sp, REGWIN_SZ, %o0             ! pt_regs *regs arg
 
        b       scall_store_args
         nop
@@ -732,16 +844,38 @@ C_LABEL(sys_execve):
        .globl  C_LABEL(sys_pipe)
 C_LABEL(sys_pipe):
        call    C_LABEL(sparc_pipe)
-        add    %sp, STACKFRAME_SZ, %o0         ! pt_regs *regs arg
+        add    %sp, REGWIN_SZ, %o0             ! pt_regs *regs arg
 
        b       C_LABEL(ret_sys_call)
         nop
 
+       .align  4
+       .globl  C_LABEL(sys_sigpause)
+C_LABEL(sys_sigpause):
+       ld      [%sp + REGWIN_SZ + PT_I0], %o0
+       call    C_LABEL(do_sigpause)
+        add    %sp, REGWIN_SZ, %o1
+
+       /* We are returning to a signal handler. */
+
+       RESTORE_ALL
+
+       .align  4
+       .globl  C_LABEL(sys_sigsuspend)
+C_LABEL(sys_sigsuspend):
+       ld      [%sp + REGWIN_SZ + PT_I0], %o0
+       call    C_LABEL(do_sigsuspend)
+        add    %sp, REGWIN_SZ, %o1
+
+       /* We are returning to a signal handler. */
+
+       RESTORE_ALL
+
        .align  4
        .globl  C_LABEL(sys_sigreturn)
 C_LABEL(sys_sigreturn):
        call    C_LABEL(do_sigreturn)
-        add    %sp, STACKFRAME_SZ, %o0
+        add    %sp, REGWIN_SZ, %o0
 
        /* We don't want to muck with user registers like a
         * normal syscall, just return.
@@ -759,16 +893,15 @@ C_LABEL(sys_fork):
        /* Save the kernel state as of now. */
        FLUSH_ALL_KERNEL_WINDOWS;
        STORE_WINDOW(sp)
-       LOAD_CURRENT(g6)
+       LOAD_CURRENT(g6, g5)
        rd      %psr, %g4
        rd      %wim, %g5
-       std     %g4, [%g6 + THREAD_KPSR]
-       std     %sp, [%g6 + THREAD_KSP]
+       std     %g4, [%g6 + THREAD_FORK_KPSR]
 
        mov     SIGCHLD, %o0                    ! arg0: clone flags
-       mov     %fp, %o1                        ! arg1: usp
+       ld      [%sp + REGWIN_SZ + PT_FP], %o1  ! arg1: usp
        call    C_LABEL(do_fork)
-        add    %sp, STACKFRAME_SZ, %o2         ! arg2: pt_regs ptr
+        add    %sp, REGWIN_SZ, %o2             ! arg2: pt_regs ptr
 
        b       scall_store_args
         nop
@@ -779,151 +912,210 @@ C_LABEL(sys_clone):
        /* Save the kernel state as of now. */
        FLUSH_ALL_KERNEL_WINDOWS;
        STORE_WINDOW(sp)
-       LOAD_CURRENT(g6)
+       LOAD_CURRENT(g6, g5)
        rd      %psr, %g4
        rd      %wim, %g5
-       std     %g4, [%g6 + THREAD_KPSR]
-       std     %sp, [%g6 + THREAD_KSP]
+       std     %g4, [%g6 + THREAD_FORK_KPSR]
 
-       ldd     [%sp + STACKFRAME_SZ + PT_I0], %o0      ! arg0,1: flags,usp
-       cmp     %o1, 0x0                                ! Is new_usp NULL?
+       ldd     [%sp + REGWIN_SZ + PT_I0], %o0  ! arg0,1: flags,usp
+       cmp     %o1, 0x0                        ! Is new_usp NULL?
        be,a    1f
-        mov    %fp, %o1                                ! yes, use current usp
+        ld     [%sp + REGWIN_SZ + PT_FP], %o1  ! yes, use current usp
 1:
        call    C_LABEL(do_fork)
-        add    %sp, STACKFRAME_SZ, %o2                 ! arg2: pt_regs ptr
+        add    %sp, REGWIN_SZ, %o2             ! arg2: pt_regs ptr
 
        b       scall_store_args
         nop
 
-#if 0 /* XXX Much later... XXX */
-       /* Whee, vfork... */
-       .globl  C_LABEL(sys_vfork)
-C_LABEL(sys_vfork):
-       /* Save the kernel state as of now. */
-       FLUSH_ALL_KERNEL_WINDOWS;
-       STORE_WINDOW(sp)
-       LOAD_CURRENT(g6)
-       rd      %psr, %g4
-       rd      %wim, %g5
-       std     %g4, [%g6 + THREAD_KPSR]
-       std     %sp, [%g6 + THREAD_KSP]
-
-       set     (0x2100 | SIGCHLD), %o0                 ! CLONE_VFORK,CLONE_VM,SIGCHLD
-       mov     %fp, %o1                                ! use current usp
-1:
-       call    C_LABEL(do_fork)
-        add    %sp, STACKFRAME_SZ, %o2                 ! arg2: pt_regs ptr
-
-       b       scall_store_args
-        nop
-#endif
-
        /* All system calls enter here... */
        .align  4
        .globl  linux_sparc_syscall
 linux_sparc_syscall:
-       /* Don't dork with %l7, it holds the pointer to the
-        * system call vector table.  SAVE_ALL does not
-        * modify its value.
+       /* While we are here trying to optimize our lives
+        * away, handle the easy bogus cases like a
+        * ni_syscall or sysnum > NR_SYSCALLS etc.
+        * In the cases where we cannot optimize the
+        * call inline we don't really lose anything
+        * performance wise because we are doing here
+        * things which we did anyway in the original
+        * routine.  The only added complexity is a
+        * bit test, compare, and branch to decide
+        * if we need to save process state or not.
         */
-       rd      %wim, %l3
-       SAVE_ALL
-
-       wr      %l0, PSR_ET, %psr       /* Turn on traps + interrupts */
-       WRITE_PAUSE
 
-#if 0 /* Trace all system calls... */
-       add     %sp, STACKFRAME_SZ, %o0
-       call    C_LABEL(syscall_trace_entry)
-        nop
-#endif
+       /* XXX TODO: When we have ptrace working test
+        * XXX       test for PF_TRACESYS in task flags.
+        */
 
-       /* SAVE_ALL may have blown away %g1, reload it. */
-       ld      [%sp + STACKFRAME_SZ + PT_G1], %g1
+       /* Direct access to user regs, must faster. */
        cmp     %g1, NR_SYSCALLS
-       bleu,a  1f
-        sll    %g1, 0x2, %g1
+       blu,a   1f
+        sll    %g1, 2, %l4
 
-       set     C_LABEL(sys_ni_syscall), %l6
-       b       2f
-        nop
+       b       syscall_is_too_hard
+        set    C_LABEL(sys_ni_syscall), %l7
 
 1:
-       /* Syscall table ptr is in %l7. */
-       ld      [%l7 + %g1], %l6        ! load up ptr to syscall handler
+       ld      [%l7 + %l4], %l7
 
-       /* Pt_regs is your friend... Make the syscall... */
-2:
-       ldd     [%sp + STACKFRAME_SZ + PT_I0], %o0
-       ldd     [%sp + STACKFRAME_SZ + PT_I2], %o2
-       ldd     [%sp + STACKFRAME_SZ + PT_I4], %o4
-       call    %l6
+       /* If bit-1 is set, this is a "fast" syscall.
+        * This is the _complete_ overhead of this optimization,
+        * and we save ourselves a load, so it evens out to nothing.
+        */
+       andcc   %l7, 0x1, %g0
+       be      syscall_is_too_hard
+        andn   %l7, 0x1, %l7
+
+       jmpl    %l7, %g0
         nop
 
+       .globl  syscall_is_too_hard
+syscall_is_too_hard:
+       rd      %wim, %l3
+       SAVE_ALL
+
+       wr      %l0, PSR_ET, %psr
+       WRITE_PAUSE
+
+2:
+       ldd     [%sp + REGWIN_SZ + PT_I0], %o0
+       st      %o0, [%sp + REGWIN_SZ + PT_G0]  ! for restarting syscalls
+       ldd     [%sp + REGWIN_SZ + PT_I2], %o2
+       call    %l7
+        ldd    [%sp + REGWIN_SZ + PT_I4], %o4
+
 scall_store_args:
-       st      %o0, [%sp + STACKFRAME_SZ + PT_I0]
+       st      %o0, [%sp + REGWIN_SZ + PT_I0]
 
        .globl  C_LABEL(ret_sys_call)
 C_LABEL(ret_sys_call):
-       ld      [%sp + STACKFRAME_SZ + PT_I0], %o0
+       ld      [%sp + REGWIN_SZ + PT_I0], %o0
        set     PSR_C, %l6
-       cmp     %o0, -ELIBSCN
+       cmp     %o0, -ENOIOCTLCMD
        bgeu    1f
-        ld     [%sp + STACKFRAME_SZ + PT_PSR], %l5
+        ld     [%sp + REGWIN_SZ + PT_PSR], %l5
 
        /* System call success, clear Carry condition code. */          
        andn    %l5, %l6, %l5
        b       2f
-        st     %l5, [%sp + STACKFRAME_SZ + PT_PSR]     
+        st     %l5, [%sp + REGWIN_SZ + PT_PSR] 
 
 1:
        /* System call failure, set Carry condition code.
         * Also, get abs(errno) to return to the process.
         */
        sub     %g0, %o0, %o0
-       st      %o0, [%sp + STACKFRAME_SZ + PT_I0]
+       st      %o0, [%sp + REGWIN_SZ + PT_I0]
        or      %l5, %l6, %l5
-       st      %l5, [%sp + STACKFRAME_SZ + PT_PSR]
+       st      %l5, [%sp + REGWIN_SZ + PT_PSR]
 
-       /* %i6 is our frame pointer, the restore done by the rett
-        * instruction will automatically put us back on the users
-        * stack.  Advance the pc and npc past the trap instruction.
-        */
+       /* Advance the pc and npc over the trap instruction. */
 2:
-       ld      [%sp + STACKFRAME_SZ + PT_NPC], %l1     /* pc  = npc   */
-       add     %l1, 0x4, %l2                           /* npc = npc+4 */
-       st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
-       st      %l2, [%sp + STACKFRAME_SZ + PT_NPC]
-
-#if 0 /* Trace all system calls... */
-       add     %sp, STACKFRAME_SZ, %o0
-       call    C_LABEL(syscall_trace_exit)
-        nop
-#endif
+       ld      [%sp + REGWIN_SZ + PT_NPC], %l1 /* pc  = npc   */
+       add     %l1, 0x4, %l2                   /* npc = npc+4 */
+       st      %l1, [%sp + REGWIN_SZ + PT_PC]
+       st      %l2, [%sp + REGWIN_SZ + PT_NPC]
 
        RESTORE_ALL
 
-       .globl  C_LABEL(flush_user_windows)
-C_LABEL(flush_user_windows):
-       LOAD_CURRENT(g2)
-       ld      [%g2 + THREAD_UMASK], %g1
-       orcc    %g0, %g1, %g0
-       be      3f
-        clr    %g3
+/* Saving and restoring the FPU state is best done from lowlevel code.
+ *
+ * void fpsave(unsigned long *fpregs, unsigned long *fsr,
+ *             void *fpqueue, unsigned long *fpqdepth)
+ */
+
+       .globl  C_LABEL(fpsave)
+C_LABEL(fpsave):
+       st      %fsr, [%o1]
+       ld      [%o1], %g1
+       set     0x2000, %g4
+       andcc   %g1, %g4, %g0
+       be      2f
+        mov    0, %g2
+
+       /* We have an fpqueue to save. */
 1:
-       _SV
-       LOAD_CURRENT(g2)
-       ld      [%g2 + THREAD_UMASK], %g1
-       orcc    %g0, %g1, %g0
+       std     %fq, [%o2]
+fpsave_magic:
+       st      %fsr, [%o1]
+       ld      [%o1], %g3
+       andcc   %g3, %g4, %g0
+       add     %g2, 1, %g2
        bne     1b
-        add    %g3, 1, %g3
+        add    %o2, 8, %o2
+
 2:
-       subcc   %g3, 1, %g3
-       bne     2b
-        _RS
-3:
-       jmp     %o7 + 0x8
+       st      %g2, [%o3]
+
+       std     %f0, [%o0 + 0x00]
+       std     %f2, [%o0 + 0x08]
+       std     %f4, [%o0 + 0x10]
+       std     %f6, [%o0 + 0x18]
+       std     %f8, [%o0 + 0x20]
+       std     %f10, [%o0 + 0x28]
+       std     %f12, [%o0 + 0x30]
+       std     %f14, [%o0 + 0x38]
+       std     %f16, [%o0 + 0x40]
+       std     %f18, [%o0 + 0x48]
+       std     %f20, [%o0 + 0x50]
+       std     %f22, [%o0 + 0x58]
+       std     %f24, [%o0 + 0x60]
+       std     %f26, [%o0 + 0x68]
+       std     %f28, [%o0 + 0x70]
+       retl
+        std    %f30, [%o0 + 0x78]
+
+       /* Thanks for Theo Deraadt and the authors of the Sprite/netbsd/openbsd
+        * code for pointing out this possible deadlock, while we save state
+        * above we could trap on the fsr store so our low level fpu trap
+        * code has to know how to deal with this.
+        */
+fpsave_catch:
+       b       fpsave_magic + 4
+        st     %fsr, [%o1]
+
+       /* void fpload(unsigned long *fpregs, unsigned long *fsr); */
+
+       .globl  C_LABEL(fpload)
+C_LABEL(fpload):
+       ldd     [%o0 + 0x00], %f0
+       ldd     [%o0 + 0x08], %f2
+       ldd     [%o0 + 0x10], %f4
+       ldd     [%o0 + 0x18], %f6
+       ldd     [%o0 + 0x20], %f8
+       ldd     [%o0 + 0x28], %f10
+       ldd     [%o0 + 0x30], %f12
+       ldd     [%o0 + 0x38], %f14
+       ldd     [%o0 + 0x40], %f16
+       ldd     [%o0 + 0x48], %f18
+       ldd     [%o0 + 0x50], %f20
+       ldd     [%o0 + 0x58], %f22
+       ldd     [%o0 + 0x60], %f24
+       ldd     [%o0 + 0x68], %f26
+       ldd     [%o0 + 0x70], %f28
+       ldd     [%o0 + 0x78], %f30
+       ld      [%o1], %fsr
+       retl
         nop
 
+       .globl  C_LABEL(udelay)
+C_LABEL(udelay):
+       save    %sp, -REGWIN_SZ, %sp
+       mov     %i0, %o0
+       sethi   %hi(0x10c6), %o1
+       call    .umul
+        or     %o1, %lo(0x10c6), %o1
+       sethi   %hi(C_LABEL(loops_per_sec)), %o3
+       call    .umul
+        ld     [%o3 + %lo(C_LABEL(loops_per_sec))], %o1
+
+       cmp     %o1, 0x0
+1:
+       bne     1b
+        subcc  %o1, 1, %o1
+       
+       ret
+       restore
+
 /* End of entry.S */
index 82b1a1b56b052d49ae0d4adedf3b3cdff9b0fd18..da59ab1c2553c1e61a5b079c5888a23817cccfd0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.10 1995/11/25 00:57:58 davem Exp $
+/* $Id: etrap.S,v 1.16 1996/02/20 07:45:01 davem Exp $
  * etrap.S: Sparc trap window preparation for entry into the
  *          Linux kernel.
  *
@@ -7,6 +7,8 @@
 
 #include <asm/cprefix.h>
 #include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/contregs.h>
 #include <asm/page.h>
 #include <asm/psr.h>
 #include <asm/ptrace.h>
@@ -84,8 +86,8 @@ trap_setup:
        /* From kernel, allocate more kernel stack and
         * build a pt_regs trap frame.
         */
-       sub     %fp, (STACKFRAME_SZ + TRACEREG_SZ), %t_kstack
-       STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, t_wim, g2)
+       sub     %fp, (REGWIN_SZ + TRACEREG_SZ), %t_kstack
+       STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
 
        /* See if we are in the trap window. */
        andcc   %t_twinmask, %t_wim, %g0
@@ -99,12 +101,11 @@ trap_setup:
         * Just do it...
         */
 1:
-       mov     %t_kstack, %sp          ! jump onto new stack
        jmpl    %t_retpc + 0x8, %g0     ! return to caller
-        nop
+        mov    %t_kstack, %sp          ! jump onto new stack
 
 trap_setup_kernel_spill:
-       LOAD_CURRENT(curptr)
+       LOAD_CURRENT(curptr, g1)
        ld      [%curptr + THREAD_UMASK], %g1
        orcc    %g0, %g1, %g0
        bne     trap_setup_user_spill   ! there are some user windows, yuck
@@ -129,21 +130,21 @@ tsetup_patch2:    and     %g2, 0xff, %g2          ! patched on 7 window Sparcs
 
        restore %g0, %g0, %g0
 
-       mov     %t_kstack, %sp          ! and onto new kernel stack
        jmpl    %t_retpc + 0x8, %g0     ! return to caller
-        nop
+        mov    %t_kstack, %sp          ! and onto new kernel stack
 
 trap_setup_from_user:
        /* We can't use %curptr yet. */
-       LOAD_CURRENT(t_kstack)
-       ld      [%t_kstack + TASK_KSTACK_PG], %t_kstack
+       LOAD_CURRENT(t_kstack, t_twinmask)
+       mov     1, %t_twinmask
+       ld      [%t_kstack + TASK_SAVED_KSTACK], %t_kstack
+       sll     %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
 
        /* Build pt_regs frame. */
-       add     %t_kstack, (PAGE_SIZE - STACKFRAME_SZ - TRACEREG_SZ), %t_kstack
-       STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, t_wim, g2)
+       STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
 
        /* Clear current->tss.w_saved */
-       LOAD_CURRENT(curptr)
+       LOAD_CURRENT(curptr, g1)
        st      %g0, [%curptr + THREAD_W_SAVED]
 
        /* See if we are in the trap window. */
@@ -176,9 +177,8 @@ trap_setup_from_user:
 tsetup_patch3: and     %g2, 0xff, %g2                  ! patched on 7win Sparcs
                st      %g2, [%curptr + THREAD_UMASK]   ! store new umask
 
-               mov     %t_kstack, %sp                  ! and onto kernel stack
                jmpl    %t_retpc + 0x8, %g0             ! return to caller
-                nop
+                mov    %t_kstack, %sp                  ! and onto kernel stack
 
 trap_setup_user_spill:
                /* A spill occured from either kernel or user mode
@@ -213,18 +213,18 @@ trap_setup_user_stack_is_bolixed:
         */
        SAVE_BOLIXED_USER_STACK(curptr, g3)
        restore %g0, %g0, %g0
-       mov     %t_kstack, %sp
+
        jmpl    %t_retpc + 0x8, %g0
-        nop
+        mov    %t_kstack, %sp
 
 trap_setup_good_ustack:
        STORE_WINDOW(sp)
 
 trap_setup_finish_up:
        restore %g0, %g0, %g0
-       mov     %t_kstack, %sp
+
        jmpl    %t_retpc + 0x8, %g0
-        nop
+        mov    %t_kstack, %sp
 
        /* Architecture specific stack checking routines.  When either
         * of these routines are called, the globals are free to use
@@ -234,7 +234,6 @@ trap_setup_finish_up:
 #define glob_tmp     g1
 
        .globl  C_LABEL(tsetup_sun4c_stackchk)
-       .globl  C_LABEL(tsetup_srmmu_stackchk)
 C_LABEL(tsetup_sun4c_stackchk):
        /* Done by caller: andcc %sp, 0x7, %g0 */
        be      1f
@@ -293,6 +292,7 @@ tsetup_sun4c_onepage:
        b       trap_setup_user_stack_is_bolixed
         nop
 
+       .globl  C_LABEL(tsetup_srmmu_stackchk)
 C_LABEL(tsetup_srmmu_stackchk):
        /* Check results of callers andcc %sp, 0x7, %g0 */
        bne     trap_setup_user_stack_is_bolixed
@@ -302,8 +302,6 @@ C_LABEL(tsetup_srmmu_stackchk):
         nop
 
        /* Clear the fault status and turn on the no_fault bit. */
-       mov     AC_M_SFSR, %glob_tmp                    ! delay from above...
-       lda     [%glob_tmp] ASI_M_MMUREGS, %g0          ! eat SFSR
        lda     [%g0] ASI_M_MMUREGS, %glob_tmp          ! read MMU control
        or      %glob_tmp, 0x2, %glob_tmp               ! or in no_fault bit
        sta     %glob_tmp, [%g0] ASI_M_MMUREGS          ! set it
@@ -317,10 +315,11 @@ C_LABEL(tsetup_srmmu_stackchk):
        mov     AC_M_SFAR, %glob_tmp
        lda     [%glob_tmp] ASI_M_MMUREGS, %g0
        mov     AC_M_SFSR, %glob_tmp
-       lda     [%glob_tmp] ASI_M_MMUREGS, %glob_tmp
+       lda     [%glob_tmp] ASI_M_MMUREGS, %glob_tmp    ! save away status of winstore
        andcc   %glob_tmp, 0x2, %g0                     ! did we fault?
        be      trap_setup_finish_up                    ! cool beans, success
         nop
 
        b       trap_setup_user_stack_is_bolixed        ! we faulted, ugh
         nop
+
index bad6b0be27fdfdc68518b60cc363a1640224e043..0fadc0f6599e8c91f08e68dc49f5a896b02c4f08 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.39 1995/11/25 00:58:01 davem Exp $
+/* $Id: head.S,v 1.47 1996/02/15 09:11:57 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -49,7 +49,7 @@ C_LABEL(cputypvallen) = C_LABEL(cputypvar) - C_LABEL(cputypval)
 C_LABEL(cputypvar):
        .asciz "compatability"
 
-/* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. --P3 */
+/* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */
        .align 4
 C_LABEL(cputypvar_sun4m):
        .asciz "compatible"
@@ -82,7 +82,7 @@ start:
 C_LABEL(trapbase):
 /* We get control passed to us here at t_zero. */
 t_zero:        b gokernel; nop; nop; nop;
-t_tflt:        TRAP_ENTRY(0x1, sparc_fault)        /* Inst. Access Exception        */
+t_tflt:        SPARC_TFAULT                        /* Inst. Access Exception        */
 t_bins:        TRAP_ENTRY(0x2, bad_instruction)    /* Illegal Instruction           */
 t_pins:        TRAP_ENTRY(0x3, priv_instruction)   /* Privileged Instruction        */
 t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler)   /* Floating Point Disabled       */
@@ -90,16 +90,16 @@ t_wovf:     WINDOW_SPILL                        /* Window Overflow               */
 t_wunf:        WINDOW_FILL                         /* Window Underflow              */
 t_mna: TRAP_ENTRY(0x7, mna_handler)        /* Memory Address Not Aligned    */
 t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler)   /* Floating Point Exception      */
-t_dflt:        TRAP_ENTRY(0x9, sparc_fault)        /* Data Miss Exception           */
+t_dflt:        SPARC_DFAULT                        /* Data Miss Exception           */
 t_tio: TRAP_ENTRY(0xa, do_tag_overflow)    /* Tagged Instruction Ovrflw     */
 t_wpt: TRAP_ENTRY(0xb, do_watchpoint)      /* Watchpoint Detected           */
 t_badc:        BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
-t_irq1:        TRAP_ENTRY_SOFTINT(1)               /* IRQ Software/SBUS Level 1     */
+t_irq1:        TRAP_ENTRY_INTERRUPT(1)             /* IRQ Software/SBUS Level 1     */
 t_irq2:        TRAP_ENTRY_INTERRUPT(2)             /* IRQ SBUS Level 2              */
 t_irq3:        TRAP_ENTRY_INTERRUPT(3)             /* IRQ SCSI/DMA/SBUS Level 3     */
-t_irq4:        TRAP_ENTRY_SOFTINT(4)               /* IRQ Software Level 4          */
+t_irq4:        TRAP_ENTRY_INTERRUPT(4)             /* IRQ Software Level 4          */
 t_irq5:        TRAP_ENTRY_INTERRUPT(5)             /* IRQ SBUS/Ethernet Level 5     */
-t_irq6:        TRAP_ENTRY_SOFTINT(6)               /* IRQ Software Level 6          */
+t_irq6:        TRAP_ENTRY_INTERRUPT(6)             /* IRQ Software Level 6          */
 t_irq7:        TRAP_ENTRY_INTERRUPT(7)             /* IRQ Video/SBUS Level 5        */
 t_irq8:        TRAP_ENTRY_INTERRUPT(8)             /* IRQ SBUS Level 6              */
 t_irq9:        TRAP_ENTRY_INTERRUPT(9)             /* IRQ SBUS Level 7              */
@@ -110,20 +110,20 @@ t_irq13:TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.               */
 t_irq14:TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
 t_nmi: NMI_TRAP                            /* Level 15 (NMI)                */
 t_racc:        TRAP_ENTRY(0x20, do_reg_access)     /* General Register Access Error */
-t_iacce:TRAP_ENTRY(0x21, sparc_fault)       /* Instr Access Error    */
+t_iacce:BAD_TRAP(0x21)                      /* Instr Access Error            */
 t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23)
 t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled)    /* Co-Processor Disabled         */
 t_uflsh:TRAP_ENTRY(0x25, do_bad_flush)      /* Unimplemented FLUSH inst.     */
 t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27)
 t_cpexc:TRAP_ENTRY(0x28, do_cp_exception)   /* Co-Processor Exception        */
-t_dacce:TRAP_ENTRY(0x29, sparc_fault)       /* Data Access Error     */
+t_dacce:BAD_TRAP(0x29)                      /* Data Access Error             */
 t_hwdz:        TRAP_ENTRY(0x2a, do_hw_divzero)     /* Division by zero, you lose... */
-t_dserr:TRAP_ENTRY(0x2b, sparc_fault)       /* Data Store Error      */
-t_daccm:TRAP_ENTRY(0x2c, sparc_fault)       /* Data Access MMU-Miss  */
+t_dserr:BAD_TRAP(0x2b)                      /* Data Store Error              */
+t_daccm:BAD_TRAP(0x2c)                      /* Data Access MMU-Miss          */
 t_bad2d:BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
 t_bad32:BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
 t_bad37:BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
-t_iaccm:TRAP_ENTRY(0x3c, sparc_fault)       /* Instr Access MMU-Miss */
+t_iaccm:BAD_TRAP(0x3c)                      /* Instr Access MMU-Miss         */
 t_bad3d:BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) BAD_TRAP(0x41)
 t_bad42:BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46)
 t_bad47:BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b)
@@ -186,16 +186,6 @@ C_LABEL(end_traptable):
 /* This was the only reasonable way I could think of to properly align
  * these page-table data structures.
  */
-
-       .globl C_LABEL(auxio_reg_addr)
-C_LABEL(auxio_reg_addr):       .skip   (PAGE_SIZE)
-
-       .globl C_LABEL(clock_reg_addr)
-C_LABEL(clock_reg_addr):       .skip   (PAGE_SIZE*5)
-
-       .globl C_LABEL(int_reg_addr)
-C_LABEL(int_reg_addr):         .skip   (PAGE_SIZE*5)
-
        .globl C_LABEL(bootup_user_stack)
        .globl C_LABEL(bootup_kernel_stack)
        .globl C_LABEL(pg0)
@@ -279,21 +269,6 @@ copy_prom_lvl14:
                ldd     [%g2 + 0x8], %g4
                std     %g4, [%g3 + 0x8]        ! Copy proms handler
 
-               /* Copy over the Prom/debugger's trap entry points. */
-copy_prom_bpoint:
-               or      %g0, (0xfe<<4), %g2
-               or      %g1, %g2, %g2
-               set     dbtrap, %g3
-               sub     %g3, %l6, %g3
-               ldd     [%g2], %g4
-               std     %g4, [%g3]
-               ldd     [%g2 + 0x8], %g4
-               std     %g4, [%g3 + 0x8]
-               ldd     [%g2 + 0x10], %g4
-               std     %g4, [%g3 + 0x10]
-               ldd     [%g2 + 0x18], %g4
-               std     %g4, [%g3 + 0x18]
-
 /* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT
  * MMU so we can remap ourselves properly.  DONT TOUCH %l0 thru %l5 in these
  * remapping routines, we need their values afterwards!
@@ -652,7 +627,7 @@ sun4c_continue_boot:
 
                /* I want a kernel stack NOW! */
                set     C_LABEL(bootup_user_stack), %g1
-               add     %g1, (PAGE_SIZE - STACKFRAME_SZ - TRACEREG_SZ), %sp
+               add     %g1, (PAGE_SIZE - REGWIN_SZ), %sp
                mov     0, %fp                  /* And for good luck */
 
                /* Zero out our BSS section. */
@@ -673,7 +648,7 @@ sun4c_continue_boot:
                st      %g4, [%g2]
 
                /* So now this should work. */
-               LOAD_CURRENT(g2)
+               LOAD_CURRENT(g2, g4)
                set     C_LABEL(bootup_kernel_stack), %g4
                st      %g4, [%g2 + TASK_KSTACK_PG]
                st      %g0, [%g2 + THREAD_UMASK]
index 697d8468123272ed4b268a7a26102731fae98e62..acd2459665774849bb701dc97d988f7cedc2e2f2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.12 1995/11/25 00:58:07 davem Exp $
+/* $Id: ioport.c,v 1.14 1996/01/03 03:34:41 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -54,20 +54,19 @@ void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
        unsigned long addr = (unsigned long) address;
        unsigned long offset = (addr & (~PAGE_MASK));
 
-       if (virtual){
+       if (virtual)
                vaddr = (unsigned long) virtual;
-       } else {
+       else
                vaddr = next_free_region;
-       }
                
        len += offset;
-       if (((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)){
-               printk ("alloc_io: Mapping ouside IOBASE area\n");
-               prom_halt ();
+       if(((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) {
+               prom_printf("alloc_io: Mapping ouside IOBASE area\n");
+               prom_halt();
        }
-       if (check_region ((vaddr | offset), len)){
-               printk ("alloc_io: 0x%lx is already in use\n", vaddr);
-               prom_halt ();
+       if(check_region ((vaddr | offset), len)) {
+               prom_printf("alloc_io: 0x%lx is already in use\n", vaddr);
+               prom_halt();
        }
 
        /* Tell Linux resource manager about the mapping */
@@ -75,10 +74,10 @@ void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
 
        base_address = vaddr;
        /* Do the actual mapping */
-       for (; len > 0; len -= PAGE_SIZE){
-               mapioaddr (addr, vaddr, bus_type, rdonly);
+       for (; len > 0; len -= PAGE_SIZE) {
+               mapioaddr(addr, vaddr, bus_type, rdonly);
                vaddr += PAGE_SIZE;
-               addr  += PAGE_SIZE;
+               addr += PAGE_SIZE;
                if (!virtual)
                        next_free_region += PAGE_SIZE;
        }
@@ -99,13 +98,13 @@ void *sparc_dvma_malloc (int len, char *name)
        unsigned long vaddr, base_address;
 
        vaddr = dvma_next_free;
-       if (check_region (vaddr, len)){
-               printk ("alloc_dma: 0x%lx is already in use\n", vaddr);
-               prom_halt ();
+       if(check_region (vaddr, len)) {
+               prom_printf("alloc_dma: 0x%lx is already in use\n", vaddr);
+               prom_halt();
        }
-       if (vaddr + len > (DVMA_VADDR + DVMA_LEN)){
-               printk ("alloc_dvma: out of dvma memory\n");
-               prom_halt ();
+       if(vaddr + len > (DVMA_VADDR + DVMA_LEN)) {
+               prom_printf("alloc_dvma: out of dvma memory\n");
+               prom_halt();
        }
 
        /* Basically these can be mapped just like any old
index 9fb9e32376beb462ea4869d37432ef389d66cdb3..ca59cad4764a076e0233d462366aff9c3172403e 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.29 1995/11/25 00:58:08 davem Exp $
+/*  $Id: irq.c,v 1.34 1996/02/20 07:45:04 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -34,8 +34,7 @@
 unsigned char *interrupt_enable = 0;
 struct sun4m_intregs *sun4m_interrupts;
 
-void
-sun4c_disable_irq(unsigned int irq_nr)
+void sun4c_disable_irq(unsigned int irq_nr)
 {
        unsigned long flags;
        unsigned char current_mask, new_mask;
@@ -60,21 +59,20 @@ sun4c_disable_irq(unsigned int irq_nr)
        default:
                restore_flags(flags);
                return;
-       };
-  
+       }
        *interrupt_enable = new_mask;
        restore_flags(flags);
 }
 
-void
-sun4m_disable_irq(unsigned int irq_nr)
+void sun4m_disable_irq(unsigned int irq_nr)
 {
+#if 0
        printk("IRQ routines not yet written for the sun4m\n");
        panic("disable_irq: Unsupported arch.");
+#endif
 }
 
-void
-disable_irq(unsigned int irq_nr)
+void disable_irq(unsigned int irq_nr)
 {
        switch(sparc_cpu_model) {
        case sun4c:
@@ -82,13 +80,13 @@ disable_irq(unsigned int irq_nr)
                break;
        case sun4m:
                sun4m_disable_irq(irq_nr);
+               break;
        default:
                panic("disable_irq: Unsupported arch.");
        }
 }
 
-void
-sun4c_enable_irq(unsigned int irq_nr)
+void sun4c_enable_irq(unsigned int irq_nr)
 {
        unsigned long flags;
        unsigned char current_mask, new_mask;
@@ -113,21 +111,20 @@ sun4c_enable_irq(unsigned int irq_nr)
        default:
                restore_flags(flags);
                return;
-       };
-
+       }
        *interrupt_enable = new_mask;
        restore_flags(flags);
 }
 
-void
-sun4m_enable_irq(unsigned int irq_nr)
+void sun4m_enable_irq(unsigned int irq_nr)
 {
+#if 0
        printk("IRQ routines not written for the sun4m yet.\n");
        panic("IRQ unsupported arch.");
+#endif
 }
 
-void
-enable_irq(unsigned int irq_nr)
+void enable_irq(unsigned int irq_nr)
 {
        switch(sparc_cpu_model) {
        case sun4c:
@@ -144,17 +141,30 @@ enable_irq(unsigned int irq_nr)
 /*
  * Initial irq handlers.
  */
-static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
-static struct irqaction cascade_irq = { NULL, 0, 0, NULL, NULL, NULL};
-static struct irqaction math_irq = { NULL, 0, 0, NULL, NULL, NULL};
+extern void timer_interrupt(int, void *, struct pt_regs *);
+extern void rs_interrupt(int, void *, struct pt_regs *);
+
+static struct irqaction timer_irq = {
+       timer_interrupt,
+       SA_INTERRUPT,
+       0, "timer",
+       NULL, NULL
+};
+
+static struct irqaction serial_irq = {
+       rs_interrupt,
+       SA_INTERRUPT,
+       0, "zilog serial",
+       NULL, NULL
+};
 
 static struct irqaction *irq_action[16] = {
          NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
-         NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
+         NULL, NULL, &timer_irq, NULL, &serial_irq, NULL , NULL, NULL
 };
 
-int
-get_irq_list(char *buf)
+
+int get_irq_list(char *buf)
 {
        int i, len = 0;
        struct irqaction * action;
@@ -177,8 +187,7 @@ get_irq_list(char *buf)
        return len;
 }
 
-void
-free_irq(unsigned int irq, void *dev_id)
+void free_irq(unsigned int irq, void *dev_id)
 {
        struct irqaction * action = *(irq + irq_action);
        struct irqaction * tmp = NULL;
@@ -193,35 +202,33 @@ free_irq(unsigned int irq, void *dev_id)
                return;
        }
        if (dev_id) {
-           for (; action; action = action->next) {
-               if (action->dev_id == dev_id) break;
-               tmp = action;
-           }
-           if (!action) {
-               printk("Trying to free free shared IRQ%d\n",irq);
-               return;
-           }
+               for (; action; action = action->next) {
+                       if (action->dev_id == dev_id) break;
+                       tmp = action;
+               }
+               if (!action) {
+                       printk("Trying to free free shared IRQ%d\n",irq);
+                       return;
+               }
        } else if (action->flags & SA_SHIRQ) {
-           printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
-           return;
+               printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
+               return;
        }
         save_flags(flags); cli();
-       if (action && tmp) {
-           tmp->next = action->next;
-       } else {
-           *(irq + irq_action) = action->next;
-       }
+       if (action && tmp)
+               tmp->next = action->next;
+       else
+               *(irq + irq_action) = action->next;
+
        kfree_s(action, sizeof(struct irqaction));
 
-       if (!(*(irq + irq_action))) {
-           disable_irq(irq);
-       }
+       if (!(*(irq + irq_action)))
+               disable_irq(irq);
 
         restore_flags(flags);
 }
 
-void
-unexpected_irq(int irq, struct pt_regs * regs)
+void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
 {
         int i;
        struct irqaction * action = *(irq + irq_action);
@@ -233,23 +240,22 @@ unexpected_irq(int irq, struct pt_regs * regs)
         for (i = 0; i < 16; i++)
                 if (action->handler)
                         prom_printf("[%s:%d:0x%x] ", action->name, (int) i,
-                              (unsigned int) action->handler);
+                                   (unsigned int) action->handler);
         printk("AIEEE\n");
        panic("bogus interrupt received");
 }
 
-void
-handler_irq(int irq, struct pt_regs * regs)
+void handler_irq(int irq, struct pt_regs * regs)
 {
        struct irqaction * action = *(irq + irq_action);
 
        kstat.interrupts[irq]++;
        while (action) {
-           if (!action->handler)
-               unexpected_irq(irq, action->dev_id, regs);
-           else
-               action->handler(irq, action->dev_id, regs);
-           action = action->next;
+               if (!action->handler)
+                       unexpected_irq(irq, action->dev_id, regs);
+               else
+                       action->handler(irq, action->dev_id, regs);
+               action = action->next;
        }
 }
 
@@ -260,17 +266,15 @@ handler_irq(int irq, struct pt_regs * regs)
  * IRQ's should use this format: notably the keyboard/timer
  * routines.
  */
-asmlinkage void
-do_IRQ(int irq, struct pt_regs * regs)
+asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
        struct irqaction * action = *(irq + irq_action);
 
        kstat.interrupts[irq]++;
        while (action) {
-           action->handler(irq, action->dev_id, regs);
-           action = action->next;
+               action->handler(irq, action->dev_id, regs);
+               action = action->next;
        }
-       return;
 }
 
 /*
@@ -278,37 +282,35 @@ do_IRQ(int irq, struct pt_regs * regs)
  * stuff - the handler is also running with interrupts disabled unless
  * it explicitly enables them later.
  */
-asmlinkage void
-do_fast_IRQ(int irq)
+asmlinkage void do_fast_IRQ(int irq)
 {
        kstat.interrupts[irq]++;
        printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
        return;
 }
 
-int
-request_fast_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
-                unsigned long irqflags, const char *devname, void *dev_id)
-)
+/* Fast IRQ's on the Sparc can only have one routine attached to them,
+ * thus no sharing possible.
+ */
+int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                    unsigned long irqflags, const char *devname)
 {
-       struct irqaction * action, *tmp = NULL;
+       struct irqaction *action;
        unsigned long flags;
 
        if(irq > 14)
                return -EINVAL;
-       if (!handler)
-           return -EINVAL;
+       if(!handler)
+               return -EINVAL;
        action = *(irq + irq_action);
-       if (action) {
-           if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
-               for (tmp = action; tmp->next; tmp = tmp->next);
-           } else {
+       if(action) {
+               if(action->flags & SA_SHIRQ)
+                       panic("Trying to register fast irq when already shared.\n");
+               if(irqflags & SA_SHIRQ)
+                       panic("Trying to register fast irq as shared.\n");
+
+               /* Anyway, someone already owns it so cannot be made fast. */
                return -EBUSY;
-           }
-           if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
-             printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
-             return -EBUSY;
-           }   
        }
 
        save_flags(flags); cli();
@@ -316,8 +318,8 @@ request_fast_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
        action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
 
        if (!action) { 
-           restore_flags(flags);
-           return -ENOMEM;
+               restore_flags(flags);
+               return -ENOMEM;
        }
 
        /* Dork with trap table if we get this far. */
@@ -332,23 +334,16 @@ request_fast_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
        action->flags = irqflags;
        action->mask = 0;
        action->name = devname;
-       action->dev_id = dev_id;
+       action->dev_id = NULL;
 
-       if (tmp) {
-           tmp->next = action;
-       } else {
-           *(irq + irq_action) = action;
-       }
+       *(irq + irq_action) = action;
 
        restore_flags(flags);
        return 0;
 }
 
-extern void probe_clock(void);
-               
-int
-request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
-           unsigned long irqflags, const char * devname, void *dev_id)
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+               unsigned long irqflags, const char * devname, void *dev_id)
 {
        struct irqaction * action, *tmp = NULL;
        unsigned long flags;
@@ -360,22 +355,23 @@ request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
            return -EINVAL;
        action = *(irq + irq_action);
        if (action) {
-           if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
-               for (tmp = action; tmp->next; tmp = tmp->next);
-           } else {
-               return -EBUSY;
-           }
-           if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
-             printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
-             return -EBUSY;
-           }   
+               if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
+                       for (tmp = action; tmp->next; tmp = tmp->next);
+               } else {
+                       return -EBUSY;
+               }
+               if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+                       printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
+                       return -EBUSY;
+               }   
        }
+
        save_flags(flags); cli();
        action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
 
        if (!action) { 
-           restore_flags(flags);
-           return -ENOMEM;
+               restore_flags(flags);
+               return -ENOMEM;
        }
 
        action->handler = handler;
@@ -385,14 +381,12 @@ request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
        action->next = NULL;
        action->dev_id = dev_id;
 
-       if (tmp) {
-           tmp->next = action;
-       } else {
-           *(irq + irq_action) = action;
-       }
+       if (tmp)
+               tmp->next = action;
+       else
+               *(irq + irq_action) = action;
+
        enable_irq(irq);
-       if(irq == 10)
-               probe_clock();
        restore_flags(flags);
        return 0;
 }
@@ -410,8 +404,7 @@ int probe_irq_off(unsigned long mask)
   return 0;
 }
 
-void
-sun4c_init_IRQ(void)
+void sun4c_init_IRQ(void)
 {
        struct linux_prom_registers int_regs[2];
        int ie_node;
@@ -422,19 +415,15 @@ sun4c_init_IRQ(void)
                panic("Cannot find /interrupt-enable node");
        /* Depending on the "address" property is bad news... */
        prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
-       sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
-                      int_regs[0].reg_size, "sun4c_interrupts",
-                      int_regs[0].which_io, 0x0);
-
-       interrupt_enable = (char *) INTREG_VADDR;
-
-       /* Default value, accept interrupts, but no one is actually active */
+       interrupt_enable = (char *) sparc_alloc_io(int_regs[0].phys_addr, 0,
+                                                  int_regs[0].reg_size,
+                                                  "sun4c_interrupts",
+                                                  int_regs[0].which_io, 0x0);
        *interrupt_enable = (SUN4C_INT_ENABLE);
-       sti(); /* Turn irq's on full-blast. */
+       sti();
 }
 
-void
-sun4m_init_IRQ(void)
+void sun4m_init_IRQ(void)
 {
        int ie_node;
 
@@ -442,7 +431,6 @@ sun4m_init_IRQ(void)
        int num_regs;
 
        cli();
-
        if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
           (ie_node = prom_getchild (ie_node)) == 0 ||
           (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0)
@@ -455,22 +443,18 @@ sun4m_init_IRQ(void)
        prom_apply_obio_ranges(int_regs, num_regs);
 
        /* Map the interrupt registers for all possible cpus. */
-       sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
-                      PAGE_SIZE*NCPUS, "interrupts_percpu",
-                      int_regs[0].which_io, 0x0);
+       sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0,
+                                         PAGE_SIZE*NCPUS, "interrupts_percpu",
+                                         int_regs[0].which_io, 0x0);
 
        /* Map the system interrupt control registers. */
-       sparc_alloc_io(int_regs[num_regs-1].phys_addr,
-                      (void *) INTREG_VADDR+(NCPUS*PAGE_SIZE),
+       sparc_alloc_io(int_regs[num_regs-1].phys_addr, 0,
                       int_regs[num_regs-1].reg_size, "interrupts_system",
                       int_regs[num_regs-1].which_io, 0x0);
-
-       sun4m_interrupts = (struct sun4m_intregs *) INTREG_VADDR;
        sti();
 }
 
-void
-init_IRQ(void)
+void init_IRQ(void)
 {
        switch(sparc_cpu_model) {
        case sun4c:
@@ -480,7 +464,7 @@ init_IRQ(void)
                sun4m_init_IRQ();
                break;
        default:
-               panic("Cannot initialize IRQ's on this Sun machine...");
+               prom_printf("Cannot initialize IRQ's on this Sun machine...");
                break;
-       };
+       }
 }
diff --git a/arch/sparc/kernel/ksyms.c b/arch/sparc/kernel/ksyms.c
new file mode 100644 (file)
index 0000000..ee30edf
--- /dev/null
@@ -0,0 +1,34 @@
+/* $Id: ksyms.c,v 1.1 1996/02/25 06:30:18 davem Exp $
+ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+/* We really haven't played around with modules at all in our
+ * port, but this is here as a starting point for when we do.
+ * One thing to note is that the way the symbols of the mul/div
+ * support routines are named is a mess, they all start with
+ * a '.' which makes it a bitch to export, we'll see.
+ */
+
+extern void bcopy (const char *src, char *dst, int len);
+extern void * memmove(void *,const void *,size_t);
+extern void * memcpy(void *,const void *,size_t);
+
+static struct symbol_table arch_symbol_table = {
+#include <linux/symtab_begin.h>
+       /* platform dependent support */
+       X(bcopy),
+       X(memmove),
+       X(memcpy),
+#include <linux/symtab_end.h>
+};
+
+void arch_syms_export(void)
+{
+       register_symtab(&arch_symbol_table);
+}
index 615c6d4f7dfe9e71da71a69dbd91310c0dfb0431..6abc9189fbaec49262ed80a227ad7688387c9502 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: probe.c,v 1.39 1995/11/26 00:54:37 davem Exp $
+/* $Id: probe.c,v 1.42 1995/12/26 01:38:08 davem Exp $
  * probe.c: Preliminary device tree probing routines...
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -187,9 +187,6 @@ probe_cpu(void)
                            fpu_vers);
                sparc_fpu_type[cpuid] = linux_sparc_fpu[31].fp_name;
        }
-
-       printk("cpu%d CPU: %s \n", cpuid, sparc_cpu_type[cpuid]);
-       printk("cpu%d FPU: %s \n", cpuid, sparc_fpu_type[cpuid]);
 }
 
 void
@@ -212,8 +209,9 @@ probe_vac(void)
                sun4c_vacinfo.log2lsize = 5;
                break;
        default:
-               printk("probe_vac: Didn't expect vac-linesize of %d, halting\n",
+               prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",
                            sun4c_vacinfo.linesize);
+               prom_halt();
        };
 
        propval = prom_getintdefault(prom_root_node, "vac_hwflush", -1);
@@ -222,49 +220,13 @@ probe_vac(void)
                                                         "vac-hwflush", 0) :
                                      propval);
 
-       printk("SUN4C: VAC size %d line size %d using %s flushes ",
-              sun4c_vacinfo.num_bytes, sun4c_vacinfo.linesize,
-              (sun4c_vacinfo.do_hwflushes ? "hardware" : "software"));
        if(sun4c_vacinfo.num_bytes != 65536) {
-               printk("WEIRD Sun4C VAC cache size, tell davem");
+               prom_printf("WEIRD Sun4C VAC cache size, tell davem");
                prom_halt();
        }
 
-       /* setup the low-level assembly routine ptrs */
-       if(sun4c_vacinfo.do_hwflushes) {
-               if(sun4c_vacinfo.linesize == 16) {
-                       sun4c_ctxflush = (unsigned long)sun4c_ctxflush_hw64KB16B;
-                       sun4c_segflush = (unsigned long)sun4c_segflush_hw64KB16B;
-                       sun4c_pgflush = (unsigned long)sun4c_pgflush_hw64KB16B;
-               } else if(sun4c_vacinfo.linesize == 32) {
-                       sun4c_ctxflush = (unsigned long)sun4c_ctxflush_hw64KB32B;
-                       sun4c_segflush = (unsigned long)sun4c_segflush_hw64KB32B;
-                       sun4c_pgflush = (unsigned long)sun4c_pgflush_hw64KB32B;
-               } else {
-                       printk("WEIRD Sun4C VAC cache line size, tell davem\n");
-                       prom_halt();
-               }
-       } else {
-               if(sun4c_vacinfo.linesize == 16) {
-                       sun4c_ctxflush = (unsigned long)sun4c_ctxflush_sw64KB16B;
-                       sun4c_segflush = (unsigned long)sun4c_segflush_sw64KB16B;
-                       sun4c_pgflush = (unsigned long)sun4c_pgflush_sw64KB16B;
-               } else if(sun4c_vacinfo.linesize == 32) {
-                       sun4c_ctxflush = (unsigned long)sun4c_ctxflush_sw64KB32B;
-                       sun4c_segflush = (unsigned long)sun4c_segflush_sw64KB32B;
-                       sun4c_pgflush = (unsigned long)sun4c_pgflush_sw64KB32B;
-               } else {
-                       printk("WEIRD Sun4C VAC cache line size, tell davem\n");
-                       prom_halt();
-               }
-       }
-
-
        sun4c_flush_all();
        sun4c_enable_vac();
-       printk("enabled\n");
-
-       return;
 }
 
 extern int num_segmaps, num_contexts;
@@ -284,9 +246,6 @@ probe_mmu(void)
                /* A sun4, sun4c or sun4e. */
                num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
                num_contexts = find_mmu_num_contexts(prom_root_node);
-
-               printk("cpu%d MMU segmaps: %d     MMU contexts: %d\n", cpuid,
-                           num_segmaps, num_contexts);
                break;
        default:
                printk("cpu%d probe_mmu: sparc_cpu_model botch\n", cpuid);
@@ -444,9 +403,6 @@ probe_auxio(void)
        /* Map the register both read and write */
        sparc_alloc_io(auxregs[0].phys_addr, (void *) AUXIO_VADDR,
                       auxregs[0].reg_size, "auxilliaryIO", auxregs[0].which_io, 0x0);
-       printk("Mapped AUXIO at paddr %08lx vaddr %08lx\n",
-                   (unsigned long) auxregs[0].phys_addr,
-                   (unsigned long) AUXIO_VADDR);
 }
 
 extern unsigned long probe_memory(void);
@@ -495,7 +451,9 @@ probe_devices(unsigned long mem_start)
        linux_num_cpus = cpu_ctr;
        for(i=0; i<cpu_ctr; i++) {
                prom_getstring(cpu_nds[i], "name", node_str, sizeof(node_str));
+#if 0
                printk("cpu%d: %s \n", i, node_str);
+#endif
        }
 
        probe_cpu();
index d6212c279bd03c672dc5f55be1c69c3cf49a4491..2fc6e1be9490ced22a3ea08ba0db7ade2e4c8a51 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.29 1995/11/25 00:58:17 davem Exp $
+/*  $Id: process.c,v 1.42 1996/02/20 07:45:08 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/delay.h>
 #include <asm/processor.h>
 #include <asm/psr.h>
 
-int current_user_segment = USER_DS; /* the return value from get_fs */
+extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
+
+int active_ds = USER_DS;
 
 /*
  * the idle loop on a Sparc... ;)
@@ -46,9 +49,15 @@ asmlinkage int sys_idle(void)
        }
 }
 
+extern char saved_command_line[];
+
 void hard_reset_now(void)
 {
-       prom_halt();
+       sti();
+       udelay(8000);
+       cli();
+       prom_feval("reset");
+       panic("Reboot failed!");
 }
 
 void show_regwindow(struct reg_window *rw)
@@ -84,9 +93,15 @@ void show_regs(struct pt_regs * regs)
  */
 void exit_thread(void)
 {
-       if(last_task_used_math == current)
+       flush_user_windows();
+       if(last_task_used_math == current) {
+               /* Keep process from leaving FPU in a bogon state. */
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+                      &current->tss.fpqueue[0], &current->tss.fpqdepth);
                last_task_used_math = NULL;
-       mmu_exit_hook(current);
+       }
+       mmu_exit_hook();
 }
 
 /*
@@ -94,29 +109,33 @@ void exit_thread(void)
  */
 void release_thread(struct task_struct *dead_task)
 {
-       mmu_release_hook(dead_task);
 }
 
 void flush_thread(void)
 {
        /* Make sure old user windows don't get in the way. */
-       mmu_flush_hook(current);
        flush_user_windows();
-       current->signal &= ~(1<<(SIGILL-1));
        current->tss.w_saved = 0;
        current->tss.uwinmask = 0;
-
        current->tss.sig_address = 0;
        current->tss.sig_desc = 0;
-
-       /* Signal stack state does not inherit. XXX Really? XXX */
        current->tss.sstk_info.cur_status = 0;
        current->tss.sstk_info.the_stack = 0;
 
+       if(last_task_used_math == current) {
+               /* Clean the fpu. */
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+                      &current->tss.fpqueue[0], &current->tss.fpqdepth);
+       }
+
        memset(&current->tss.reg_window[0], 0,
               (sizeof(struct reg_window) * NSWINS));
        memset(&current->tss.rwbuf_stkptrs[0], 0,
               (sizeof(unsigned long) * NSWINS));
+       mmu_flush_hook();
+       /* Now, this task is no longer a kernel thread. */
+       current->tss.flags &= ~SPARC_FLAG_KTHREAD;
 }
 
 /*
@@ -125,7 +144,12 @@ void flush_thread(void)
  * Parent -->  %o0 == childs  pid, %o1 == 0
  * Child  -->  %o0 == parents pid, %o1 == 1
  *
- * I'm feeling sick...
+ * NOTE: We have a seperate fork kpsr/kwim because
+ *       the parent could change these values between
+ *       sys_fork invocation and when we reach here
+ *       if the parent should sleep while trying to
+ *       allocate the task_struct and kernel stack in
+ *       do_fork().
  */
 extern void ret_sys_call(void);
 
@@ -133,34 +157,37 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
                 struct task_struct *p, struct pt_regs *regs)
 {
        struct pt_regs *childregs;
-       struct sparc_stackf *old_stack, *new_stack;
-       unsigned long stack_offset, kthread_usp = 0;
+       struct reg_window *old_stack, *new_stack;
+       unsigned long stack_offset;
 
-       mmu_task_cacheflush(current);
-       p->tss.context = -1;
+       if(last_task_used_math == current) {
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&p->tss.float_regs[0], &p->tss.fsr,
+                      &p->tss.fpqueue[0], &p->tss.fpqdepth);
+       }
 
        /* Calculate offset to stack_frame & pt_regs */
-       stack_offset = (PAGE_SIZE - TRACEREG_SZ);
+       stack_offset = ((PAGE_SIZE*2) - TRACEREG_SZ);
+       if(regs->psr & PSR_PS)
+               stack_offset -= REGWIN_SZ;
        childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
        *childregs = *regs;
-       new_stack = (((struct sparc_stackf *) childregs) - 1);
-       old_stack = (((struct sparc_stackf *) regs) - 1);
+       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;
+       p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack;
        p->tss.kpc = (((unsigned long) ret_sys_call) - 0x8);
+       p->tss.kpsr = current->tss.fork_kpsr;
+       p->tss.kwim = current->tss.fork_kwim;
+       p->tss.kregs = childregs;
+       childregs->u_regs[UREG_FP] = sp;
 
-       /* As a special case, if this is a kernel fork we need
-        * to give the child a new fresh stack for when it returns
-        * from the syscall. (ie. the "user" stack)  This happens
-        * only once and we count on the page acquisition happening
-        * successfully.
-        */
        if(regs->psr & PSR_PS) {
-                unsigned long n_stack = get_free_page(GFP_KERNEL);
-                childregs->u_regs[UREG_FP] = (n_stack | (sp & 0xfff));
-                memcpy((char *)n_stack,(char *)(sp & PAGE_MASK),PAGE_SIZE);
-                kthread_usp = n_stack;
-       }
+               stack_offset += TRACEREG_SZ;
+               childregs->u_regs[UREG_FP] = p->kernel_stack_page + stack_offset;
+               p->tss.flags |= SPARC_FLAG_KTHREAD;
+       } else
+               p->tss.flags &= ~SPARC_FLAG_KTHREAD;
 
        /* Set the return value for the child. */
        childregs->u_regs[UREG_I0] = current->pid;
@@ -168,8 +195,6 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
 
        /* Set the return value for the parent. */
        regs->u_regs[UREG_I1] = 0;
-
-       mmu_fork_hook(p, kthread_usp);
 }
 
 /*
@@ -177,6 +202,31 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
+       unsigned long first_stack_page;
+
+       dump->magic = SUNOS_CORE_MAGIC;
+       dump->len = sizeof(struct user);
+       dump->regs.psr = regs->psr;
+       dump->regs.pc = regs->pc;
+       dump->regs.npc = regs->npc;
+       dump->regs.y = regs->y;
+       /* fuck me plenty */
+       memcpy(&dump->regs.regs[0], &regs->u_regs[1], (sizeof(unsigned long) * 15));
+       dump->uexec = current->tss.core_exec;
+       dump->u_tsize = (((unsigned long) current->mm->end_code) -
+               ((unsigned long) current->mm->start_code)) & ~(PAGE_SIZE - 1);
+       dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1)));
+       dump->u_dsize -= dump->u_tsize;
+       dump->u_dsize &= ~(PAGE_SIZE - 1);
+       first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1));
+       dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1);
+       memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->tss.float_regs[0], (sizeof(unsigned long) * 32));
+       dump->fpu.fpstatus.fsr = current->tss.fsr;
+       dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0;
+       dump->fpu.fpstatus.fpq_count = current->tss.fpqdepth;
+       memcpy(&dump->fpu.fpstatus.fpq[0], &current->tss.fpqueue[0],
+              ((sizeof(unsigned long) * 2) * 16));
+       dump->sigcode = current->tss.sig_desc;
 }
 
 /*
@@ -198,7 +248,6 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
        char *filename;
 
        flush_user_windows();
-       mmu_task_cacheflush(current);
        error = getname((char *) regs->u_regs[UREG_I0], &filename);
        if(error)
                return error;
@@ -207,27 +256,3 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
        putname(filename);
        return error;
 }
-
-void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
-{
-       unsigned long saved_psr = (regs->psr & (PSR_CWP)) | PSR_S;
-
-       memset(regs, 0, sizeof(struct pt_regs));
-       regs->pc = ((pc & (~3)) - 4); /* whee borken a.out header fields... */
-       regs->npc = regs->pc + 4;
-       regs->psr = saved_psr;
-       regs->u_regs[UREG_G1] = sp; /* Base of arg/env stack area */
-
-       /* XXX More mysterious netbsd garbage... XXX */
-       regs->u_regs[UREG_G2] = regs->u_regs[UREG_G7] = regs->npc;
-
-       /* Allocate one reg window because the first jump into
-        * user mode will restore one register window by definition
-        * of the 'rett' instruction.  Also, SunOS crt.o code
-        * depends upon the arg/envp area being _exactly_ one
-        * register window above %sp when the process begins
-        * execution.
-        */
-       sp -= REGWIN_SZ;
-       regs->u_regs[UREG_FP] = sp;
-}
index d24ff4999726464640361220ed01dd4a9643d6cb..4a36852559de97aaf5546ac3cdcb00b0d1fdf461 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.11 1995/11/25 00:58:19 davem Exp $
+/* $Id: rtrap.S,v 1.21 1996/02/20 07:45:11 davem Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -45,16 +45,15 @@ rtrap_7win_patch5:  and     %g1, 0x7f, %g1
        .globl  ret_trap_entry, rtrap_patch1, rtrap_patch2
        .globl  rtrap_patch3, rtrap_patch4, rtrap_patch5
 ret_trap_entry:
-       ld      [%sp + STACKFRAME_SZ + PT_PSR], %t_psr
+       ld      [%sp + REGWIN_SZ + PT_PSR], %t_psr
        andcc   %t_psr, PSR_PS, %g0
        bne     ret_trap_kernel
         nop
 
        sethi   %hi(C_LABEL(need_resched)), %twin_tmp1
        ld      [%twin_tmp1 + %lo(C_LABEL(need_resched))], %twin_tmp2
-       LOAD_CURRENT(twin_tmp1)
 
-       cmp     %twin_tmp2, 0x0
+       cmp     %twin_tmp2, 0
        be      signal_p
         nop
 
@@ -70,41 +69,51 @@ ret_trap_entry:
 
 signal_p:
        /* No signals for swapper. */
-       sethi   %hi(C_LABEL(init_task)), %twin_tmp3
-       or      %twin_tmp3, %lo(C_LABEL(init_task)), %twin_tmp3
+       LOAD_CURRENT(twin_tmp1, twin_tmp3)
+       set     C_LABEL(init_task), %twin_tmp3
        cmp     %twin_tmp3, %twin_tmp1
        be      ret_trap_continue
         nop
 
        ld      [%twin_tmp1 + TASK_SIGNAL], %twin_tmp2
-       ld      [%twin_tmp1 + TASK_BLOCKED], %twin_tmp3
-       andncc  %twin_tmp2, %twin_tmp3, %twin_tmp2
+       ld      [%twin_tmp1 + TASK_BLOCKED], %o0
+       andncc  %twin_tmp2, %o0, %g0
        be      ret_trap_continue
         nop
 
-       mov     %twin_tmp2, %o0         ! oldmask
-       add     %sp, STACKFRAME_SZ, %o1 ! pt_regs ptr
        call    C_LABEL(do_signal)
-        nop
+        add    %sp, REGWIN_SZ, %o1     ! pt_regs ptr
 
        /* Fall through... */
 ret_trap_continue:
+       ld      [%sp + REGWIN_SZ + PT_PSR], %t_psr
        wr      %t_psr, 0x0, %psr
        WRITE_PAUSE
 
-       LOAD_CURRENT(twin_tmp2)
+       /* If not current fpu proc, disable fp-ops */
+       LOAD_CURRENT(twin_tmp2, twin_tmp1)
+       set     C_LABEL(last_task_used_math), %twin_tmp1
+       ld      [%twin_tmp1], %twin_tmp1
+       cmp     %twin_tmp2, %twin_tmp1
+       be      1f
+        nop
+
+       set     PSR_EF, %twin_tmp1
+       andn    %t_psr, %twin_tmp1, %t_psr
+       st      %t_psr, [%sp + REGWIN_SZ + PT_PSR]
+
+1:
        ld      [%twin_tmp2 + THREAD_W_SAVED], %twin_tmp1
        orcc    %g0, %twin_tmp1, %g0
        be      ret_trap_nobufwins
         nop
 
-       wr      %t_psr, 0x0, %psr
        wr      %t_psr, PSR_ET, %psr
        WRITE_PAUSE
 
        mov     1, %o1
-       call    C_LABEL(do_sparc_winfault)
-        add    %sp, STACKFRAME_SZ, %o0
+       call    C_LABEL(try_to_clear_window_buffer)
+        add    %sp, REGWIN_SZ, %o0
 
        b       ret_trap_entry
         nop
@@ -126,6 +135,7 @@ ret_trap_nobufwins:
                /* Calculate new %wim, we have to pull a register
                 * window from the users stack.
                 */
+ret_trap_pull_one_window:
                rd      %wim, %t_wim
                sll     %t_wim, 0x1, %twin_tmp1
 rtrap_patch1:  srl     %t_wim, 0x7, %twin_tmp2
@@ -159,23 +169,36 @@ ret_trap_userwins_ok:
        jmp     %t_pc
        rett    %t_npc
        
+       /* HyperSparc special nop patching, if we are on a hypersparc
+        * we nop the top two instructions and the first nop coming
+        * up to be:
+        * rd   %iccr, %g0  <-- flush on-chip instruction cache
+        * jmp  %t_pc
+        * rett %t_npc
+        */
+       nop
+       nop
+
 ret_trap_unaligned_pc:
-       add     %sp, STACKFRAME_SZ, %o0
-       ld      [%sp + STACKFRAME_SZ + PT_PC], %o1
-       ld      [%sp + STACKFRAME_SZ + PT_NPC], %o2
-       ld      [%sp + STACKFRAME_SZ + PT_PSR], %o3
+       add     %sp, REGWIN_SZ, %o0
+       ld      [%sp + REGWIN_SZ + PT_PC], %o1
+       ld      [%sp + REGWIN_SZ + PT_NPC], %o2
+       ld      [%sp + REGWIN_SZ + PT_PSR], %o3
+
+       wr      %t_wim, 0x0, %wim               ! or else...
+       WRITE_PAUSE
 
-       wr      %t_psr, 0x0, %psr
        wr      %t_psr, PSR_ET, %psr
        WRITE_PAUSE
 
        call    C_LABEL(do_memaccess_unaligned)
         nop
 
-       b       ret_trap_entry
+       b       ret_trap_entry                  ! maybe signal posted
         nop
 
 ret_trap_kernel:
+       ld      [%sp + REGWIN_SZ + PT_PSR], %t_psr
        wr      %t_psr, 0x0, %psr
        WRITE_PAUSE
 
@@ -218,15 +241,12 @@ ret_trap_user_stack_is_bolixed:
        wr      %t_wim, 0x0, %wim
        WRITE_PAUSE
 
-       wr      %t_psr, 0x0, %psr
        wr      %t_psr, PSR_ET, %psr
        WRITE_PAUSE
 
-       mov     0, %o1
-       call    C_LABEL(do_sparc_winfault)
-        add    %sp, STACKFRAME_SZ, %o0
+       call    C_LABEL(window_ret_fault)
+        add    %sp, REGWIN_SZ, %o0
 
-       /* Try it all again. */
        b       ret_trap_entry
         nop
 
@@ -297,7 +317,7 @@ sun4c_rett_onepage:
        b       ret_trap_userwins_ok
         nop
 
-       .globl  C_LABEL(sun4c_rett_stackchk)
+       .globl  C_LABEL(srmmu_rett_stackchk)
 C_LABEL(srmmu_rett_stackchk):
        bne     ret_trap_user_stack_is_bolixed
         sethi  %hi(KERNBASE), %g1
diff --git a/arch/sparc/kernel/sclow.S b/arch/sparc/kernel/sclow.S
new file mode 100644 (file)
index 0000000..91e3e11
--- /dev/null
@@ -0,0 +1,191 @@
+/* sclow.S: Low level special syscall handling.
+ *          Basically these are cases where we can completly
+ *          handle the system call without saving any state
+ *          because we know that the process will not sleep.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/cprefix.h>
+#include <asm/ptrace.h>
+#include <asm/errno.h>
+#include <asm/winmacro.h>
+#include <asm/psr.h>
+
+#define CC_AND_RETT  \
+       set     PSR_C, %l4; \
+       andn    %l0, %l4, %l4; \
+       wr      %l4, 0x0, %psr; \
+       nop; nop; nop; \
+       jmp     %l2; \
+       rett    %l2 + 4;
+
+#define SC_AND_RETT  \
+       set     PSR_C, %l4; \
+       or      %l0, %l4, %l4; \
+       wr      %l4, 0x0, %psr; \
+       nop; nop; nop; \
+       jmp     %l2; \
+       rett    %l2 + 4;
+
+#define LABEL(func)  CONCAT(func, _low)
+
+       .globl  LABEL(sunosnop)
+LABEL(sunosnop):
+       CC_AND_RETT
+
+       .globl  LABEL(sunosgetpid)
+LABEL(sunosgetpid):
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + 108], %i0
+       ld      [%l4 + 256], %l5
+       ld      [%l5 + 108], %i1
+       CC_AND_RETT
+
+       .globl  LABEL(sunosgetuid)
+LABEL(sunosgetuid):
+       LOAD_CURRENT(l4, l5)
+       lduh    [%l4 + 280], %i0
+       lduh    [%l4 + 282], %i1
+       CC_AND_RETT
+
+       .globl  LABEL(sunosgetgid)
+LABEL(sunosgetgid):
+       LOAD_CURRENT(l4, l5)
+       lduh    [%l4 + 288], %i0
+       lduh    [%l4 + 290], %i1
+       CC_AND_RETT
+
+       .globl  LABEL(sunosmctl)
+LABEL(sunosmctl):
+       mov     0, %i0
+       CC_AND_RETT
+
+       .globl  LABEL(sunosgdtsize)
+LABEL(sunosgdtsize):   
+       mov     256, %i0
+       CC_AND_RETT
+
+       .globl  LABEL(sunossblock)
+LABEL(sunossblock):
+       LOAD_CURRENT(l4, l5)
+       set     -65793, %l5
+       and     %i0, %l5, %l5
+       ld      [%l4 + TASK_BLOCKED], %i0
+       or      %i0, %l5, %l5
+       st      %l5, [%l4 + TASK_BLOCKED]
+       CC_AND_RETT
+
+       .globl  LABEL(sunossmask)
+LABEL(sunossmask):
+       LOAD_CURRENT(l4, l5)
+       set     -65793, %l5
+       and     %i0, %l5, %l5
+       ld      [%l4 + TASK_BLOCKED], %i0
+       st      %l5, [%l4 + TASK_BLOCKED]
+       CC_AND_RETT
+
+       .globl  LABEL(getpagesize)
+LABEL(getpagesize):
+       set     4096, %i0
+       CC_AND_RETT
+
+       .globl  LABEL(umask)
+LABEL(umask):
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + 1560], %l5
+       and     %i0, 511, %l4
+       lduh    [%l5 + 4], %i0
+       sth     %l4, [%l5 + 4]
+       CC_AND_RETT
+
+       .globl  LABEL(write)
+LABEL(write):
+       cmp     %i0, 255                /* fd >= NR_OPEN */
+       bgu,a   write_error_return
+        mov    EBADF, %i0
+
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + 1564], %l5
+       sll     %i0, 2, %l6
+       add     %l5, %l6, %l5
+       ld      [%l5 + 36], %l6
+       cmp     %l6, 0                  /* !(file=current->files->fd[fd]) */
+       be,a    write_error_return
+        mov    EBADF, %i0      
+
+       ld      [%l6 + 36], %l5
+       cmp     %l5, 0                  /* !(inode=file->f_inode) */
+       be,a    write_error_return
+        mov    EBADF, %i0
+
+       lduh    [%l6], %l5              /* !(file->f_mode & 2) */
+       andcc   %l5, 2, %g0
+       be,a    write_error_return
+        mov    EBADF, %i0
+
+       ld      [%l6 + 40], %l5
+       cmp     %l5, 0                  /* !file->f_op */
+       be,a    write_error_return
+        mov    EINVAL, %i0
+
+       ld      [%l5 + 8], %l5          /* !file->f_op->write */
+       cmp     %l5, 0
+       be,a    write_error_return
+        mov    EINVAL, %i0
+
+       cmp     %i2, 0                  /* count == 0 */
+       bne     1f
+        nop
+
+       mov     0, %i0
+       CC_AND_RETT
+
+1:
+       /* See if we can do the optimization... */
+       ld      [%l6 + 36], %l5
+       lduh    [%l5 + 16], %l5
+       srl     %l5, 8, %l6
+       cmp     %l6, 1                  /* MEM_MAJOR */
+       bne,a   write_is_too_hard
+        sethi  %hi(C_LABEL(quick_sys_write)), %l7
+
+       and     %l5, 0xff, %l5
+       cmp     %l5, 3                  /* NULL_MINOR */
+       bne,a   write_is_too_hard
+        sethi  %hi(C_LABEL(quick_sys_write)), %l7
+
+       /* We only optimize for the /dev/null case currently,
+        * however to stay POSIX4 compliant we must check the
+        * validity of the passed buffer.  Blowlaris2.x does not
+        * do this and is therefore not POSIX4 compliant!
+        * If you are going to optimize for benchmarks, fine,
+        * but to break behavior of a system call in the process
+        * is complete brain damage...
+        */
+
+       /* XXX write verify_area thingy for full POSIX conformance! XXX */
+
+       mov     %i2, %i0
+       CC_AND_RETT
+
+write_is_too_hard:
+       b       syscall_is_too_hard
+        or     %l7, %lo(C_LABEL(quick_sys_write)), %l7
+
+write_error_return:
+       SC_AND_RETT
+
+       /* XXX sys_nice() XXX */
+       /* XXX sys_setpriority() XXX */
+       /* XXX sys_getpriority() XXX */
+       /* XXX sys_setregid() XXX */
+       /* XXX sys_setgid() XXX */
+       /* XXX sys_setreuid() XXX */
+       /* XXX sys_setuid() XXX */
+       /* XXX sys_setfsuid() XXX */
+       /* XXX sys_setfsgid() XXX */
+       /* XXX sys_setpgid() XXX */
+       /* XXX sys_getpgid() XXX */
+       /* XXX sys_setsid() XXX */
+       /* XXX sys_getsid() XXX */
index 1947ea91ce6e4a4f09b16a87dd299257bb936866..20a261d87e4d99898937c85887578a898a0ada98 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.41 1995/11/25 00:58:21 davem Exp $
+/*  $Id: setup.c,v 1.54 1996/02/25 06:49:18 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -28,6 +33,7 @@
 #include <asm/traps.h>
 #include <asm/vaddrs.h>
 #include <asm/kdebug.h>
+#include <asm/mbus.h>
 
 struct screen_info screen_info = {
        0, 0,                   /* orig-x, orig-y */
@@ -42,6 +48,7 @@ struct screen_info screen_info = {
 };
 
 char wp_works_ok = 0;
+unsigned int phys_bytes_of_ram, end_of_phys_memory;
 
 unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
 {
@@ -55,6 +62,9 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
  */
 
 extern unsigned long trapbase;
+extern void breakpoint(void);
+extern void console_restore_palette(void);
+asmlinkage void sys_sync(void);        /* it's really int */
 
 /* Pretty sick eh? */
 void prom_sync_me(void)
@@ -68,8 +78,14 @@ void prom_sync_me(void)
                             "nop\n\t"
                             "nop\n\t" : : "r" (&trapbase));
 
+        console_restore_palette ();
        prom_printf("PROM SYNC COMMAND...\n");
        show_free_areas();
+       if(current != task[0]) {
+               sti();
+               sys_sync();
+               cli();
+       }
        prom_printf("Returning to prom\n");
 
        __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
@@ -145,23 +161,30 @@ boot_flags_init(char *commands)
 
 extern void load_mmu(void);
 extern int prom_probe_memory(void);
-extern void probe_vac(void);
+extern void sun4c_probe_vac(void);
 extern void get_idprom(void);
-extern unsigned int end_of_phys_memory;
 extern char cputypval;
-extern unsigned long start, end, bootup_stack, bootup_kstack;
-
+extern unsigned long start, end;
+extern void panic_setup(char *, int *);
 
-char sparc_command_line[256];  /* Should be enough */
 char saved_command_line[256];
 enum sparc_cpu sparc_cpu_model;
 
 struct tt_entry *sparc_ttable;
 
+static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
+
 void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
-       int total, i;
+       int total, i, panic_stuff[2];
+
+       /* Always reboot on panic, but give 5 seconds to hit L1-A
+        * and look at debugging info if desired.
+        */
+       panic_stuff[0] = 1;
+       panic_stuff[1] = 5;
+       panic_setup(0, panic_stuff);
 
        sparc_ttable = (struct tt_entry *) &start;
 
@@ -181,7 +204,7 @@ void setup_arch(char **cmdline_p,
          {
          case sun4c:
                  printk("SUN4C\n");
-                 probe_vac();
+                 sun4c_probe_vac();
                  break;
           case sun4m:
                  printk("SUN4M\n");
@@ -215,8 +238,10 @@ void setup_arch(char **cmdline_p,
        load_mmu();
        total = prom_probe_memory();
        *memory_start_p = (((unsigned long) &end));
-       printk("Physical Memory: %d bytes (in hex %08lx)\n", (int) total,
+#if 0
+       prom_printf("Physical Memory: %d bytes (in hex %08lx)\n", (int) total,
                    (unsigned long) total);
+#endif
 
        for(i=0; sp_banks[i].num_bytes != 0; i++) {
 #if 0
@@ -229,10 +254,15 @@ void setup_arch(char **cmdline_p,
 
        prom_setsync(prom_sync_me);
 
+       *memory_end_p = (end_of_phys_memory + PAGE_OFFSET);
+       if(*memory_end_p > IOBASE_VADDR)
+               *memory_end_p = IOBASE_VADDR;
+
        /* Due to stack alignment restrictions and assumptions... */
        init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
-
-       *memory_end_p = (end_of_phys_memory + PAGE_OFFSET);
+       init_task.mm->mmap->vm_start = KERNBASE;
+       init_task.mm->mmap->vm_end = *memory_end_p;
+       init_task.tss.kregs = &fake_swapper_regs;
 
        {
                extern int serial_console;  /* in console.c, of course */
@@ -250,6 +280,15 @@ void setup_arch(char **cmdline_p,
                        prom_halt();
                }
        }
+#if 1
+       /* XXX ROOT_DEV hack for kgdb - davem XXX */
+#if 1
+       ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255); /* NFS */
+#else
+       ROOT_DEV = 0x801; /* SCSI DISK */
+#endif
+
+#endif
 }
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
@@ -257,12 +296,35 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
        return -EIO;
 }
 
-/*
- * BUFFER is PAGE_SIZE bytes long.
- *
- * XXX Need to do better than this! XXX
- */
+/* BUFFER is PAGE_SIZE bytes long. */
+
+extern char *sparc_cpu_type[];
+extern char *sparc_fpu_type[];
+
 int get_cpuinfo(char *buffer)
 {
-       return sprintf(buffer, "Sparc RISC\n");
+       int cpuid=get_cpuid();
+
+       return sprintf(buffer, "cpu\t\t: %s\n"
+            "fpu\t\t: %s\n"
+            "promlib\t\t: Version %d Revision %d\n"
+            "wp\t\t: %s\n"
+            "type\t\t: %s\n"
+            "Elf Support\t: %s\n"   /* I can't remember when I do --ralp */
+            "BogoMips\t: %lu.%02lu\n"
+           "%s",
+            sparc_cpu_type[cpuid],
+            sparc_fpu_type[cpuid],
+            romvec->pv_romvers, prom_rev,
+            wp_works_ok ? "yes" : "no",
+            &cputypval,
+#if CONFIG_BINFMT_ELF
+            "yes",
+#else
+            "no",
+#endif
+            loops_per_sec/500000, (loops_per_sec/5000) % 100,
+           mmu_info()
+            );
+
 }
index b3dd4fef568d6e3a03982b9760547b39bf81e4df..cadecff926167e73c241b908cc7108d2a99ef61b 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.20 1995/11/26 02:29:09 davem Exp $
+/*  $Id: signal.c,v 1.28 1995/12/29 21:47:18 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -28,81 +28,76 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
  * atomically swap in the new signal mask, and wait for a signal.
  * This is really tricky on the Sparc, watch out...
  */
-asmlinkage inline int _sigpause_common(unsigned int set, struct pt_regs *regs)
+asmlinkage inline void _sigpause_common(unsigned int set, struct pt_regs *regs)
 {
        unsigned long mask;
 
        mask = current->blocked;
        current->blocked = set & _BLOCKABLE;
+
        /* Advance over the syscall instruction for when
         * we return.  We want setup_frame to save the proper
-        * state, but then below we set ourselves backwards
-        * to compensate for what ret_sys_call does. Ick!
+        * state, including the error return number & condition
+        * codes.
         */
-       regs->pc += 4;
+       regs->pc = regs->npc;
        regs->npc += 4;
+       regs->psr |= PSR_C;
+       regs->u_regs[UREG_I0] = EINTR;
 
        while (1) {
                current->state = TASK_INTERRUPTIBLE;
                schedule();
-               if (do_signal(mask, regs)) {
-                       /* If we actually post the signal then we
-                        * will get our PCs advanced in entry.S, to
-                        * compensate we throw the PCs back one insn.
-                        */
-                       regs->pc -= 4;
-                       regs->npc -= 4;
-                       return -EINTR;
-               }
+               if (do_signal(mask, regs))
+                       return;
        }
 }
 
-asmlinkage int sys_sigpause(unsigned int set)
+asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
 {
-       struct pt_regs *regs;
-       unsigned long fp;
-
-       __asm__ __volatile__("mov %%fp, %0\n\t" :
-                            "=r" (fp));
-       regs = ((struct pt_regs *) (fp + STACKFRAME_SZ));
-       return _sigpause_common(set, regs);
+       _sigpause_common(set, regs);
 }
 
-asmlinkage int sys_sigsuspend(unsigned int *sigmaskp)
+asmlinkage void do_sigsuspend(unsigned int *sigmaskp, struct pt_regs *regs)
 {
-       struct pt_regs *regs;
-       unsigned long fp;
        unsigned int set;
 
-       __asm__ __volatile__("mov %%fp, %0\n\t" :
-                            "=r" (fp));
-       regs = ((struct pt_regs *) (fp + STACKFRAME_SZ));
-       if(verify_area(VERIFY_READ, sigmaskp, sizeof(unsigned int)))
-               return -EFAULT;
+       /* Manual does not state what is supposed to happen if
+        * the sigmask ptr is bogus.  It does state that EINTR
+        * is the only valid return value and it indicates
+        * successful signal delivery.  Must investigate.
+        */
+       if(verify_area(VERIFY_READ, sigmaskp, sizeof(unsigned int))) {
+               regs->pc = regs->npc;
+               regs->npc += 4;
+               regs->u_regs[UREG_I0] = EFAULT;
+               regs->psr |= PSR_C;
+               return;
+       }
        set = *sigmaskp;
-       return _sigpause_common(set, regs);
+       _sigpause_common(set, regs);
 }
 
-extern unsigned long nwindows;
-
 asmlinkage void do_sigreturn(struct pt_regs *regs)
 {
        struct sigcontext_struct *scptr =
                (struct sigcontext_struct *) regs->u_regs[UREG_I0];
 
-       /* Make the stack consistant. */
-       flush_user_windows();
+       synchronize_user_stack();
 
        /* Check sanity of the user arg. */
        if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext_struct)) ||
-          ((((unsigned long) scptr)) & 0x3))
+          ((((unsigned long) scptr)) & 0x3)) {
+               printk("%s [%d]: do_sigreturn, scptr is invalid at pc<%08lx> scptr<%p>\n",
+                      current->comm, current->pid, regs->pc, scptr);
                do_exit(SIGSEGV);
+       }
 
        if((scptr->sigc_pc | scptr->sigc_npc) & 3)
                return; /* Nice try. */
 
        current->blocked = scptr->sigc_mask & _BLOCKABLE;
-       current->tss.sstk_info.cur_status = (scptr->sigc_onstack & 0x1);
+       current->tss.sstk_info.cur_status = (scptr->sigc_onstack & 1);
        regs->pc = scptr->sigc_pc;
        regs->npc = scptr->sigc_npc;
        regs->u_regs[UREG_FP] = scptr->sigc_sp;
@@ -114,38 +109,6 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
        regs->psr |= (scptr->sigc_psr & PSR_ICC);
 }
 
-/* I love register windows...
- * Basically, this tries to get as many of the current user
- * windows on the stack as possible, even if unaligned.  Failing
- * that the windows end up in the per-task window save buffer
- * in the thread struct, these will be copied onto the signal
- * stack for possible inspection by the process.
- */
-static inline void
-do_magic_sparc_stuff(void)
-{
-       unsigned long sp;
-       int this_win;
-
-       flush_user_windows();
-       this_win = (current->tss.w_saved - 1);
-       while(this_win >= 0) {
-               sp = current->tss.rwbuf_stkptrs[this_win];
-               if(!(sp & 7) && !verify_area(VERIFY_WRITE, (char *)sp,
-                                            sizeof(struct reg_window))) {
-                       memcpy((char *)sp,
-                              (char *)&current->tss.reg_window[this_win],
-                              sizeof(struct reg_window));
-                       current->tss.w_saved--;
-                       memcpy((char *)&current->tss.reg_window[this_win],
-                              (char *)&current->tss.reg_window[this_win+1],
-                              (sizeof(struct reg_window) *
-                              (current->tss.w_saved-this_win)));
-               }
-               this_win -= 1;
-       }
-}
-
 /*
  * Set up a signal frame... Make the stack look the way SunOS
  * expects it to look which is basically:
@@ -172,25 +135,27 @@ struct signal_sframe {
 
 static inline void
 setup_frame(struct sigaction *sa, struct sigcontext_struct **fp,
-           unsigned long pc, struct pt_regs *regs, int signr,
-           unsigned long oldmask)
+           unsigned long pc, unsigned long npc, struct pt_regs *regs,
+           int signr, unsigned long oldmask)
 {
        struct signal_sframe *sframep;
        struct sigcontext_struct *sc;
        int window = 0;
        int old_status = current->tss.sstk_info.cur_status;
 
+       synchronize_user_stack();
        sframep = (struct signal_sframe *) *fp;
        sframep = (struct signal_sframe *) (((unsigned long) sframep)-SF_ALIGNEDSZ);
        sc = &sframep->sig_context;
        if(verify_area(VERIFY_WRITE, sframep, sizeof(*sframep)) ||
           (((unsigned long) sframep) & 7) ||
-          (((unsigned long) sframep) >= KERNBASE)) {
+          (((unsigned long) sframep) >= KERNBASE) ||
+          ((sparc_cpu_model == sun4 || sparc_cpu_model == sun4c) &&
+           ((unsigned long) sframep < 0xe0000000 && (unsigned long) sframep >= 0x20000000))) {
                printk("%s [%d]: User has trashed signal stack\n",
                       current->comm, current->pid);
                printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n",
                       sframep, pc, signr);
-               show_regs(regs);
                /* Don't change signal code and address, so that
                 * post mortem debuggers can have a look.
                 */
@@ -200,13 +165,12 @@ setup_frame(struct sigaction *sa, struct sigcontext_struct **fp,
                return;
        }
        *fp = (struct sigcontext_struct *) sframep;
-       do_magic_sparc_stuff();
 
        sc->sigc_onstack = old_status;
        sc->sigc_mask = oldmask;
        sc->sigc_sp = regs->u_regs[UREG_FP];
-       sc->sigc_pc = regs->pc;
-       sc->sigc_npc = regs->npc;
+       sc->sigc_pc = pc;
+       sc->sigc_npc = npc;
        sc->sigc_psr = regs->psr;
        sc->sigc_g1 = regs->u_regs[UREG_G1];
        sc->sigc_o0 = regs->u_regs[UREG_I0];
@@ -220,12 +184,6 @@ setup_frame(struct sigaction *sa, struct sigcontext_struct **fp,
                               sizeof(struct reg_window));
                }
        else
-               /* This is so that gdb and friends can trace back
-                * through the stack properly.  An alternative
-                * is to set the fp in this new window to the
-                * sp of the frame at the time of the signal and
-                * I see some problems with that maneuver.
-                */
                memcpy(sframep, (char *)regs->u_regs[UREG_FP],
                       sizeof(struct reg_window));
 
@@ -243,6 +201,7 @@ setup_frame(struct sigaction *sa, struct sigcontext_struct **fp,
                sframep->sig_address = 0;
        }
        sframep->sig_scptr = sc;
+       regs->u_regs[UREG_FP] = (unsigned long) *fp;
 }
 
 /*
@@ -261,6 +220,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
        unsigned long handler_signal = 0;
        struct sigcontext_struct *frame = NULL;
        unsigned long pc = 0;
+       unsigned long npc = 0;
        unsigned long signr;
        struct sigaction *sa;
 
@@ -269,22 +229,6 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                clear_bit(signr, &current->signal);
                sa = current->sig->action + signr;
                signr++;
-               if((current->flags & PF_PTRACED) && signr != SIGKILL) {
-                       current->exit_code = signr;
-                       current->state = TASK_STOPPED;
-                       notify_parent(current);
-                       schedule();
-                       if(!(signr = current->exit_code))
-                               continue;
-                       current->exit_code = 0;
-                       if(signr == SIGSTOP)
-                               continue;
-                       if(_S(signr) & current->blocked) {
-                               current->signal |= _S(signr);
-                               continue;
-                       }
-                       sa = current->sig->action + signr - 1;
-               }
                if(sa->sa_handler == SIG_IGN) {
                        if(signr != SIGCHLD)
                                continue;
@@ -299,8 +243,6 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                                continue;
 
                        case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
-                               if(current->flags & PF_PTRACED)
-                                       continue;
                                current->state = TASK_STOPPED;
                                current->exit_code = signr;
                                if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
@@ -322,12 +264,27 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                        }
                }
                /* OK, we're invoking a handler. */
+               if(regs->psr & PSR_C) {
+                       if(regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+                          (regs->u_regs[UREG_I0] == ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
+                               regs->u_regs[UREG_I0] = EINTR;
+               }
                handler_signal |= 1 << (signr - 1);
                mask &= ~sa->sa_mask;
        }
+       if((regs->psr & PSR_C) &&
+          (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+           regs->u_regs[UREG_I0] == ERESTARTSYS ||
+           regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+               /* replay the system call when we are done */
+               regs->u_regs[UREG_I0] = regs->u_regs[UREG_G0];
+               regs->pc -= 4;
+               regs->npc -= 4;
+       }
        if(!handler_signal)
                return 0;
        pc = regs->pc;
+       npc = regs->npc;
        frame = (struct sigcontext_struct *) regs->u_regs[UREG_FP];
        signr = 1;
        sa = current->sig->action;
@@ -336,15 +293,16 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                        break;
                if(!(mask & handler_signal))
                        continue;
-               setup_frame(sa, &frame, pc, regs, signr, oldmask);
+               setup_frame(sa, &frame, pc, npc, regs, signr, oldmask);
                pc = (unsigned long) sa->sa_handler;
+               npc = pc + 4;
                if(sa->sa_flags & SA_ONESHOT)
                        sa->sa_handler = NULL;
                current->blocked |= sa->sa_mask;
                oldmask |= sa->sa_mask;
        }
-       regs->u_regs[UREG_FP] = (unsigned long) frame;
-       regs->npc = (regs->pc = pc) + 4;
+       regs->pc = pc;
+       regs->npc = npc;
        return 1;
 }
 
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
new file mode 100644 (file)
index 0000000..5960293
--- /dev/null
@@ -0,0 +1,243 @@
+/* smp.c: Sparc SMP support.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+
+int smp_num_cpus;
+int smp_threads_ready;
+volatile unsigned long smp_msg_data;
+volatile int smp_src_cpu;
+volatile int smp_msg_id;
+
+static volatile int smp_commenced = 0;
+
+/* The only guarenteed locking primitive available on all Sparc
+ * processors is 'ldstub [%addr_reg + imm], %dest_reg' which atomicly
+ * places the current byte at the effective address into dest_reg and
+ * places 0xff there afterwards.  Pretty lame locking primitive
+ * compared to the Alpha and the intel no?  Most Sparcs have 'swap'
+ * instruction which is muct better...
+ */
+klock_t kernel_lock;
+
+void smp_commence(void)
+{
+       /*
+        *      Lets the callin's below out of their loop.
+        */
+       smp_commenced = 1;
+}
+
+void smp_callin(void)
+{
+       int cpuid = smp_get_processor_id();
+
+       /* XXX Clear the software interrupts _HERE_. */
+
+       sti();
+       calibrate_delay();
+       smp_store_cpu_info(cpuid);
+       set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]);
+       local_invalidate_all();
+       while(!smp_commenced);
+       if(cpu_number_map[cpuid] == -1)
+               while(1);
+       local_invalidate_all();
+}
+
+void smp_boot_cpus(void)
+{
+}
+
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+       struct sparc_ipimsg *msg = (struct sparc_ipimsg *) data;
+       unsigned long target_map;
+       int p = smp_processor_id();
+       static volatile int message_cpu = NO_PROC_ID;
+
+       if(!smp_activated || !smp_commenced)
+               return;
+
+       if(msg == MSG_RESCHEDULE) {
+               if(smp_cpu_in_msg[p])
+                       return;
+       }
+
+       if(message_cpu != NO_PROC_ID && msg != MSG_STOP_CPU) {
+               panic("CPU #%d: Message pass %d but pass in progress by %d of %d\n",
+                     smp_processor_id(),msg,message_cpu, smp_msg_id);
+       }
+       message_cpu = smp_processor_id();
+       smp_cpu_in_msg[p]++;
+       if(msg != MSG_RESCHEDULE) {
+               smp_src_cpu = p;
+               smp_msg_id = msg;
+               smp_msg_data = data;
+       }
+
+       if(target == MSG_ALL_BUT_SELF) {
+               target_map = cpu_present_map;
+               cpu_callin_map[0] = (1<<smp_src_cpu);
+       } else if(target == MSG_ALL) {
+               target_map = cpu_present_map;
+               cpu_callin_map[0] = 0;
+       } else {
+               target_map = (1<<target);
+               cpu_callin_map[0] = 0;
+       }
+
+       /* XXX Send lvl15 soft interrupt to cpus here XXX */
+
+       switch(wait) {
+       case 1:
+               while(cpu_callin_map[0] != target_map);
+               break;
+       case 2:
+               while(smp_invalidate_needed);
+               break;
+       }
+       smp_cpu_in_msg[p]--;
+       message_cpu = NO_PROC_ID;
+}
+
+inline void smp_invalidate(int type, unsigned long a, unsigned long b, unsigned long c)
+{
+       unsigned long flags;
+
+       smp_invalidate_needed = cpu_present_map & ~(1<<smp_processor_id());
+       save_flags(flags); cli();
+       smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
+       local_invalidate();
+       restore_flags(flags);
+}
+
+void smp_invalidate_all(void)
+{
+       smp_invalidate(0, 0, 0, 0);
+}
+
+void smp_invalidate_mm(struct mm_struct *mm)
+{
+       smp_invalidate(1, (unsigned long) mm, 0, 0);
+}
+
+void smp_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+       smp_invalidate(2, (unsigned long) mm, start, end);
+}
+
+void smp_invalidate_page(struct vm_area_struct *vmap, unsigned long page)
+{
+       smp_invalidate(3, (unsigned long)vmap->vm_mm, page, 0);
+}
+
+void smp_reschedule_irq(int cpl, struct pt_regs *regs)
+{
+       if(smp_processor_id() != active_kernel_processor)
+               panic("SMP Reschedule on CPU #%d, but #%d is active.\n",
+                     smp_processor_id(), active_kernel_processor);
+       if(user_mode(regs)) {
+               current->utime++;
+               if (current->pid) {
+                       if (current->priority < 15)
+                               kstat.cpu_nice++;
+                       else
+                               kstat.cpu_user++;
+               }
+               /* Update ITIMER_VIRT for current task if not in a system call */
+               if (current->it_virt_value && !(--current->it_virt_value)) {
+                       current->it_virt_value = current->it_virt_incr;
+                       send_sig(SIGVTALRM,current,1);
+               }
+       } else {
+               current->stime++;
+               if(current->pid)
+                       kstat.cpu_system++;
+#ifdef CONFIG_PROFILE
+               if (prof_buffer && current->pid) {
+                       extern int _stext;
+                       unsigned long eip = regs->eip - (unsigned long) &_stext;
+                       eip >>= CONFIG_PROFILE_SHIFT;
+                       if (eip < prof_len)
+                               prof_buffer[eip]++;
+               }
+#endif
+       }
+
+       /*
+        * check the cpu time limit on the process.
+        */
+       if ((current->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) &&
+           (((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_max))
+               send_sig(SIGKILL, current, 1);
+       if ((current->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) &&
+           (((current->stime + current->utime) % HZ) == 0)) {
+               unsigned long psecs = (current->stime + current->utime) / HZ;
+               /* send when equal */
+               if (psecs == current->rlim[RLIMIT_CPU].rlim_cur)
+                       send_sig(SIGXCPU, current, 1);
+               /* and every five seconds thereafter. */
+               else if ((psecs > current->rlim[RLIMIT_CPU].rlim_cur) &&
+                        ((psecs - current->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0)
+                       send_sig(SIGXCPU, current, 1);
+       }
+
+       /* Update ITIMER_PROF for the current task */
+       if (current->it_prof_value && !(--current->it_prof_value)) {
+               current->it_prof_value = current->it_prof_incr;
+               send_sig(SIGPROF,current,1);
+       }
+
+       if(0 > --current->counter || current->pid == 0) {
+               current->counter = 0;
+               need_resched = 1;
+       }
+}
+
+void smp_message_irq(int cpl, struct pt_regs *regs)
+{
+       int i=smp_processor_id();
+/*     static int n=0;
+       if(n++<NR_CPUS)
+               printk("IPI %d->%d(%d,%ld)\n",smp_src_cpu,i,smp_msg_id,smp_msg_data);*/
+       switch(smp_msg_id)
+       {
+               case 0: /* IRQ 13 testing - boring */
+                       return;
+                       
+               /*
+                *      A TLB flush is needed.
+                */
+                
+               case MSG_INVALIDATE_TLB:
+                       if(clear_bit(i,(unsigned long *)&smp_invalidate_needed))
+                               local_invalidate();
+                       set_bit(i, (unsigned long *)&cpu_callin_map[0]);
+                       cpu_callin_map[0]|=1<<smp_processor_id();
+                       break;
+                       
+               /*
+                *      Halt other CPU's for a panic or reboot
+                */
+               case MSG_STOP_CPU:
+                       while(1)
+                       {
+                               if(cpu_data[smp_processor_id()].hlt_works_ok)
+                                       __asm__("hlt");
+                       }
+               default:
+                       printk("CPU #%d sent invalid cross CPU message to CPU #%d: %X(%lX).\n",
+                               smp_src_cpu,smp_processor_id(),smp_msg_id,smp_msg_data);
+                       break;
+       }
+       /*
+        *      Clear the IPI, so we can receive future IPI's
+        */
+        
+       apic_read(APIC_SPIV);           /* Dummy read */
+       apic_write(APIC_EOI, 0);        /* Docs say use 0 for future compatibility */
+}
index e1bcbad929a78361717c9149477efeeeca367382..604b0fc964b842eb89e9e91e5990a0fb0f8a05da 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.7 1995/11/25 00:58:26 davem Exp $
+/* $Id: sparc-stub.c,v 1.10 1996/02/15 09:12:09 davem Exp $
  * sparc-stub.c:  KGDB support for the Linux kernel.
  *
  * Modifications to run under Linux
@@ -636,7 +636,6 @@ handle_exception (unsigned long *registers)
  * breakpoint, and the icache probably has no way of knowing that a data ref to
  * some location may have changed something that is in the instruction cache.
  */
-
                        /* Only instruction cache flushing on the sun4c/sun4
                         * for now.  We assume control flow during the kgdb
                         * transaction has not left the context in which it
index 2da321920dbf0854f0d6f96fb93ef4b72bfb1d5c..d7ea7cc31649c66fdf8cdfa70613e116a9e676a8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunos_asm.S,v 1.8 1995/11/25 00:58:29 davem Exp $
+/* $Id: sunos_asm.S,v 1.10 1995/12/26 04:09:33 davem Exp $
  * sunos_asm.S: SunOS system calls which must have a low-level
  *              entry point to operate correctly.
  *
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
 
-       /* Note that for dual value returning system calls we
-        * need to store the second one ourselves in the pt_regs
-        * trap-frame.  linux_sparc_syscall does %o0 for us
-        * however.
-        */
-
        .text
        .align 4
 
        /* SunOS getpid() returns pid in %o0 and ppid in %o1 */
        .globl  C_LABEL(sunos_getpid)
 C_LABEL(sunos_getpid):
-       save    %sp, -STACKFRAME_SZ, %sp
        call    C_LABEL(sys_getpid)
-       nop
+        nop
 
-       mov     %o0, %i0
+       st      %o0, [%sp + REGWIN_SZ + PT_I0]
 
        call    C_LABEL(sys_getppid)
-       nop     
+        nop    
 
-       st      %o0, [%fp + STACKFRAME_SZ + PT_I1]
+       st      %o0, [%sp + REGWIN_SZ + PT_I1]
 
-       ret
-       restore
+       b       C_LABEL(ret_sys_call)
+        nop
 
        /* SunOS getuid() returns uid in %o0 and euid in %o1 */
        .globl  C_LABEL(sunos_getuid)
 C_LABEL(sunos_getuid):
-       save    %sp, -STACKFRAME_SZ, %sp
        call    C_LABEL(sys_getuid)
-       nop
+        nop
 
-       mov     %o0, %i0
+       st      %o0, [%sp + REGWIN_SZ + PT_I0]
 
        call    C_LABEL(sys_geteuid)
-       nop
+        nop
 
-       st      %o0, [%fp + STACKFRAME_SZ + PT_I1]
+       st      %o0, [%sp + REGWIN_SZ + PT_I1]
 
-       ret
-       restore
+       b       C_LABEL(ret_sys_call)
+        nop
 
        /* SunOS getgid() returns gid in %o0 and egid in %o1 */
        .globl  C_LABEL(sunos_getgid)
 C_LABEL(sunos_getgid):
-       save    %sp, -STACKFRAME_SZ, %sp
        call    C_LABEL(sys_getgid)
-       nop
+        nop
 
-       mov     %o0, %i0
+       st      %o0, [%sp + REGWIN_SZ + PT_I0]
 
        call    C_LABEL(sys_getegid)
-       nop
+        nop
 
-       st      %o0, [%fp + STACKFRAME_SZ + PT_I1]
+       st      %o0, [%sp + REGWIN_SZ + PT_I1]
 
-       ret
-       restore
+       b       C_LABEL(ret_sys_call)
+        nop
 
        /* SunOS's execv() call only specifies the argv argument, the
         * environment settings are the same as the calling processes.
         */
        .globl  C_LABEL(sunos_execv)
 C_LABEL(sunos_execv):
-       save    %sp, -STACKFRAME_SZ, %sp
+       st      %g0, [%sp + REGWIN_SZ + PT_I2]
 
-       st      %g0, [%fp + STACKFRAME_SZ + PT_I2]
        call    C_LABEL(sparc_execve)
-       add     %fp, STACKFRAME_SZ, %o0
+        add    %sp, REGWIN_SZ, %o0
 
-       st      %o0, [%fp + STACKFRAME_SZ + PT_I1]
+       st      %o0, [%sp + REGWIN_SZ + PT_I0]
 
-       ret
-       restore
+       b       C_LABEL(ret_sys_call)
+        nop
 
index 9a24af4f38501c495965294da41c585e3056894b..a1c64bf0c776d4477ce66f1fef048307925a8670 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.8 1995/11/26 04:07:39 davem Exp $
+/* $Id: sunos_ioctl.c,v 1.17 1996/02/10 04:29:20 davem Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
 #include <linux/if.h>
 #include <linux/if_arp.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
+#include <asm/kbio.h>
+
+#if 0
+extern char sunkbd_type;
+extern char sunkbd_layout;
+#endif
 
 extern asmlinkage int sys_ioctl(unsigned int, unsigned int, unsigned long);
+extern asmlinkage int sys_setsid(void);
 
 asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
 {
        struct file *filp;
-       
+       int foo;
+
        if (fd >= NR_OPEN || !(filp = current->files->fd [fd]))
                return -EBADF;
 
+       /* First handle an easy compat. case for tty ldisc. */
+       if(cmd == TIOCSETD) {
+               int *p, ntty = N_TTY, old_fs;
+
+               p = (int *) arg;
+               foo = verify_area(VERIFY_WRITE, p, sizeof(int));
+               if(foo) return foo;
+               if(*p == 2) {
+                       old_fs = get_fs();
+                       set_fs(KERNEL_DS);
+                       foo = sys_ioctl(fd, cmd, (int) &ntty);
+                       set_fs(old_fs);
+                       return (foo == -EINVAL ? -EOPNOTSUPP : foo);
+               }
+       }
+
+       /* Binary compatability is good American knowhow fuckin' up. */
+       if(cmd == TIOCNOTTY)
+               return sys_setsid();
+
        /* SunOS networking ioctls. */
        switch (cmd) {
        case _IOW('r', 10, struct rtentry):
@@ -49,7 +78,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
                return sys_ioctl(fd, SIOCSIFMEM, arg);
        case _IORW('i', 19, struct ifreq):
                return sys_ioctl(fd, SIOCGIFMEM, arg);
-       case _IORW('i', 20, struct ifreq):
+       case _IORW('i', 20, struct ifconf):
                return sys_ioctl(fd, SIOCGIFCONF, arg);
        case _IOW('i', 21, struct ifreq): /* SIOCSIFMTU */
                return sys_ioctl(fd, SIOCSIFMTU, arg);
@@ -83,7 +112,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
        case _IOW('i', 46, struct ifreq): /* SIOCSSDSTATS */
        case _IOW('i', 47, struct ifreq): /* SIOCSSESTATS */
        case _IOW('i', 48, struct ifreq): /* SIOCSPROMISC */
-               return -EINVAL;
+               return -EOPNOTSUPP;
 
        case _IOW('i', 49, struct ifreq):
                return sys_ioctl(fd, SIOCADDMULTI, arg);
@@ -91,6 +120,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
                return sys_ioctl(fd, SIOCDELMULTI, arg);
 
        /* FDDI interface ioctls, unsupported. */
+               
        case _IOW('i', 51, struct ifreq): /* SIOCFDRESET */
        case _IOW('i', 52, struct ifreq): /* SIOCFDSLEEP */
        case _IOW('i', 53, struct ifreq): /* SIOCSTRTFMWAR */
@@ -100,10 +130,27 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
        case _IOW('i', 57, struct ifreq): /* SIOCFDEXUSER */
        case _IOW('i', 58, struct ifreq): /* SIOCFDGNETMAP */
        case _IOW('i', 59, struct ifreq): /* SIOCFDGIOCTL */
-               return -EINVAL;
+               printk("FDDI ioctl, returning EOPNOTSUPP\n");
+               return -EOPNOTSUPP;
+       case _IOW('t', 125, int):
+               /* More stupid tty sunos ioctls, just
+                * say it worked.
+                */
+               return 0;
+       /* Non posix grp */
+       case _IOR('t', 119, int):
+               return -EIO;
+       }
+
+#if 0
+       if (cmd & 0xff00 == ('k' << 8)){
+               printk ("[[KBIO: %8.8x\n", (unsigned int) cmd);
        }
+#endif
 
-       return sys_ioctl (fd, cmd, arg);
+       foo = sys_ioctl(fd, cmd, arg);
+       /* so stupid... */
+       return (foo == -EINVAL ? -EOPNOTSUPP : foo);
 }
 
 
index d5fc112921fba36b9dc7fa516a3b6b2122419533..305f31644f59d7bfad1b7123304f59b9adcc0e93 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: switch.S,v 1.9 1995/11/25 00:58:32 davem Exp $
+/* $Id: switch.S,v 1.14 1995/12/29 21:47:22 davem Exp $
  * switch.S: Sparc task switch code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -13,8 +13,6 @@
 #include <asm/winmacro.h>
 
 #define sw_ntask     g1
-#define sw_sp        g2
-#define sw_pc        g3
 #define sw_psr       g4
 #define sw_wim       g5
 #define sw_tmp       g6
@@ -26,7 +24,7 @@
  * First successful task switch 05/13/95 21:52:37
  */
        .align 4
-       .globl  C_LABEL(sparc_switch_to), C_LABEL(mmu_switch_lowlevel)
+       .globl  C_LABEL(sparc_switch_to)
 C_LABEL(sparc_switch_to):
        mov     %o0, %sw_ntask
 
@@ -34,37 +32,24 @@ C_LABEL(sparc_switch_to):
        FLUSH_ALL_KERNEL_WINDOWS; 
        STORE_WINDOW(sp)
        rd      %psr, %sw_psr
-       sethi   %hi(PSR_EF), %sw_tmp
-       andn    %sw_psr, %sw_tmp, %sw_psr
-       LOAD_CURRENT(sw_tmp)
+       LOAD_CURRENT(sw_tmp, sw_wim)
        rd      %wim, %sw_wim
        std     %sw_psr, [%sw_tmp + THREAD_KPSR]
        std     %sp, [%sw_tmp + THREAD_KSP]
 
        /* Load new kernel state. */
        wr      %sw_psr, PSR_ET, %psr
+       WRITE_PAUSE
        sethi   %hi(C_LABEL(current_set)), %sw_tmp
        st      %sw_ntask, [%sw_tmp + %lo(C_LABEL(current_set))]
        ldd     [%sw_ntask + THREAD_KPSR], %sw_psr
-       ldd     [%sw_ntask + THREAD_KSP], %sw_sp
        wr      %sw_psr, PSR_ET, %psr
        WRITE_PAUSE
        wr      %sw_wim, 0x0, %wim
        WRITE_PAUSE
-       mov     %sw_sp, %sp
+       ldd     [%sw_ntask + THREAD_KSP], %sp
        LOAD_WINDOW(sp)
-       mov     %sw_pc, %o7
-
-       /* Jump into the proper context. */
-       ld      [%sw_ntask + THREAD_CONTEXT], %sw_ctx
-       tst     %sw_ctx
-       bneg    1f                      ! this must be swapper
-        nop
 
-C_LABEL(mmu_switch_lowlevel):
-       sethi   %hi(AC_CONTEXT), %sw_tmp        ! else set new context
-       stba    %sw_ctx, [%sw_tmp] ASI_CONTROL
-1:
        wr      %sw_psr, 0x0, %psr              ! traps back on
        WRITE_PAUSE
 
diff --git a/arch/sparc/kernel/sys_bsd.c b/arch/sparc/kernel/sys_bsd.c
new file mode 100644 (file)
index 0000000..fce1c58
--- /dev/null
@@ -0,0 +1,48 @@
+/* sys_bsd.c: {net, open}bsd specific system call handling.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+#include <linux/kernel.h>
+
+#include <asm/ptrace.h>
+#include <asm/bsderrno.h>
+
+static int errno_trans[] = {
+       0,
+       BSD_EPERM, BSD_ENOENT, BSD_ESRCH, BSD_EINTR, BSD_EIO,
+       BSD_ENXIO, BSD_E2BIG, BSD_ENOEXEC, BSD_EBADF, BSD_ECHILD,
+       BSD_EAGAIN, BSD_ENOMEM, BSD_EACCES, BSD_EFAULT, BSD_ENOTBLK,
+       BSD_EBUSY, BSD_EEXIST, BSD_EXDEV, BSD_ENODEV, BSD_ENOTDIR,
+       BSD_EISDIR, BSD_EINVAL, BSD_ENFILE, BSD_EMFILE, BSD_ENOTTY,
+       BSD_ETXTBSY, BSD_EFBIG, BSD_ENOSPC, BSD_ESPIPE, BSD_EROFS,
+       BSD_EMLINK, BSD_EPIPE, BSD_EDOM, BSD_ERANGE, BSD_EWOULDBLOCK,
+       BSD_EINPROGRESS, BSD_EALREADY, BSD_ENOTSOCK, BSD_EDESTADDRREQ,
+       BSD_EMSGSIZE, BSD_EPROTOTYPE, BSD_ENOPROTOOPT, BSD_EPROTONOSUPPORT,
+       BSD_ESOCKTNOSUPPORT, BSD_EOPNOTSUPP, BSD_EPFNOSUPPORT, BSD_EAFNOSUPPORT,
+       BSD_EADDRINUSE,
+       BSD_EADDRNOTAVAIL, BSD_ENETDOWN, BSD_ENETUNREACH, BSD_ENETRESET,
+       BSD_ECONNABORTED, BSD_ECONNRESET, BSD_ENOBUFS, BSD_EISCONN,
+       BSD_ENOTCONN, BSD_ESHUTDOWN, BSD_ETOOMANYREFS, BSD_ETIMEDOUT,
+       BSD_ECONNREFUSED, BSD_ELOOP, BSD_ENAMETOOLONG, BSD_EHOSTDOWN,
+       BSD_EHOSTUNREACH, BSD_ENOTEMPTY, BSD_EPROCLIM, BSD_EUSERS,
+       BSD_EDQUOT, BSD_ESTALE, BSD_EREMOTE, BSD_ENOSTR, BSD_ETIME,
+       BSD_ENOSR, BSD_ENOMSG, BSD_EBADMSG, BSD_EIDRM, BSD_EDEADLK,
+       BSD_ENOLCK, BSD_ENONET, BSD_ERREMOTE, BSD_ENOLINK, BSD_EADV,
+       BSD_ESRMNT, BSD_ECOMM, BSD_EPROTO, BSD_EMULTIHOP, BSD_EDOTDOT,
+       BSD_EREMCHG, BSD_ENOSYS
+};
+
+asmlinkage int netbsd_nosys(void)
+{
+       struct pt_regs *regs;
+
+       regs = (struct pt_regs *) (current->saved_kernel_stack +
+                                  sizeof(struct reg_window));
+       current->tss.sig_address = regs->pc;
+       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);
+       return -BSD_ENOSYS;
+}
index d39a123f4741489e94ab218b76214070a617d7bb..975ed80a0f9d35b0101099da9e6f1483374cfcd0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.6 1995/11/25 00:58:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.7 1996/03/01 07:15:58 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -43,6 +43,38 @@ asmlinkage void sparc_pipe(struct pt_regs *regs)
        }
 }
 
+/* Note most sanity checking already done in sclow.S code. */
+asmlinkage int quick_sys_write(unsigned int fd, char *buf, unsigned int count)
+{
+       struct file *file = current->files->fd[fd];
+       struct inode *inode = file->f_inode;
+       int error;
+
+       error = verify_area(VERIFY_READ, buf, count);
+       if(error)
+               return error;
+       /*
+        * If data has been written to the file, remove the setuid and
+        * the setgid bits. We do it anyway otherwise there is an
+        * extremely exploitable race - does your OS get it right |->
+        *
+        * Set ATTR_FORCE so it will always be changed.
+        */
+       if (!suser() && (inode->i_mode & (S_ISUID | S_ISGID))) {
+               struct iattr newattrs;
+               newattrs.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID);
+               newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_FORCE;
+               notify_change(inode, &newattrs);
+       }
+
+       down(&inode->i_sem);
+       error = file->f_op->write(inode,file,buf,count);
+       up(&inode->i_sem);
+       return error;
+}
+
+/* XXX do we need this crap? XXX */
+
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
index f4b49628b0d0fc90b232a338c4162aa002bdcef6..050e473a93e6b96af2059fc4ae447dfe40502b93 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.20 1995/11/25 00:58:37 davem Exp $
+/* $Id: sys_sunos.c,v 1.33 1996/03/01 07:16:00 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatability support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -15,6 +15,7 @@
 #include <linux/mman.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 #include <linux/fs.h>
 #include <linux/resource.h>
 #include <linux/signal.h>
@@ -26,6 +27,8 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/pconf.h>
+#include <asm/idprom.h> /* for gethostid() */
+#include <asm/unistd.h>
 
 /* For the nfs mount emulation */
 #include <linux/socket.h>
 
 static unsigned long get_sparc_unmapped_area(unsigned long len)
 {
-       unsigned long addr;
+       unsigned long addr = 0xE8000000UL;
        struct vm_area_struct * vmm;
 
        if (len > TASK_SIZE)
                return 0;
-       addr = 0xE8000000UL;    /* To make it work on a sun4c. */
-       for (vmm = current->mm->mmap; ; vmm = vmm->vm_next) {
+       for (vmm = find_vma(current, addr); ; vmm = vmm->vm_next) {
+               /* At this point:  (!vmm || addr < vmm->vm_end). */
                if (TASK_SIZE - len < addr)
                        return 0;
-               if (!vmm)
+               if (!vmm || addr + len <= vmm->vm_start)
                        return addr;
-               if (addr > vmm->vm_end)
-                       continue;
-               if (addr + len > vmm->vm_start) {
-                       addr = vmm->vm_end;
-                       continue;
-               }
-               return addr;
+               addr = vmm->vm_end;
        }
 }
 
@@ -99,22 +96,10 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
                return ((retval < KERNBASE) ? 0 : retval);
 }
 
-/* Weird SunOS mm control function.. */
+/* lmbench calls this, just say "yeah, ok" */
 asmlinkage int sunos_mctl(unsigned long addr, unsigned long len, int function, char *arg)
 {
-       printk("%s: Call to sunos_mctl(addr<%08lx>, len<%08lx>, function<%d>, arg<%p>) "
-              "is unsupported\n", current->comm, addr, len, function, arg);
-       return -EAGAIN;
-}
-
-/* XXX This won't be necessary when I sync up to never kernel in 1.3.x series
- * XXX which has the sys_msync() system call implemented properly.
- */
-asmlinkage int sunos_msync(unsigned long addr, unsigned long len, unsigned long flags)
-{
-       printk("%s: Call to sunos_msync(addr<%08lx>, len<%08lx>, flags<%08lx>) "
-              "is unsupported\n", current->comm, addr, len, flags);
-       return -EINVAL;
+       return 0;
 }
 
 /* SunOS is completely broken... it returns 0 on success, otherwise
@@ -188,10 +173,10 @@ asmlinkage unsigned long sunos_sbrk(int increment)
 
        /* This should do it hopefully... */
        error = sunos_brk(((int) current->mm->brk) + increment);
-       if(error == 0)
-               return current->mm->brk;
-       else
+       if(error)
                return error;
+       else
+               return current->mm->brk;
 }
 
 /* XXX Completely undocumented, and completely magic...
@@ -316,12 +301,28 @@ asmlinkage long sunos_getdtablesize(void)
 
 asmlinkage unsigned long sunos_sigblock(unsigned long blk_mask)
 {
-       unsigned long old = current->blocked;
+       unsigned long flags;
+       unsigned long old;
 
+       save_flags(flags); cli();
+       old = current->blocked;
        current->blocked |= (blk_mask & _BLOCKABLE);
+       restore_flags(flags);
        return old;
 }
 
+asmlinkage unsigned long sunos_sigsetmask(unsigned long newmask)
+{
+       unsigned long flags;
+       unsigned long retval;
+
+       save_flags(flags); cli();
+       retval = current->blocked;
+       current->blocked = newmask & _BLOCKABLE;
+       restore_flags(flags);
+       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) */
@@ -359,7 +360,7 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
        dirent = buf->curr;
        buf->previous = dirent;
        put_user(ino, &dirent->d_ino);
-       put_user((strlen(name)), &dirent->d_namlen);
+       put_user(namlen, &dirent->d_namlen);
        put_user(reclen, &dirent->d_reclen);
        memcpy_tofs(dirent->d_name, name, namlen);
        put_user(0, dirent->d_name + namlen);
@@ -399,6 +400,76 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
        return cnt - buf.count;
 }
 
+/* Old sunos getdirentries, severely broken compatability stuff here. */
+struct sunos_direntry {
+    unsigned long  d_ino;
+    unsigned short d_reclen;
+    unsigned short 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);
+       memcpy_tofs(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, void * dirent, int cnt, unsigned int *basep)
+{
+       struct file * file;
+       struct sunos_direntry * lastdirent;
+       struct sunos_direntry_callback buf;
+       int error;
+
+       if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+               return -EBADF;
+       if (!file->f_op || !file->f_op->readdir)
+               return -ENOTDIR;
+       if(verify_area(VERIFY_WRITE, dirent, cnt) ||
+          verify_area(VERIFY_WRITE, basep, sizeof(unsigned int)))
+               return -EFAULT;
+       if(cnt < (sizeof(struct sunos_direntry) + 255))
+               return -EINVAL;
+
+       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)
+               return error;
+       lastdirent = buf.previous;
+       if (!lastdirent)
+               return buf.error;
+       put_user(file->f_pos, basep);
+       return cnt - buf.count;
+}
+
 asmlinkage int sunos_getdomainname(char *name, int len)
 {
        int error;
@@ -430,18 +501,16 @@ asmlinkage int sunos_uname(struct sunos_utsname *name)
        if(error)
                return error;
        memcpy_tofs(&name->sname[0], &system_utsname.sysname[0],
-                   sizeof(name->sname));
+                   sizeof(name->sname) - 1);
        memcpy_tofs(&name->nname[0], &system_utsname.nodename[0],
-                   sizeof(name->nname));
+                   sizeof(name->nname) - 1);
        name->nname[8] = '\0';
-       memcpy_tofs(&name->nnext[0], &system_utsname.nodename[9],
-                   sizeof(name->nnext));
        memcpy_tofs(&name->rel[0], &system_utsname.release[0],
-                   sizeof(name->rel));
+                   sizeof(name->rel) - 1);
        memcpy_tofs(&name->ver[0], &system_utsname.version[0],
-                   sizeof(name->ver));
+                   sizeof(name->ver) - 1);
        memcpy_tofs(&name->mach[0], &system_utsname.machine[0],
-                   sizeof(name->mach));
+                   sizeof(name->mach) - 1);
        return 0;
 }
 
@@ -449,8 +518,8 @@ asmlinkage int sunos_nosys(void)
 {
        struct pt_regs *regs;
 
-       regs = (struct pt_regs *) (((current->tss.ksp) & PAGE_MASK) +
-                                  (PAGE_SIZE - TRACEREG_SZ));
+       regs = (struct pt_regs *) (current->saved_kernel_stack +
+                                  sizeof(struct reg_window));
        current->tss.sig_address = regs->pc;
        current->tss.sig_desc = regs->u_regs[UREG_G1];
        send_sig(SIGSYS, current, 1);
@@ -500,9 +569,9 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);
 
 asmlinkage int sunos_select(int width, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
-    /* SunOS binaries expect that select won't change the tvp contents */
-    current->personality |= STICKY_TIMEOUTS;
-    return sys_select (width, inp, outp, exp, tvp);
+       /* SunOS binaries expect that select won't change the tvp contents */
+       current->personality |= STICKY_TIMEOUTS;
+       return sys_select (width, inp, outp, exp, tvp);
 }
 
 asmlinkage void sunos_nop(void)
@@ -520,38 +589,6 @@ asmlinkage void sunos_nop(void)
 #define SMNT_MULTI        64
 #define SMNT_SYS5         128
 
-struct ufs_mntargs {
-       char *dev_name;
-};
-
-struct lo_mntargs {
-       char *dev_name;
-};
-
-struct ext2_mntargs {
-       char *dev_name;
-};
-
-struct iso9660_mntargs {
-       char *dev_name;
-};
-
-struct minix_mntargs {
-       char *dev_name;
-};
-
-struct ext_mntargs {
-       char *dev_name;
-};
-
-struct msdos_mntargs {
-       char *dev_name;
-};
-
-struct xiafs_mntargs {
-       char *dev_name;
-};
-
 struct sunos_fh_t {
        char fh_data [NFS_FHSIZE];
 };
@@ -572,23 +609,14 @@ struct sunos_nfs_mount_args {
        char       *netname;   /* server's netname */
 };
 
-extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
 
-extern int do_mount(dev_t, const char *, char *, int, void *);
+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 sys_mount (char * dev_name, char * dir_name, char * type,
-                 unsigned long new_flags, void * data);
-
-extern asmlinkage int
-sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
-
-extern asmlinkage int
-sys_socket(int family, int type, int protocol);
-
-asmlinkage int
-sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+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
@@ -654,7 +682,6 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
        struct nfs_mount_data linux_nfs_mount;
        struct sunos_nfs_mount_args *sunos_mount = data;
        dev_t dev;
-       struct pt_regs *regs;
 
        error = verify_area(VERIFY_READ, data, sizeof (struct sunos_nfs_mount_args));
        if (error)
@@ -700,18 +727,10 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
 
        dev = get_unnamed_dev ();
        
-       ret = do_mount (dev, dir_name, "nfs", linux_flags, &linux_nfs_mount);
+       ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
        if (ret)
            put_unnamed_dev(dev);
 
-#if 0
-       /* Kill the process: the nfs directory is already mounted */
-       regs = (struct pt_regs *) (((current->tss.ksp) & PAGE_MASK) +
-                                  (PAGE_SIZE - TRACEREG_SZ));
-       current->tss.sig_address = regs->pc;
-       current->tss.sig_desc = regs->u_regs[UREG_G1];
-       send_sig(SIGSYS, current, 1);
-#endif
        return ret;
 }
 
@@ -740,7 +759,7 @@ sunos_mount(char *type, char *dir, int flags, void *data)
        if(error)
                return error;
        if(strcmp(type, "ext2") == 0) {
-               dev_fname = (char *) data;;
+               dev_fname = (char *) data;
        } else if(strcmp(type, "iso9660") == 0) {
                dev_fname = (char *) data;
        } else if(strcmp(type, "minix") == 0) {
@@ -761,8 +780,6 @@ sunos_mount(char *type, char *dir, int flags, void *data)
        if(error)
                return error;
        error = sys_mount(dev_fname, dir, type, linux_flags, NULL);
-       printk("sys_mount(type<%s>, device<%s>) returns %d\n",
-              type, dev_fname, error);
        return error;
 }
 
@@ -794,8 +811,39 @@ asmlinkage int sunos_killpg(int pgrp, int sig)
        return kill_pg(pgrp, sig, 0);
 }
 
-extern asmlinkage sunos_audit ()
+asmlinkage int sunos_audit(void)
 {
        printk ("sys_audit\n");
        return -1;
 }
+
+extern asmlinkage unsigned long sunos_gethostid(void)
+{
+       return (unsigned long) idprom->id_sernum;
+}
+
+extern asmlinkage long sunos_sysconf (int name)
+{
+       switch (name){
+       case _SC_ARG_MAX:
+               return ARG_MAX;
+       case _SC_CHILD_MAX:
+               return CHILD_MAX;
+       case _SC_CLK_TCK:
+               return HZ;
+       case _SC_NGROUPS_MAX:
+               return NGROUPS_MAX;
+       case _SC_OPEN_MAX:
+               return OPEN_MAX;
+       case _SC_JOB_CONTROL:
+               return 1;       /* yes, we do support job control */
+       case _SC_SAVED_IDS:
+               return 1;       /* yes, we do support saved uids  */
+       case _SC_VERSION:
+               /* mhm, POSIX_VERSION is in /usr/include/unistd.h
+                * should it go on /usr/include/linux?
+                */
+               return  199009L; 
+       }
+       return -1;
+}
index 0e95bfc9ee1b302924de104563679beb46f17d48..f88d9b2652ce6ae5a79e4f1814f902c887a6b1d1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.22 1995/11/25 00:58:42 davem Exp $
+/* $Id: systbls.S,v 1.29 1996/03/01 07:16:02 davem Exp $
  * systbls.S: System call entry point tables for OS compatability.
  *            The native Linux system call table lives here also.
  *
 
 #include <asm/cprefix.h>
 
+       /* READ THIS BEFORE DICKING WITH THIS TABLE...
+        *
+        * The format of these entries is kind of peculiar
+        * to optimize non-blocking easy syscalls.  If
+        * it is a difficult call or it will sleep the entry
+        * is just to word aligned address of the function
+        * routine to call.  If the lowest bit of the entry
+        * is set then (entry & ~1) is the address of the low
+        * in-trap-window assembler routine which will handle
+        * the system call at the lowest possible level.  For
+        * these low level optimized routines no state is saved
+        * at all and the usual restrictions reply.  Act as
+        * if you got called directly from the trap table.
+        * Some of these optimized routines try really hard
+        * to get around a state save, if you run into trouble
+        * you can still survive by branching to the label
+        * syscall_is_too_hard which is in entry.S  If you
+        * have to back out like this you _must_ preserve the
+        * value of %l0, %l1, %l2, and %l7 when you were called
+        * so be _careful_.
+        */
+
+#define LOWSYS(func) (CONCAT(func, _low) + 1)
+
        .data
        .align 4
 
 
        .globl C_LABEL(sys_call_table)
 C_LABEL(sys_call_table):
-       .long C_LABEL(sys_setup)                /* 0 */
-       .long C_LABEL(sys_exit)
-       .long C_LABEL(sys_fork)
-       .long C_LABEL(sys_read)
-       .long C_LABEL(sys_write)
-       .long C_LABEL(sys_open)                 /* 5 */
-       .long C_LABEL(sys_close)
-       .long C_LABEL(sys_wait4)
-       .long C_LABEL(sys_creat)
-       .long C_LABEL(sys_link)
-       .long C_LABEL(sys_unlink)               /* 10 */
-       .long C_LABEL(sunos_execv)
-       .long C_LABEL(sys_chdir)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_mknod)
-       .long C_LABEL(sys_chmod)                /* 15 */
-       .long C_LABEL(sys_chown)
-       .long C_LABEL(sys_brk)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_lseek)
-       .long C_LABEL(sys_getpid)               /* 20 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_setuid)
-       .long C_LABEL(sys_getuid)
-       .long C_LABEL(sys_ni_syscall)           /* 25 */
-       .long C_LABEL(sys_ni_syscall)           /* this will be sys_ptrace() */
-       .long C_LABEL(sys_alarm)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_pause)
-       .long C_LABEL(sys_utime)                /* 30 */
-       .long C_LABEL(sys_stty)
-       .long C_LABEL(sys_gtty)
-       .long C_LABEL(sys_access)
-       .long C_LABEL(sys_nice)
-       .long C_LABEL(sys_ftime)                /* 35 */
-       .long C_LABEL(sys_sync)
-       .long C_LABEL(sys_kill)
-       .long C_LABEL(sys_newstat)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_newlstat)             /* 40 */
-       .long C_LABEL(sys_dup)
-       .long C_LABEL(sys_pipe)
-       .long C_LABEL(sys_times)
-       .long C_LABEL(sys_profil)
-       .long C_LABEL(sys_ni_syscall)           /* 45 */
-       .long C_LABEL(sys_setgid)
-       .long C_LABEL(sys_getgid)
-       .long C_LABEL(sys_signal)
-       .long C_LABEL(sys_geteuid)
-       .long C_LABEL(sys_getegid)              /* 50 */
-       .long C_LABEL(sys_acct)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ioctl)
-       .long C_LABEL(sys_reboot)               /* 55 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_symlink)
-       .long C_LABEL(sys_readlink)
-       .long C_LABEL(sys_execve)
-       .long C_LABEL(sys_umask)                /* 60 */
-       .long C_LABEL(sys_chroot)
-       .long C_LABEL(sys_newfstat)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_getpagesize)
-       .long C_LABEL(sys_ni_syscall)           /* 65 */
-       .long C_LABEL(sys_vfork)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 70 */
-       .long C_LABEL(sunos_mmap)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_munmap)
-       .long C_LABEL(sys_mprotect)
-       .long C_LABEL(sys_ni_syscall)           /* 75 */
-       .long C_LABEL(sys_vhangup)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_getgroups)
-       .long C_LABEL(sys_setgroups)            /* 80 */
-       .long C_LABEL(sys_getpgrp)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_setitimer)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_swapon)               /* 85 */
-       .long C_LABEL(sys_getitimer)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_sethostname)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_dup2)                 /* 90 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_fcntl)
-       .long C_LABEL(sys_select)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_fsync)                /* 95 */
-       .long C_LABEL(sys_setpriority)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_getpriority)          /* 100 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 105 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 110 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 115 */
-       .long C_LABEL(sys_gettimeofday)
-       .long C_LABEL(sys_getrusage)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 120 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_settimeofday)
-       .long C_LABEL(sys_fchown)
-       .long C_LABEL(sys_fchmod)
-       .long C_LABEL(sys_ni_syscall)           /* 125 */
-       .long C_LABEL(sys_setreuid)
-       .long C_LABEL(sys_setregid)
-       .long C_LABEL(sys_rename)
-       .long C_LABEL(sys_truncate)
-       .long C_LABEL(sys_ftruncate)            /* 130 */
-       .long C_LABEL(sys_flock)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 135 */
-       .long C_LABEL(sys_mkdir)
-       .long C_LABEL(sys_rmdir)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 140 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_getrlimit)
-       .long C_LABEL(sys_setrlimit)            /* 145 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 150 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 155 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_statfs)
-       .long C_LABEL(sys_fstatfs)
-       .long C_LABEL(sys_umount)
-       .long C_LABEL(sys_ni_syscall)           /* 160 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_setdomainname)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* sys_quotactl -- 165 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_mount)
-       .long C_LABEL(sys_ustat)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 170 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_getdents)
-       .long C_LABEL(sys_setsid)               /* 175 */
-       .long C_LABEL(sys_fchdir)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 180 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_sigpending)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_setpgid)              /* 185 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_uname)
-       .long C_LABEL(sys_init_module)          /* 190 */
-       .long C_LABEL(sys_personality)
-       .long C_LABEL(sys_prof)
-       .long C_LABEL(sys_break)
-       .long C_LABEL(sys_lock)
-       .long C_LABEL(sys_mpx)                  /* 195 */
-       .long C_LABEL(sys_ulimit)
-       .long C_LABEL(sys_getppid)
-       .long C_LABEL(sys_sigaction)
-       .long C_LABEL(sys_sgetmask)
-       .long C_LABEL(sys_ssetmask)             /* 200 */
-       .long C_LABEL(sys_sigsuspend)
-       .long C_LABEL(sys_newlstat)
-       .long C_LABEL(sys_uselib)
-       .long C_LABEL(old_readdir)
-       .long C_LABEL(sys_ni_syscall)           /* 205 */
-       .long C_LABEL(sys_socketcall)
-       .long C_LABEL(sys_syslog)
-       .long C_LABEL(sys_olduname)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_idle)                 /* 210 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_waitpid)
-       .long C_LABEL(sys_swapoff)
-       .long C_LABEL(sys_sysinfo)
-       .long C_LABEL(sys_ipc)                  /* 215 */
-       .long C_LABEL(sys_sigreturn)
-       .long C_LABEL(sys_clone)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_adjtimex)
-       .long C_LABEL(sys_sigprocmask)          /* 220 */
-       .long C_LABEL(sys_create_module)
-       .long C_LABEL(sys_delete_module)
-       .long C_LABEL(sys_get_kernel_syms)
-       .long C_LABEL(sys_getpgid)
-       .long C_LABEL(sys_bdflush)              /* 225 */
-       .long C_LABEL(sys_sysfs)
-       .long C_LABEL(sys_ni_syscall)           /* Andrew Filesystem Syscall */
-       .long C_LABEL(sys_setfsuid)
-       .long C_LABEL(sys_setfsgid)
-       .long C_LABEL(sys_llseek)               /* 230 Should be newselect... */
-       .long C_LABEL(sys_time)
-       .long C_LABEL(sys_ni_syscall)           /* Should be oldstat... */
-       .long C_LABEL(sys_stime)
-       .long C_LABEL(sys_ni_syscall)           /* Should be oldfstat */
-       .long C_LABEL(sys_ni_syscall)           /* 235 - sys_phys */
-       .long C_LABEL(sys_llseek)
-
+/*0*/  .long C_LABEL(sys_setup), C_LABEL(sys_exit), C_LABEL(sys_fork)
+       .long C_LABEL(sys_read), C_LABEL(sys_write), C_LABEL(sys_open)
+       .long C_LABEL(sys_close), C_LABEL(sys_wait4), C_LABEL(sys_creat)
+       .long C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv)
+       .long C_LABEL(sys_chdir), C_LABEL(sys_ni_syscall), C_LABEL(sys_mknod)
+       .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sys_brk)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_lseek), C_LABEL(sys_getpid)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_setuid)
+       .long C_LABEL(sys_getuid), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_alarm), C_LABEL(sys_ni_syscall), C_LABEL(sys_pause)
+       .long C_LABEL(sys_utime), C_LABEL(sys_stty), C_LABEL(sys_gtty)
+       .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_ftime)
+       .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
+       .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_profil)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid)
+       .long C_LABEL(sys_signal), C_LABEL(sys_geteuid)
+/*50*/ .long C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ioctl), C_LABEL(sys_reboot)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
+       .long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
+       .long C_LABEL(sys_newfstat), C_LABEL(sys_ni_syscall), C_LABEL(sys_getpagesize)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_vfork), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sunos_mmap), C_LABEL(sys_ni_syscall), C_LABEL(sys_munmap)
+       .long C_LABEL(sys_mprotect), C_LABEL(sys_ni_syscall), C_LABEL(sys_vhangup)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_getgroups)
+       .long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_setitimer), C_LABEL(sys_ni_syscall), C_LABEL(sys_swapon)
+       .long C_LABEL(sys_getitimer), C_LABEL(sys_ni_syscall), C_LABEL(sys_sethostname)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_dup2), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+/*100*/        .long C_LABEL(sys_getpriority), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
+       .long C_LABEL(sys_fchmod), C_LABEL(sys_ni_syscall), C_LABEL(sys_setreuid)
+       .long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
+       .long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_getrlimit)
+       .long C_LABEL(sys_setrlimit), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+/*150*/        .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
+       .long C_LABEL(sys_umount), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_setdomainname)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_getdents), C_LABEL(sys_setsid)
+       .long C_LABEL(sys_fchdir), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_sigpending), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_setpgid), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_uname), C_LABEL(sys_init_module)
+       .long C_LABEL(sys_personality), C_LABEL(sys_prof), C_LABEL(sys_break)
+       .long C_LABEL(sys_lock), C_LABEL(sys_mpx), C_LABEL(sys_ulimit)
+       .long C_LABEL(sys_getppid), C_LABEL(sys_sigaction), C_LABEL(sys_sgetmask)
+/*200*/        .long C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat)
+       .long C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_olduname)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_idle), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo)
+       .long C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_adjtimex), C_LABEL(sys_sigprocmask)
+       .long C_LABEL(sys_create_module), C_LABEL(sys_delete_module)
+       .long C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush)
+       .long C_LABEL(sys_sysfs), C_LABEL(sys_ni_syscall), C_LABEL(sys_setfsuid)
+       .long C_LABEL(sys_setfsgid), C_LABEL(sys_llseek), C_LABEL(sys_time)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_stime), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_llseek)
        /* "We are the Knights of the Forest of Ni!!" */
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
        .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 240 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 245 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 250 */
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)
-       .long C_LABEL(sys_ni_syscall)           /* 255 */
+/*250*/        .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+       .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
 
        /* Now the SunOS syscall table. */
 
        .align 4
        .globl C_LABEL(sunos_sys_table)
 C_LABEL(sunos_sys_table):
-       .long C_LABEL(sunos_indir)              /* so stupid... */
-       .long C_LABEL(sys_exit)
-       .long C_LABEL(sys_fork)
-       .long C_LABEL(sys_read)
-       .long C_LABEL(sys_write)
-       .long C_LABEL(sys_open)                 /* 5 */
-       .long C_LABEL(sys_close)
-       .long C_LABEL(sunos_wait4)              /* broken... */
-       .long C_LABEL(sys_creat)
-       .long C_LABEL(sys_link)
-       .long C_LABEL(sys_unlink)               /* 10 */
-       .long C_LABEL(sunos_execv)
-       .long C_LABEL(sys_chdir)
-       .long C_LABEL(sunos_nosys)              /* Obsolete sys_time(), unused */
-       .long C_LABEL(sys_mknod)
-       .long C_LABEL(sys_chmod)                /* 15 */
-       .long C_LABEL(sys_chown)
-       .long C_LABEL(sunos_brk)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_lseek)
-       .long C_LABEL(sunos_getpid)             /* 20 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_getuid)
-       .long C_LABEL(sunos_nosys)              /* 25 */
-       .long C_LABEL(sunos_nosys)              /* this will be sys_ptrace() */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* Old SunOS fstat, unsupported */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 30 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_access)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 35 */
-       .long C_LABEL(sys_sync)
-       .long C_LABEL(sys_kill)
-       .long C_LABEL(sys_newstat)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_newlstat)             /* 40 */
-       .long C_LABEL(sys_dup)
-       .long C_LABEL(sys_pipe)
-       .long C_LABEL(sunos_nosys)              /* SunOS sys_times() */
-       .long C_LABEL(sys_profil)
-       .long C_LABEL(sunos_nosys)              /* 45 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_getgid)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 50 */
-       .long C_LABEL(sys_acct)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_mctl)
-       .long C_LABEL(sunos_ioctl)
-       .long C_LABEL(sys_reboot)               /* 55 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_symlink)
-       .long C_LABEL(sys_readlink)
-       .long C_LABEL(sys_execve)
-       .long C_LABEL(sys_umask)                /* 60 */
-       .long C_LABEL(sys_chroot)
-       .long C_LABEL(sys_newfstat)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_getpagesize)
-       .long C_LABEL(sunos_msync)              /* 65 */
-       .long C_LABEL(sys_vfork)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_sbrk)
-       .long C_LABEL(sunos_sstk)               /* 70 */
-       .long C_LABEL(sunos_mmap)
-       .long C_LABEL(sunos_vadvise)
-       .long C_LABEL(sys_munmap)
-       .long C_LABEL(sys_mprotect)
-       .long C_LABEL(sunos_madvise)            /* 75 */
-       .long C_LABEL(sys_vhangup)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_mincore)
-       .long C_LABEL(sys_getgroups)
-       .long C_LABEL(sys_setgroups)            /* 80 */
-       .long C_LABEL(sys_getpgrp)
-       .long C_LABEL(sunos_setpgrp)
-       .long C_LABEL(sys_setitimer)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_swapon)               /* 85 */
-       .long C_LABEL(sys_getitimer)
-       .long C_LABEL(sys_gethostname)
-       .long C_LABEL(sys_sethostname)
-       .long C_LABEL(sunos_getdtablesize)
-       .long C_LABEL(sys_dup2)                 /* 90 */
-       .long C_LABEL(sunos_nop)                /* getdopt() does nothing */
-       .long C_LABEL(sys_fcntl)
-       .long C_LABEL(sys_select)
-       .long C_LABEL(sunos_nop)                /* setdopt() also does nothing */
-       .long C_LABEL(sys_fsync)                /* 95 */
-       .long C_LABEL(sys_setpriority)
-       .long C_LABEL(sys_socket)
-       .long C_LABEL(sys_connect)
-       .long C_LABEL(sys_accept)
-       .long C_LABEL(sys_getpriority)          /* 100 */
-       .long C_LABEL(sys_send)
-       .long C_LABEL(sys_recv)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_bind)
-       .long C_LABEL(sys_setsockopt)           /* 105 */
-       .long C_LABEL(sys_listen)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_sigaction)            /* sigvec */
-       .long C_LABEL(sunos_sigblock)           /* sigblock */
-       .long C_LABEL(sys_ssetmask)             /* sigsetmask -- 110 */
-       .long C_LABEL(sys_sigpause)             /* sigpause */
-       .long C_LABEL(sys_sigstack)             /* sigstack */
-       .long C_LABEL(sunos_nosys)              /* recvmsg */
-       .long C_LABEL(sunos_nosys)              /* sendmsg */
-       .long C_LABEL(sunos_nosys)              /* vtrace -- 115 */
-       .long C_LABEL(sys_gettimeofday)
-       .long C_LABEL(sys_getrusage)
-       .long C_LABEL(sys_getsockopt)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_readv)                /* 120 */
-       .long C_LABEL(sys_writev)
-       .long C_LABEL(sys_settimeofday)
-       .long C_LABEL(sys_fchown)
-       .long C_LABEL(sys_fchmod)
-       .long C_LABEL(sys_recvfrom)             /* recvfrom -- 125 */
-       .long C_LABEL(sys_setreuid)
-       .long C_LABEL(sys_setregid)
-       .long C_LABEL(sys_rename)
-       .long C_LABEL(sys_truncate)
-       .long C_LABEL(sys_ftruncate)            /* 130 */
-       .long C_LABEL(sys_flock)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_sendto)               /* sendto */
-       .long C_LABEL(sys_shutdown)             /* shutdown */
-       .long C_LABEL(sunos_nosys)              /* socketpair -- 135 */
-       .long C_LABEL(sys_mkdir)
-       .long C_LABEL(sys_rmdir)
-       .long C_LABEL(sys_utimes)               /* utimes */
-       .long C_LABEL(sys_sigreturn)
-       .long C_LABEL(sunos_nosys)              /* adjtime -- 140 */
-       .long C_LABEL(sys_getpeername)          /* getpeername */
-       .long C_LABEL(sunos_nosys)              /* gethostid */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_getrlimit)
-       .long C_LABEL(sys_setrlimit)            /* 145 */
-       .long C_LABEL(sunos_killpg)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_getsockname)          /* getsockname -- 150 */
-       .long C_LABEL(sunos_nosys)              /* getmsg */
-       .long C_LABEL(sunos_nosys)              /* putmsg */
-       .long C_LABEL(sunos_nosys)              /* poll */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* nfssvc -- 155 */
-       .long C_LABEL(sunos_nosys)              /* getdirectries */
-       .long C_LABEL(sys_statfs)
-       .long C_LABEL(sys_fstatfs)
-       .long C_LABEL(sys_umount)
-       .long C_LABEL(sunos_nosys)              /* async_daemon -- 160 */
-       .long C_LABEL(sunos_nosys)              /* getfh */
-       .long C_LABEL(sunos_getdomainname)      /* getdomainname */
-       .long C_LABEL(sys_setdomainname)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* quotactl -- 165 */
-       .long C_LABEL(sunos_nosys)              /* exportfs */
-       .long C_LABEL(sunos_mount)
-       .long C_LABEL(sys_ustat)
-       .long C_LABEL(sunos_nosys)              /* semsys */
-       .long C_LABEL(sunos_nosys)              /* msgsys -- 170 */
-       .long C_LABEL(sunos_nosys)              /* shmsys */
-       .long C_LABEL(sunos_audit)              /* auditsys */
-       .long C_LABEL(sunos_nosys)              /* rfssys */
-       .long C_LABEL(sunos_getdents)
-       .long C_LABEL(sys_setsid)               /* 175 */
-       .long C_LABEL(sys_fchdir)
-       .long C_LABEL(sunos_nosys)              /* fchroot */
-       .long C_LABEL(sunos_nosys)              /* vpixsys ???XXX */
-       .long C_LABEL(sunos_nosys)              /* aioread */
-       .long C_LABEL(sunos_nosys)              /* aiowrite -- 180 */
-       .long C_LABEL(sunos_nosys)              /* aiowait */
-       .long C_LABEL(sunos_nosys)              /* aiocancel */
-       .long C_LABEL(sys_sigpending)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_setpgid)              /* 185 */
-       .long C_LABEL(sunos_pathconf)           /* pathconf */
-       .long C_LABEL(sunos_fpathconf)          /* fpathconf */
-       .long C_LABEL(sunos_nosys)              /* sysconf */
-       .long C_LABEL(sunos_uname)
-       .long C_LABEL(sunos_nosys)              /* 190 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 195 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 200 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 205 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 210 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 215 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 220 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 225 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 230 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 235 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 240 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 245 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 250 */
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys)              /* 255 */
+/*0*/  .long C_LABEL(sunos_indir), C_LABEL(sys_exit), C_LABEL(sys_fork)
+       .long C_LABEL(sys_read), C_LABEL(sys_write), C_LABEL(sys_open)
+       .long C_LABEL(sys_close), C_LABEL(sunos_wait4), C_LABEL(sys_creat)
+       .long C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv)
+       .long C_LABEL(sys_chdir), C_LABEL(sunos_nosys), C_LABEL(sys_mknod)
+       .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sunos_brk)
+       .long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), LOWSYS(sunosgetpid)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long LOWSYS(sunosgetuid), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
+       .long C_LABEL(sunos_nosys), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
+       .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sys_profil)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), LOWSYS(sunosgetgid)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+/*50*/ .long C_LABEL(sunos_nosys), C_LABEL(sys_acct), C_LABEL(sunos_nosys)
+       .long LOWSYS(sunosmctl), C_LABEL(sunos_ioctl), C_LABEL(sys_reboot)
+       .long C_LABEL(sunos_nosys), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
+       .long C_LABEL(sys_execve), LOWSYS(umask), C_LABEL(sys_chroot)
+       .long C_LABEL(sys_newfstat), C_LABEL(sunos_nosys), LOWSYS(getpagesize)
+       .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_sbrk), C_LABEL(sunos_sstk)
+       .long C_LABEL(sunos_mmap), C_LABEL(sunos_vadvise), C_LABEL(sys_munmap)
+       .long C_LABEL(sys_mprotect), C_LABEL(sunos_madvise), C_LABEL(sys_vhangup)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_mincore), C_LABEL(sys_getgroups)
+       .long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sunos_setpgrp)
+       .long C_LABEL(sys_setitimer), C_LABEL(sunos_nosys), C_LABEL(sys_swapon)
+       .long C_LABEL(sys_getitimer), C_LABEL(sys_gethostname), C_LABEL(sys_sethostname)
+       .long LOWSYS(sunosgdtsize), C_LABEL(sys_dup2), LOWSYS(sunosnop)
+       .long C_LABEL(sys_fcntl), C_LABEL(sunos_select), LOWSYS(sunosnop)
+       .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_socket)
+       .long C_LABEL(sys_connect), C_LABEL(sys_accept)
+/*100*/        .long C_LABEL(sys_getpriority), C_LABEL(sys_send), C_LABEL(sys_recv)
+       .long C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sys_setsockopt)
+       .long C_LABEL(sys_listen), C_LABEL(sunos_nosys), C_LABEL(sys_sigaction)
+       .long LOWSYS(sunossblock), LOWSYS(sunossmask), C_LABEL(sys_sigpause)
+       .long C_LABEL(sys_sigstack), C_LABEL(sys_recvmsg), C_LABEL(sys_sendmsg)
+       .long C_LABEL(sunos_nosys), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
+       .long C_LABEL(sys_getsockopt), C_LABEL(sunos_nosys), C_LABEL(sys_readv)
+       .long C_LABEL(sys_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
+       .long C_LABEL(sys_fchmod), C_LABEL(sys_recvfrom), C_LABEL(sys_setreuid)
+       .long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
+       .long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sunos_nosys)
+       .long C_LABEL(sys_sendto), C_LABEL(sys_shutdown), C_LABEL(sys_socketpair)
+       .long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_utimes)
+       .long C_LABEL(sys_sigreturn), C_LABEL(sunos_nosys), C_LABEL(sys_getpeername)
+       .long C_LABEL(sunos_gethostid), C_LABEL(sunos_nosys), C_LABEL(sys_getrlimit)
+       .long C_LABEL(sys_setrlimit), C_LABEL(sunos_killpg), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+/*150*/        .long C_LABEL(sys_getsockname), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_getdirentries), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
+       .long C_LABEL(sys_umount), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname)
+       .long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_audit)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
+       .long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sys_sigpending), C_LABEL(sunos_nosys)
+       .long C_LABEL(sys_setpgid), C_LABEL(sunos_pathconf), C_LABEL(sunos_fpathconf)
+       .long C_LABEL(sunos_sysconf), C_LABEL(sunos_uname), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+/*200*/        .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+/*250*/        .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+
+       /* {net, open}bsd system call table. */
+
+       .align  4
+       .globl  C_LABEL(bsd_sys_table)
+C_LABEL(bsd_sys_table):
+       .long C_LABEL(sunos_nosys)/*SYSCALL*/, C_LABEL(sunos_nosys)/*EXIT*/
+       .long C_LABEL(sunos_nosys)/*FORK*/, C_LABEL(sunos_nosys)/*READ*/
+       .long C_LABEL(sunos_nosys)/*WRITE*/, C_LABEL(sunos_nosys)/*OPEN*/
+       .long C_LABEL(sunos_nosys)/*CLOSE*/, C_LABEL(sunos_nosys)/*WAIT4*/
+       .long C_LABEL(sunos_nosys)/*CREAT*/, C_LABEL(sunos_nosys)/*LINK*/
+       .long C_LABEL(sunos_nosys)/*UNLINK*/, C_LABEL(sunos_nosys)/*EXECV*/
+       .long C_LABEL(sunos_nosys)/*CHDIR*/, C_LABEL(sunos_nosys)/*FCHDIR*/
+       .long C_LABEL(sunos_nosys)/*MKNOD*/, C_LABEL(sunos_nosys)/*CHMOD*/
+       .long C_LABEL(sunos_nosys)/*CHOWN*/, C_LABEL(sunos_nosys)/*BREAK*/
+       .long C_LABEL(sunos_nosys)/*GETFSSTAT*/, C_LABEL(sunos_nosys)/*OLSEEK*/
+       .long C_LABEL(sunos_nosys)/*GETPID*/, C_LABEL(sunos_nosys)/*MOUNT*/
+       .long C_LABEL(sunos_nosys)/*UNMOUNT*/, C_LABEL(sunos_nosys)/*SETUID*/
+       .long C_LABEL(sunos_nosys)/*GETUID*/, C_LABEL(sunos_nosys)/*GETEUID*/
+       .long C_LABEL(sunos_nosys)/*PTRACE*/, C_LABEL(sunos_nosys)/*RECVMSG*/
+       .long C_LABEL(sunos_nosys)/*SENDMSG*/, C_LABEL(sunos_nosys)/*RECVFROM*/
+       .long C_LABEL(sunos_nosys)/*ACCEPT*/, C_LABEL(sunos_nosys)/*GETPEERNAME*/
+       .long C_LABEL(sunos_nosys)/*GETSOCKNAME*/, C_LABEL(sunos_nosys)/*ACCESS*/
+       .long C_LABEL(sunos_nosys)/*CHFLAGS*/, C_LABEL(sunos_nosys)/*FCHFLAGS*/
+       .long C_LABEL(sunos_nosys)/*SYNC*/, C_LABEL(sunos_nosys)/*KILL*/
+       .long C_LABEL(sunos_nosys)/*OSTAT*/, C_LABEL(sunos_nosys)/*GETPPID*/
+       .long C_LABEL(sunos_nosys)/*OLSTAT*/, C_LABEL(sunos_nosys)/*DUP*/
+       .long C_LABEL(sunos_nosys)/*PIPE*/, C_LABEL(sunos_nosys)/*GETEGID*/
+       .long C_LABEL(sunos_nosys)/*PROFIL*/, C_LABEL(sunos_nosys)/*KTRACE*/
+       .long C_LABEL(sunos_nosys)/*SIGACTION*/, C_LABEL(sunos_nosys)/*GETGID*/
+       .long C_LABEL(sunos_nosys)/*SIGPROCMASK*/, C_LABEL(sunos_nosys)/*GETLOGIN*/
+       .long C_LABEL(sunos_nosys)/*SETLOGIN*/, C_LABEL(sunos_nosys)/*ACCT*/
+       .long C_LABEL(sunos_nosys)/*SIGPENDING*/, C_LABEL(sunos_nosys)/*SIGALTSTACK*/
+       .long C_LABEL(sunos_nosys)/*IOCTL*/, C_LABEL(sunos_nosys)/*REBOOT*/
+       .long C_LABEL(sunos_nosys)/*REVOKE*/, C_LABEL(sunos_nosys)/*SYMLINK*/
+       .long C_LABEL(sunos_nosys)/*READLINK*/, C_LABEL(sunos_nosys)/*EXECVE*/
+       .long C_LABEL(sunos_nosys)/*UMASK*/, C_LABEL(sunos_nosys)/*CHROOT*/
+       .long C_LABEL(sunos_nosys)/*OFSTAT*/, C_LABEL(sunos_nosys)/*OGETKERNINFO*/
+       .long C_LABEL(sunos_nosys)/*OGETPAGESIZE*/, C_LABEL(sunos_nosys)/*MSYNC*/
+       .long C_LABEL(sunos_nosys)/*VFORK*/, C_LABEL(sunos_nosys)/*VREAD*/
+       .long C_LABEL(sunos_nosys)/*VWRITE*/, C_LABEL(sunos_nosys)/*SBRK*/
+       .long C_LABEL(sunos_nosys)/*SSTK*/, C_LABEL(sunos_nosys)/*OMMAP*/
+       .long C_LABEL(sunos_nosys)/*VADVISE*/, C_LABEL(sunos_nosys)/*MUNMAP*/
+       .long C_LABEL(sunos_nosys)/*MPROTECT*/, C_LABEL(sunos_nosys)/*MADVISE*/
+       .long C_LABEL(sunos_nosys)/*VHANGUP*/, C_LABEL(sunos_nosys)/*VLIMIT*/
+       .long C_LABEL(sunos_nosys)/*MINCORE*/, C_LABEL(sunos_nosys)/*GETGROUPS*/
+       .long C_LABEL(sunos_nosys)/*SETGROUPS*/, C_LABEL(sunos_nosys)/*GETPGRP*/
+       .long C_LABEL(sunos_nosys)/*SETPGID*/, C_LABEL(sunos_nosys)/*SETITIMER*/
+       .long C_LABEL(sunos_nosys)/*OWAIT*/, C_LABEL(sunos_nosys)/*SWAPON*/
+       .long C_LABEL(sunos_nosys)/*GETITIMER*/, C_LABEL(sunos_nosys)/*OGETHOSTNAME*/
+       .long C_LABEL(sunos_nosys)/*OSETHOSTNAME*/, C_LABEL(sunos_nosys)/*OGETDTABLESIZE*/
+       .long C_LABEL(sunos_nosys)/*DUP2*/, C_LABEL(sunos_nosys)/*GETDOPT*/
+       .long C_LABEL(sunos_nosys)/*FCNTL*/, C_LABEL(sunos_nosys)/*SELECT*/
+       .long C_LABEL(sunos_nosys)/*SETDOPT*/, C_LABEL(sunos_nosys)/*FSYNC*/
+       .long C_LABEL(sunos_nosys)/*SETPRIORITY*/, C_LABEL(sunos_nosys)/*SOCKET*/
+       .long C_LABEL(sunos_nosys)/*CONNECT*/, C_LABEL(sunos_nosys)/*OACCEPT*/
+       .long C_LABEL(sunos_nosys)/*GETPRIORITY*/, C_LABEL(sunos_nosys)/*OSEND*/
+       .long C_LABEL(sunos_nosys)/*ORECV*/, C_LABEL(sunos_nosys)/*SIGRETURN*/
+       .long C_LABEL(sunos_nosys)/*BIND*/, C_LABEL(sunos_nosys)/*SETSOCKOPT*/
+       .long C_LABEL(sunos_nosys)/*LISTEN*/, C_LABEL(sunos_nosys)/*VTIMES*/
+       .long C_LABEL(sunos_nosys)/*OSIGVEC*/, C_LABEL(sunos_nosys)/*OSIGBLOCK*/
+       .long C_LABEL(sunos_nosys)/*OSIGSETMASK*/, C_LABEL(sunos_nosys)/*SIGSUSPEND*/
+       .long C_LABEL(sunos_nosys)/*OSIGSTACK*/, C_LABEL(sunos_nosys)/*ORECVMSG*/
+       .long C_LABEL(sunos_nosys)/*OSENDMSG*/, C_LABEL(sunos_nosys)/*VTRACE*/
+       .long C_LABEL(sunos_nosys)/*GETTIMEOFDAY*/, C_LABEL(sunos_nosys)/*GETRUSAGE*/
+       .long C_LABEL(sunos_nosys)/*GETSOCKOPT*/, C_LABEL(sunos_nosys)/*ORESUBA*/
+       .long C_LABEL(sunos_nosys)/*READV*/, C_LABEL(sunos_nosys)/*WRITEV*/
+       .long C_LABEL(sunos_nosys)/*SETTIMEOFDAY*/, C_LABEL(sunos_nosys)/*FCHOWN*/
+       .long C_LABEL(sunos_nosys)/*FCHMOD*/, C_LABEL(sunos_nosys)/*ORECVFROM*/
+       .long C_LABEL(sunos_nosys)/*OSETREUID*/, C_LABEL(sunos_nosys)/*OSETREGID*/
+       .long C_LABEL(sunos_nosys)/*RENAME*/, C_LABEL(sunos_nosys)/*OTRUNCATE*/
+       .long C_LABEL(sunos_nosys)/*OFTRUNCATE*/, C_LABEL(sunos_nosys)/*FLOCK*/
+       .long C_LABEL(sunos_nosys)/*MKFIFO*/, C_LABEL(sunos_nosys)/*SENDTO*/
+       .long C_LABEL(sunos_nosys)/*SHUTDOWN*/, C_LABEL(sunos_nosys)/*SOCKETPAIR*/
+       .long C_LABEL(sunos_nosys)/*MKDIR*/, C_LABEL(sunos_nosys)/*RMDIR*/
+       .long C_LABEL(sunos_nosys)/*UTIMES*/, C_LABEL(sunos_nosys)/*OSIGRETURN*/
+       .long C_LABEL(sunos_nosys)/*ADJTIME*/, C_LABEL(sunos_nosys)/*OGETPEERNAME*/
+       .long C_LABEL(sunos_nosys)/*OGETHOSTID*/, C_LABEL(sunos_nosys)/*OSETHOSTID*/
+       .long C_LABEL(sunos_nosys)/*OGETRLIMIT*/, C_LABEL(sunos_nosys)/*OSETRLIMIT*/
+       .long C_LABEL(sunos_nosys)/*OKILLPG*/, C_LABEL(sunos_nosys)/*SETSID*/
+       .long C_LABEL(sunos_nosys)/*QUOTACTL*/, C_LABEL(sunos_nosys)/*OQUOTA*/
+       .long C_LABEL(sunos_nosys)/*OGETSOCKNAME*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NFSSVC*/
+       .long C_LABEL(sunos_nosys)/*OGETDIRENTRIES*/, C_LABEL(sunos_nosys)/*STATFS*/
+       .long C_LABEL(sunos_nosys)/*FSTATFS*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*GETFH*/
+       .long C_LABEL(sunos_nosys)/*OGETDOMAINNAME*/
+       .long C_LABEL(sunos_nosys)/*OSETDOMAINNAME*/
+       .long C_LABEL(sunos_nosys)/*OUNAME*/, C_LABEL(sunos_nosys)/*SYSARCH*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*OSEMSYS*/
+       .long C_LABEL(sunos_nosys)/*OMSGSYS*/, C_LABEL(sunos_nosys)/*OSHMSYS*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*SETGID*/
+       .long C_LABEL(sunos_nosys)/*SETEGID*/, C_LABEL(sunos_nosys)/*SETEUID*/
+       .long C_LABEL(sunos_nosys)/*LFS_BMAPV*/, C_LABEL(sunos_nosys)/*LFS_MARKV*/
+       .long C_LABEL(sunos_nosys)/*LFS_SEGCLEAN*/, C_LABEL(sunos_nosys)/*LFS_SEGWAIT*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*STAT*/, C_LABEL(sunos_nosys)/*FSTAT*/
+       .long C_LABEL(sunos_nosys)/*LSTAT*/, C_LABEL(sunos_nosys)/*PATHCONF*/
+       .long C_LABEL(sunos_nosys)/*FPATHCONF*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*GETRLIMIT*/, C_LABEL(sunos_nosys)/*SETRLIMIT*/
+       .long C_LABEL(sunos_nosys)/*GETDIRENTRIES*/, C_LABEL(sunos_nosys)/*MMAP*/
+       .long C_LABEL(sunos_nosys)/*__SYSCALL*/, C_LABEL(sunos_nosys)/*LSEEK*/
+       .long C_LABEL(sunos_nosys)/*TRUNCATE*/, C_LABEL(sunos_nosys)/*FTRUNCATE*/
+       .long C_LABEL(sunos_nosys)/*__SYSCTL*/, C_LABEL(sunos_nosys)/*MLOCK*/
+       .long C_LABEL(sunos_nosys)/*MUNLOCK*/, C_LABEL(sunos_nosys)/*UNDELETE*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+       .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+       .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+       .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+       .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*__SEMCTL*/, C_LABEL(sunos_nosys)/*SEMGET*/
+       .long C_LABEL(sunos_nosys)/*SEMOP*/, C_LABEL(sunos_nosys)/*SEMCONFIG*/
+       .long C_LABEL(sunos_nosys)/*MSGCTL*/, C_LABEL(sunos_nosys)/*MSGGET*/
+       .long C_LABEL(sunos_nosys)/*MSGSND*/, C_LABEL(sunos_nosys)/*MSGRCV*/
+       .long C_LABEL(sunos_nosys)/*SHMAT*/, C_LABEL(sunos_nosys)/*SHMCTL*/
+       .long C_LABEL(sunos_nosys)/*SHMDT*/, C_LABEL(sunos_nosys)/*SHMGET*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+       .long C_LABEL(sunos_nosys)/*MINHERIT*/, C_LABEL(sunos_nosys)/*RFORK*/
+
+       /* One thing left, Solaris syscall table, TODO */
index a2b510e0aadb6b504169a315b17aec547496fe8d..ace139ffc18c0d1f563d6f9b74e00e47fdbcd9f7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.4 1995/11/25 03:29:31 davem Exp $
+/* $Id: time.c,v 1.7 1996/03/01 07:16:05 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/segment.h>
 #include <asm/timer.h>
 #include <asm/mostek.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
 
 #define TIMER_IRQ  10    /* Also at level 14, but we ignore that one. */
 
+enum sparc_clock_type sp_clock_typ;
+struct mostek48t02 *mstk48t02_regs = 0;
+struct mostek48t08 *mstk48t08_regs = 0;
+volatile unsigned int *master_l10_limit = 0;
+volatile unsigned int *master_l10_counter = 0;
+struct sun4m_timer_regs *sun4m_timers;
+
 static int set_rtc_mmss(unsigned long);
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-void timer_interrupt(int irq, struct pt_regs * regs)
+void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
        /* last time the cmos clock got updated */
        static long last_rtc_update=0;
@@ -78,6 +88,141 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon,
          )*60 + sec; /* finally seconds */
 }
 
+/* Clock probing, we probe the timers here also. */
+volatile unsigned int foo_limit;
+
+static void clock_probe(void)
+{
+       char node_str[128];
+       register int node, type;
+       struct linux_prom_registers clk_reg[2];
+
+       /* This will basically traverse the node-tree of the prom to see
+        * which timer chip is on this machine.
+        */
+
+       node = 0;
+       if(sparc_cpu_model == sun4) {
+               printk("clock_probe: No SUN4 Clock/Timer support yet...\n");
+               return;
+       }
+       if(sparc_cpu_model == sun4c) node=prom_getchild(prom_root_node);
+       else
+               if(sparc_cpu_model == sun4m)
+                       node=prom_getchild(prom_searchsiblings(prom_getchild(prom_root_node), "obio"));
+       type = 0;
+       sp_clock_typ = MSTK_INVALID;
+       for(;;) {
+               prom_getstring(node, "model", node_str, sizeof(node_str));
+               if(strcmp(node_str, "mk48t02") == 0) {
+                       sp_clock_typ = MSTK48T02;
+                       if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) {
+                               printk("clock_probe: FAILED!\n");
+                               halt();
+                       }
+                       prom_apply_obio_ranges(clk_reg, 1);
+                       /* Map the clock register io area read-only */
+                       mstk48t02_regs = (struct mostek48t02 *) 
+                               sparc_alloc_io((void *) clk_reg[0].phys_addr,
+                                              (void *) 0, sizeof(*mstk48t02_regs),
+                                              "clock", clk_reg[0].which_io, 0x0);
+                       mstk48t08_regs = 0;  /* To catch weirdness */
+                       break;
+               }
+
+               if(strcmp(node_str, "mk48t08") == 0) {
+                       sp_clock_typ = MSTK48T08;
+                       if(prom_getproperty(node, "reg", (char *) clk_reg,
+                                           sizeof(clk_reg)) == -1) {
+                               printk("clock_probe: FAILED!\n");
+                               halt();
+                       }
+                       prom_apply_obio_ranges(clk_reg, 1);
+                       /* Map the clock register io area read-only */
+                       mstk48t08_regs = (struct mostek48t08 *)
+                               sparc_alloc_io((void *) clk_reg[0].phys_addr,
+                                              (void *) 0, sizeof(*mstk48t08_regs),
+                                              "clock", clk_reg[0].which_io, 0x0);
+
+                       mstk48t02_regs = &mstk48t08_regs->regs;
+                       break;
+               }
+
+               node = prom_getsibling(node);
+               if(node == 0) {
+                       printk("Aieee, could not find timer chip type\n");
+                       return;
+               }
+       }
+
+       if(sparc_cpu_model == sun4c) {
+               /* Map the Timer chip, this is implemented in hardware inside
+                * the cache chip on the sun4c.
+                */
+               sun4c_timers = sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, 0,
+                                              sizeof(struct sun4c_timer_info),
+                                              "timer", 0x0, 0x0);
+
+               /* Have the level 10 timer tick at 100HZ.  We don't touch the
+                * level 14 timer limit since we are letting the prom handle
+                * them until we have a real console driver so L1-A works.
+                */
+               sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10);
+               master_l10_limit = &(sun4c_timers->timer_limit10);
+               master_l10_counter = &(sun4c_timers->cur_count10);
+       } else {
+               /* XXX FIx this SHIT... UP and MP sun4m configurations
+                * XXX have completely different layouts for the counter
+                * XXX registers. AIEEE!!!
+                */
+
+               int reg_count;
+               struct linux_prom_registers cnt_regs[PROMREG_MAX];
+               volatile unsigned long *real_limit;
+               int obio_node, cnt_node;
+
+               cnt_node = 0;
+               if((obio_node =
+                   prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
+                  (obio_node = prom_getchild (obio_node)) == 0 ||
+                  (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
+                       prom_printf("Cannot find /obio/counter node\n");
+                       prom_halt();
+               }
+               reg_count = prom_getproperty(cnt_node, "reg",
+                                            (void *) cnt_regs, sizeof(cnt_regs));
+               reg_count = (reg_count/sizeof(struct linux_prom_registers));
+
+               /* Apply the obio ranges to the timer registers. */
+               prom_apply_obio_ranges(cnt_regs, reg_count);
+
+               /* Map the per-cpu Counter registers. */
+               sparc_alloc_io(cnt_regs[0].phys_addr, 0,
+                              PAGE_SIZE*NCPUS, "counters_percpu",
+                              cnt_regs[0].which_io, 0x0);
+
+               /* Map the system Counter register. */
+               sun4m_timers = sparc_alloc_io(cnt_regs[reg_count-1].phys_addr, 0,
+                                             cnt_regs[reg_count-1].reg_size,
+                                             "counters_system",
+                                             cnt_regs[reg_count-1].which_io, 0x0);
+
+               real_limit = &sun4m_timers->l10_timer_limit;
+               if(reg_count < 4) {
+                       /* Uniprocessor timers, ugh. */
+                       real_limit = (volatile unsigned long *) sun4m_timers;
+               }
+
+               /* Avoid interrupt bombs... */
+               foo_limit = (volatile) *real_limit;
+
+               /* Must set the master pointer first or we will lose badly. */
+               master_l10_limit = real_limit;
+               master_l10_counter = real_limit + 1;
+               *master_l10_limit =  (((1000000/HZ) + 1) << 10);
+       }
+}
+
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
 #endif
@@ -91,7 +236,9 @@ void time_init(void)
        unsigned int year, mon, day, hour, min, sec;
        struct mostek48t02 *mregs;
 
-       request_irq(TIMER_IRQ, timer_interrupt, SA_INTERRUPT, "timer");
+       clock_probe();
+       /*      request_irq(TIMER_IRQ, timer_interrupt, SA_INTERRUPT, "timer", NULL); */
+       enable_irq(TIMER_IRQ);
        mregs = mstk48t02_regs;
        if(!mregs) {
                prom_printf("Something wrong, clock regs not mapped yet.\n");
index a2dee849a648aed4442e217b13e539636fdb1d88..5736b70f6f28f8cedadbcdf768b6e957a13efabe 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.18 1995/11/25 00:58:47 davem Exp $
+/* $Id: traps.c,v 1.32 1996/03/01 07:16:08 davem Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -10,6 +10,7 @@
 
 #include <linux/sched.h>  /* for jiffies */
 #include <linux/kernel.h>
+#include <linux/signal.h>
 
 #include <asm/delay.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/mp.h>
 #include <asm/kdebug.h>
+#include <asm/unistd.h>
 
-void
-syscall_trace_entry(struct pt_regs *regs)
+struct trap_trace_entry {
+       unsigned long pc;
+       unsigned long type;
+};
+
+int trap_curbuf = 0;
+struct trap_trace_entry trapbuf[1024];
+
+void syscall_trace_entry(struct pt_regs *regs)
 {
-       printk("%s[%d]: sys[%d](%d, %d, %d, %d) ",
-              current->comm, current->pid,
-              regs->u_regs[UREG_G1], regs->u_regs[UREG_I0],
-              regs->u_regs[UREG_I1], regs->u_regs[UREG_I2],
-              regs->u_regs[UREG_I3]);
-       return;
+       printk("%s[%d]: ", current->comm, current->pid);
+       printk("scall<%d> (could be %d)\n", (int) regs->u_regs[UREG_G1],
+              (int) regs->u_regs[UREG_I0]);
 }
 
-void
-syscall_trace_exit(struct pt_regs *regs)
+void syscall_trace_exit(struct pt_regs *regs)
 {
-       printk("retvals[%d,%d] at pc<%08lx>\n",
-              regs->u_regs[UREG_I0], regs->u_regs[UREG_I1],
-              regs->pc, regs->npc);
-       return;
 }
 
-void
-do_cwp_assertion_failure(struct pt_regs *regs, unsigned long psr)
+void die_if_kernel(char *str, struct pt_regs *regs)
 {
-       printk("CWP return from trap assertion fails:\n");
-       printk("Current psr %08lx, new psr %08lx\n", psr, regs->psr);
+       unsigned long i;
+       unsigned long *pc;
+
+       if(regs->psr & PSR_PS)
+               do_exit(SIGKILL);
+       printk("%s(%d): %s\n", current->comm, current->pid, str);
        show_regs(regs);
-       panic("bogus CWP");
+       printk("Instruction DUMP:");
+       pc = (unsigned long *) regs->pc;
+       for(i = -3; i < 6; i++)
+               printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+       printk("\n");
+       do_exit(SIGSEGV);
 }
 
-void
-do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
+void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
 {
-
-  printk("Unimplemented Sparc TRAP, type = %02lx psr = %08lx pc = %08lx\n",
-        type, psr, pc);
-  halt();
-
-  return;
+       if(type < 0x80) {
+               /* Sun OS's puke from bad traps, Linux survives! */
+               printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
+               panic("Whee... Hello Mr. Penguin");
+       }       
+       current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80);
+       current->tss.sig_address = pc;
+       send_sig(SIGILL, current, 1);
 }
 
-void
-do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
+void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                           unsigned long psr)
 {
-       printk("Illegal instruction at PC %08lx NPC %08lx PSR %08lx\n",
-              pc, npc, psr);
        if(psr & PSR_PS)
-               panic("Kernel illegal instruction, how are ya!");
+               die_if_kernel("Kernel illegal instruction", regs);
        current->tss.sig_address = pc;
        current->tss.sig_desc = SUBSIG_ILLINST;
        send_sig(SIGILL, current, 1);
-       return;
 }
 
-void
-do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
+void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                        unsigned long psr)
 {
-       printk("Privileged instruction at PC %08lx NPC %08lx PSR %08lx\n",
-              pc, npc, psr);
+       if(psr & PSR_PS)
+               die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
        current->tss.sig_address = pc;
        current->tss.sig_desc = SUBSIG_PRIVINST;
        send_sig(SIGILL, current, 1);
-       return;
 }
 
 /* XXX User may want to be allowed to do this. XXX */
 
-void
-do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
+void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                           unsigned long psr)
 {
-       printk("Unaligned memory access at PC %08lx NPC %08lx PSR %08lx\n",
-              pc, npc, psr);
        if(regs->psr & PSR_PS)
-               panic("Kernel does unaligned memory access, yuck!");
+               die_if_kernel("Kernel MNA access", regs);
        current->tss.sig_address = pc;
        current->tss.sig_desc = SUBSIG_PRIVINST;
        send_sig(SIGBUS, current, 1);
-       return;
 }
 
-void
-do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
+extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
+                  void *fpqueue, unsigned long *fpqdepth);
+extern void fpload(unsigned long *fpregs, unsigned long *fsr);
+
+static unsigned long init_fsr = 0x0UL;
+static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
+                { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
+
+void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                unsigned long psr)
 {
        /* Sanity check... */
        if(psr & PSR_PS)
-               panic("FPE disabled trap from kernel, die die die...");
+               die_if_kernel("Kernel gets Penguin-FPU disabled trap", regs);
 
        put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
-       if(last_task_used_math == current) {
-               /* No state save necessary */
-               regs->psr |= PSR_EF;
+       regs->psr |= PSR_EF;
+       if(last_task_used_math == current)
                return;
-       }
        if(last_task_used_math) {
                /* Other processes fpu state, save away */
-               __asm__ __volatile__("st %%fsr, [%0]\n\t" : :
-                                    "r" (&current->tss.fsr) : "memory");
-
-               /* Save away the floating point queue if necessary. */
-               if(current->tss.fsr & 0x2000)
-                       __asm__ __volatile__("mov 0x0, %%g2\n\t"
-                                            "1: std %%fq, [%2 + %%g2]\n\t"
-                                            "st %%fsr, [%0]\n\t"
-                                            "ld [%0], %%g3\n\t"
-                                            "andcc %%g3, %1, %%g0\n\t"
-                                            "bne 1b\n\t"
-                                            "add %%g2, 0x8, %%g2\n\t"
-                                            "srl %%g2, 0x3, %%g2\n\t"
-                                            "st %%g2, [%3]\n\t" : :
-                                            "r" (&current->tss.fsr), "r" (0x2000),
-                                            "r" (&current->tss.fpqueue[0]),
-                                            "r" (&current->tss.fpqdepth) :
-                                            "g2", "g3", "memory");
-               else
-                       current->tss.fpqdepth = 0;
-
-               __asm__ __volatile__("std %%f0, [%0 + 0x00]\n\t"
-                                    "std %%f2, [%0 + 0x08]\n\t"
-                                    "std %%f4, [%0 + 0x10]\n\t"
-                                    "std %%f6, [%0 + 0x18]\n\t"
-                                    "std %%f8, [%0 + 0x20]\n\t"
-                                    "std %%f10, [%0 + 0x28]\n\t"
-                                    "std %%f12, [%0 + 0x30]\n\t"
-                                    "std %%f14, [%0 + 0x38]\n\t"
-                                    "std %%f16, [%0 + 0x40]\n\t"
-                                    "std %%f18, [%0 + 0x48]\n\t"
-                                    "std %%f20, [%0 + 0x50]\n\t"
-                                    "std %%f22, [%0 + 0x58]\n\t"
-                                    "std %%f24, [%0 + 0x60]\n\t"
-                                    "std %%f26, [%0 + 0x68]\n\t"
-                                    "std %%f28, [%0 + 0x70]\n\t"
-                                    "std %%f30, [%0 + 0x78]\n\t" : :
-                                    "r" (&current->tss.float_regs[0]) :
-                                    "memory");
+               struct task_struct *fptask = last_task_used_math;
+               fpsave(&fptask->tss.float_regs[0], &fptask->tss.fsr,
+                      &fptask->tss.fpqueue[0], &fptask->tss.fpqdepth);
        }
        last_task_used_math = current;
        if(current->used_math) {
-               /* Restore the old state. */
-               __asm__ __volatile__("ldd [%0 + 0x00], %%f0\n\t"
-                                    "ldd [%0 + 0x08], %%f2\n\t"
-                                    "ldd [%0 + 0x10], %%f4\n\t"
-                                    "ldd [%0 + 0x18], %%f6\n\t"
-                                    "ldd [%0 + 0x20], %%f8\n\t"
-                                    "ldd [%0 + 0x28], %%f10\n\t"
-                                    "ldd [%0 + 0x30], %%f12\n\t"
-                                    "ldd [%0 + 0x38], %%f14\n\t"
-                                    "ldd [%0 + 0x40], %%f16\n\t"
-                                    "ldd [%0 + 0x48], %%f18\n\t"
-                                    "ldd [%0 + 0x50], %%f20\n\t"
-                                    "ldd [%0 + 0x58], %%f22\n\t"
-                                    "ldd [%0 + 0x60], %%f24\n\t"
-                                    "ldd [%0 + 0x68], %%f26\n\t"
-                                    "ldd [%0 + 0x70], %%f28\n\t"
-                                    "ldd [%0 + 0x78], %%f30\n\t"
-                                    "ld  [%1], %%fsr\n\t" : :
-                                    "r" (&current->tss.float_regs[0]),
-                                    "r" (&current->tss.fsr));
+               fpload(&current->tss.float_regs[0], &current->tss.fsr);
        } else {
                /* Set initial sane state. */
-               auto unsigned long init_fsr = 0x0UL;
-               auto unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
-               { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
-                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
-                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
-                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
-               __asm__ __volatile__("ldd [%0 + 0x00], %%f0\n\t"
-                                    "ldd [%0 + 0x08], %%f2\n\t"
-                                    "ldd [%0 + 0x10], %%f4\n\t"
-                                    "ldd [%0 + 0x18], %%f6\n\t"
-                                    "ldd [%0 + 0x20], %%f8\n\t"
-                                    "ldd [%0 + 0x28], %%f10\n\t"
-                                    "ldd [%0 + 0x30], %%f12\n\t"
-                                    "ldd [%0 + 0x38], %%f14\n\t"
-                                    "ldd [%0 + 0x40], %%f16\n\t"
-                                    "ldd [%0 + 0x48], %%f18\n\t"
-                                    "ldd [%0 + 0x50], %%f20\n\t"
-                                    "ldd [%0 + 0x58], %%f22\n\t"
-                                    "ldd [%0 + 0x60], %%f24\n\t"
-                                    "ldd [%0 + 0x68], %%f26\n\t"
-                                    "ldd [%0 + 0x70], %%f28\n\t"
-                                    "ldd [%0 + 0x78], %%f30\n\t"
-                                    "ld  [%1], %%fsr\n\t" : :
-                                    "r" (&init_fregs[0]),
-                                    "r" (&init_fsr) : "memory");
+               fpload(&init_fregs[0], &init_fsr);
                current->used_math = 1;
        }
 }
 
-void
-do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
+static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
+static unsigned long fake_fsr;
+static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
+static unsigned long fake_depth;
+
+void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                unsigned long psr)
 {
-       if(psr & PSR_PS)
-               panic("FPE exception trap from kernel, die die die...");
-       /* XXX Do something real... XXX */
+       static calls = 0;
+       struct task_struct *fpt = last_task_used_math;
+
+       put_psr(get_psr() | PSR_EF);
+       /* If nobody owns the fpu right now, just clear the
+        * error into our fake static buffer and hope it don't
+        * happen again.  Thank you crashme...
+        */
+       if(!fpt) {
+               fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
+               regs->psr &= ~PSR_EF;
+               return;
+       }
+       fpsave(&fpt->tss.float_regs[0], &fpt->tss.fsr,
+              &fpt->tss.fpqueue[0], &fpt->tss.fpqdepth);
+       last_task_used_math->tss.sig_address = pc;
+       last_task_used_math->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */
+       if(psr & PSR_PS) {
+               /* The first fsr store/load we tried trapped,
+                * the second one will not (we hope).
+                */
+               printk("WARNING: FPU exception from kernel mode. at pc=%08lx\n",
+                      regs->pc);
+               regs->pc = regs->npc;
+               regs->npc += 4;
+               calls++;
+               if(calls > 2)
+                       die_if_kernel("Too many Penguin-FPU traps from kernel mode",
+                                     regs);
+               return;
+       }
+       send_sig(SIGFPE, last_task_used_math, 1);
+       last_task_used_math = NULL;
        regs->psr &= ~PSR_EF;
-       last_task_used_math = (struct task_struct *) 0;
-       current->tss.sig_address = pc;
-       current->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */
-       send_sig(SIGFPE, current, 1);
-       return;
+       if(calls > 0)
+               calls=0;
 }
 
-void
-handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
+void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                        unsigned long psr)
 {
-       printk("Tag overflow trap at PC %08lx NPC %08lx PSR %08lx\n",
-              pc, npc, psr);
        if(psr & PSR_PS)
-               panic("KERNEL tag overflow trap, wowza!");
+               die_if_kernel("Penguin overflow trap from kernel mode", regs);
        current->tss.sig_address = pc;
        current->tss.sig_desc = SUBSIG_TAG; /* as good as any */
        send_sig(SIGEMT, current, 1);
-       return;
 }
 
-void
-handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                       unsigned long psr)
 {
        printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
@@ -249,63 +204,44 @@ handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
        if(psr & PSR_PS)
                panic("Tell me what a watchpoint trap is, and I'll then deal "
                      "with such a beast...");
-       return;
 }
 
-void
-handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                       unsigned long psr)
 {
        printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
               pc, npc, psr);
-       halt();
-       return;
+       send_sig(SIGILL, current, 1);
 }
 
-void
-handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
+void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                       unsigned long psr)
 {
-       printk("Co-Processor disabled trap at PC %08lx NPC %08lx PSR %08lx\n",
-              pc, npc, psr);
-       halt();
-       return;
+       send_sig(SIGILL, current, 1);
 }
 
-void
-handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
+void handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                     unsigned long psr)
 {
        printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n",
               pc, npc, psr);
-       halt();
-       return;
+       send_sig(SIGILL, current, 1);
 }
 
-void
-handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
+void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                        unsigned long psr)
 {
        printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
               pc, npc, psr);
-       halt();
-       return;
+       send_sig(SIGILL, current, 1);
 }
 
-void
-handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                       unsigned long psr)
 {
        printk("Divide By Zero Exception at PC %08lx NPC %08lx PSR %08lx\n",
               pc, npc, psr);
-       halt();
-       return;
-}
-
-void do_ast(struct pt_regs *regs)
-{
-       panic("Don't know how to handle AST traps yet ;-(\n");
-       return;
+       send_sig(SIGILL, current, 1);
 }
 
 /* Since we have our mappings set up, on multiprocessors we can spin them
@@ -315,14 +251,13 @@ void do_ast(struct pt_regs *regs)
 extern void sparc_cpu_startup(void);
 
 extern int linux_num_cpus;
-extern pgd_t *lnx_root;
+extern pgd_t **srmmu_context_table;
 
 int linux_smp_still_initting;
 unsigned int thiscpus_tbr;
 int thiscpus_mid;
 
-void
-trap_init(void)
+void trap_init(void)
 {
        struct linux_prom_registers ctx_reg;
        int i;
@@ -341,7 +276,7 @@ trap_init(void)
               linux_num_cpus);
        linux_smp_still_initting = 1;
        ctx_reg.which_io = 0x0;  /* real ram */
-       ctx_reg.phys_addr = (char *) (((unsigned long) lnx_root) - PAGE_OFFSET);
+       ctx_reg.phys_addr = (char *) (((unsigned long) srmmu_context_table) - PAGE_OFFSET);
        ctx_reg.reg_size = 0x0;
        /* This basically takes every cpu, loads up our Linux context table
         * into it's context table pointer register, inits it at the low level
@@ -369,12 +304,4 @@ trap_init(void)
        }
 
        linux_smp_still_initting = 1;
-
-       return;
-}
-
-void
-die_if_kernel(char * str, struct pt_regs * regs, long err)
-{
-  return;
 }
diff --git a/arch/sparc/kernel/windows.c b/arch/sparc/kernel/windows.c
new file mode 100644 (file)
index 0000000..de15408
--- /dev/null
@@ -0,0 +1,108 @@
+/* windows.c: Routines to deal with register window management
+ *            at the C-code level.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+
+/* Do save's until all user register windows are out of the cpu. */
+void flush_user_windows(void)
+{
+       if(current->tss.uwinmask)
+               flush_user_windows();
+}
+
+static inline void shift_window_buffer(int first_win, int last_win, struct thread_struct *tp)
+{
+       int i;
+
+       for(i = first_win; i < last_win; i++) {
+               tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
+               memcpy(&tp->reg_window[i], &tp->reg_window[i+1], sizeof(struct reg_window));
+       }
+}
+
+/* Place as many of the user's current register windows 
+ * on the stack that we can.  Even if the %sp is unaligned
+ * we still copy the window there, the only case that we don't
+ * succeed is if the %sp points to a bum mapping altogether.
+ * setup_frame() and do_sigreturn() use this before shifting
+ * the user stack around.  Future instruction and hardware
+ * bug workaround routines will need this functionality as
+ * well.
+ */
+void synchronize_user_stack(void)
+{
+       struct thread_struct *tp = &current->tss;
+       int window;
+
+       flush_user_windows();
+
+       if(!tp->w_saved)
+               return;
+
+       /* Ok, there is some dirty work to do. */
+       for(window = tp->w_saved - 1; window >= 0; window--) {
+               unsigned long sp = tp->rwbuf_stkptrs[window];
+
+               /* See if %sp is reasonable at all. */
+               if(verify_area(VERIFY_WRITE, (char *) sp, sizeof(struct reg_window)))
+                       continue;
+
+               /* Ok, let it rip. */
+               memcpy((char *) sp, &tp->reg_window[window], sizeof(struct reg_window));
+               shift_window_buffer(window, tp->w_saved - 1, tp);
+               tp->w_saved--;
+       }
+}
+
+/* An optimization. */
+static inline void copy_aligned_window(void *dest, const void *src)
+{
+       __asm__ __volatile__("ldd [%1], %%g2\n\t"
+                            "ldd [%1 + 0x8], %%g4\n\t"
+                            "std %%g2, [%0]\n\t"
+                            "std %%g4, [%0 + 0x8]\n\t"
+                            "ldd [%1 + 0x10], %%g2\n\t"
+                            "ldd [%1 + 0x18], %%g4\n\t"
+                            "std %%g2, [%0 + 0x10]\n\t"
+                            "std %%g4, [%0 + 0x18]\n\t"
+                            "ldd [%1 + 0x20], %%g2\n\t"
+                            "ldd [%1 + 0x28], %%g4\n\t"
+                            "std %%g2, [%0 + 0x20]\n\t"
+                            "std %%g4, [%0 + 0x28]\n\t"
+                            "ldd [%1 + 0x30], %%g2\n\t"
+                            "ldd [%1 + 0x38], %%g4\n\t"
+                            "std %%g2, [%0 + 0x30]\n\t"
+                            "std %%g4, [%0 + 0x38]\n\t" : :
+                            "r" (dest), "r" (src) :
+                            "g2", "g3", "g4", "g5");
+}
+
+/* Try to push the windows in a threads window buffer to the
+ * user stack.  Unaligned %sp's are not allowed here.
+ */
+
+#define stack_is_bad(sp, rw) \
+  (((sp) & 7) || verify_area(rw, (char *) (sp), sizeof(struct reg_window)))
+
+void try_to_clear_window_buffer(struct pt_regs *regs, int who)
+{
+       struct thread_struct *tp = &current->tss;
+       int window;
+
+       flush_user_windows();
+       for(window = 0; window < tp->w_saved; window++) {
+               unsigned long sp = tp->rwbuf_stkptrs[window];
+
+               if(stack_is_bad(sp, VERIFY_WRITE))
+                       do_exit(SIGILL);
+               else
+                       copy_aligned_window((char *) sp, &tp->reg_window[window]);
+       }
+       tp->w_saved = 0;
+}
index 3d0772523c9591daf954f3b4423df90fd17b94ee..69003289114aba13ded15bd27b478541f1a04fec 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: wof.S,v 1.14 1995/11/25 00:58:49 davem Exp $
+/* $Id: wof.S,v 1.20 1996/02/20 07:45:18 davem Exp $
  * wof.S: Sparc window overflow handler.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -87,14 +87,14 @@ spnwin_patch2:      and     %glob_tmp, 0xff, %glob_tmp
         * up for us to see if this is from user or kernel.
         * Get the load of 'curptr' out of the way.
         */
-       LOAD_CURRENT(curptr)
+       LOAD_CURRENT(curptr, twin_tmp)
 
        andcc   %t_psr, PSR_PS, %g0
        be      spwin_fromuser                          ! all user wins, branch
         nop
        
        /* See if any user windows are active in the set. */
-       ld      [%curptr + THREAD_UMASK], %twin_tmp     ! grab currents win mask
+       ld      [%curptr + THREAD_UMASK], %twin_tmp     ! grab win mask
        orcc    %g0, %twin_tmp, %g0                     ! check for set bits
        bne     spwin_exist_uwins                       ! yep, there are some
         nop
@@ -237,22 +237,25 @@ spnwin_patch3:    and     %twin_tmp, 0xff, %twin_tmp      ! patched on 7win Sparcs
                st      %twin_tmp, [%curptr + THREAD_UMASK]
 
        /* Jump onto kernel stack for this process... */
-       ld      [%curptr + TASK_KSTACK_PG], %sp
-       add     %sp, (PAGE_SIZE - TRACEREG_SZ - STACKFRAME_SZ), %sp
+       ld      [%curptr + TASK_SAVED_KSTACK], %sp
 
        /* Restore the saved globals and build a pt_regs frame. */
        mov     %saved_g5, %g5
        mov     %saved_g6, %g6
-       rd      %wim, %twin_tmp
-       STORE_PT_ALL(sp, t_psr, t_pc, t_npc, twin_tmp, g1)
+       STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
 
        /* Turn on traps and call c-code to deal with it. */
        wr      %t_psr, PSR_ET, %psr
        WRITE_PAUSE
 
-       mov     1, %o1
-       call    C_LABEL(do_sparc_winfault)
-        add    %sp, STACKFRAME_SZ, %o0
+#if 0
+       mov     0, %o1
+       call    C_LABEL(try_to_clear_window_buffer)
+        add    %sp, REGWIN_SZ, %o0
+#else
+       call    C_LABEL(window_overflow_fault)
+        nop
+#endif
 
        /* Return from trap if C-code actually fixes things, if it
         * doesn't then we never get this far as the process will
@@ -388,7 +391,7 @@ C_LABEL(spwin_srmmu_stackchk):
         */
        /* Check results of callers andcc %sp, 0x7, %g0 */
        bne     spwin_user_stack_is_bolixed
-       sethi   %hi(KERNBASE), %glob_tmp
+        sethi  %hi(KERNBASE), %glob_tmp
        cmp     %glob_tmp, %sp
        bleu    spwin_user_stack_is_bolixed
         mov    AC_M_SFSR, %glob_tmp
index a1cb4941aa5338ee8b4ac561f2cff8058874db3e..1b9f03e76e014564b0601496a1855bdea2ee31a5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.13 1995/11/25 00:58:51 davem Exp $
+/* $Id: wuf.S,v 1.20 1996/02/20 07:45:22 davem Exp $
  * wuf.S: Window underflow trap handler for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller
@@ -19,7 +19,7 @@
 #define t_pc        l1
 #define t_npc       l2
 #define t_wim       l3
-/* Don`t touch the above registers or else you die horribly... */
+/* Don't touch the above registers or else you die horribly... */
 
 /* Now macros for the available scratch registers in this routine. */
 #define twin_tmp1    l4
@@ -141,15 +141,14 @@ fwin_user_stack_is_bolixed:
        /* Place a pt_regs frame on the kernel stack, save back
         * to the trap window and call c-code to deal with this.
         */
-       LOAD_CURRENT(l4)
-       ld      [%l4 + TASK_KSTACK_PG], %l5
-       add     %l5, (PAGE_SIZE - TRACEREG_SZ - STACKFRAME_SZ), %l5
+       LOAD_CURRENT(l4, l5)
+       ld      [%l4 + TASK_SAVED_KSTACK], %l5
 
        /* Store globals into pt_regs frame. */
        STORE_PT_GLOBALS(l5)
        STORE_PT_YREG(l5, g3)
 
-       /* Save kernel %sp in global while we change windows */
+       /* Save kernel %sp in global while we change windows. */
        mov     %l5, %g2
 
        save    %g0, %g0, %g0
@@ -157,6 +156,7 @@ fwin_user_stack_is_bolixed:
        /* LOCATION: Window 'O' */
 
        rd      %psr, %g3               /* Read %psr in live user window */
+       mov     %fp, %g6                /* Save bogus frame pointer. */
 
        save    %g0, %g0, %g0
 
@@ -166,7 +166,7 @@ fwin_user_stack_is_bolixed:
 
        /* Build rest of pt_regs. */
        STORE_PT_INS(sp)
-       STORE_PT_PRIV(sp, t_psr, t_pc, t_npc, t_wim)
+       STORE_PT_PRIV(sp, t_psr, t_pc, t_npc)
 
        /* re-set trap time %wim value */
        wr      %t_wim, 0x0, %wim
@@ -174,22 +174,16 @@ fwin_user_stack_is_bolixed:
        /* Fix users window mask and buffer save count. */
        mov     0x1, %g5
        sll     %g5, %g3, %g5
-       LOAD_CURRENT(twin_tmp1)
+       LOAD_CURRENT(twin_tmp1, g1)
        st      %g5, [%twin_tmp1 + THREAD_UMASK]        ! one live user window still
        st      %g0, [%twin_tmp1 + THREAD_W_SAVED]      ! no windows in the buffer
 
-       wr      %t_psr, 0x0, %psr
        wr      %t_psr, PSR_ET, %psr                    ! enable traps
        WRITE_PAUSE
 
-       mov     2, %o1
-       call    C_LABEL(do_sparc_winfault)              ! call c-code
-        add    %sp, STACKFRAME_SZ, %o0                 ! pt_regs ptr is arg0
+       call    C_LABEL(window_underflow_fault)
+        mov    %g6, %o0
 
-       /* Return from trap if C-code actually fixes things, if it
-        * doesn't then we never get this far as the process will
-        * be given the look of death from Commander Peanut.
-        */
        b       ret_trap_entry
         nop
 
@@ -347,5 +341,11 @@ C_LABEL(srmmu_fwin_stackchk):
        be      fwin_user_finish_up
         nop
 
+       /* Did I ever tell you about my window labotomy?
+        * anyways... fwin_user_stack_is_bolixed expects
+        * to be in window 'W' so make it happy or else
+        * we watchdog badly.
+        */
+       restore %g0, %g0, %g0
        b       fwin_user_stack_is_bolixed      ! oh well
-        nop
+        restore        %g0, %g0, %g0
index 56cc496721a8a2d3de0feff45bfd5ce9cec51a4f..7e0aa8739480c0111fd05327d87eea880724646e 100644 (file)
@@ -1,15 +1,18 @@
-# $Id: Makefile,v 1.5 1995/11/25 00:58:56 davem Exp $
+# $Id: Makefile,v 1.7 1995/12/10 06:25:02 davem Exp $
 # Makefile for Sparc library files..
 #
 
 CFLAGS := $(CFLAGS) -ansi
 
-OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o
+OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o
 
 lib.a: $(OBJS)
        $(AR) rcs lib.a $(OBJS)
        sync
 
+memcpy.o: memcpy.S
+       $(CC) -ansi -c -o memcpy.o memcpy.S
+
 mul.o: mul.S
        $(CC) -c -o mul.o mul.S
 
diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S
new file mode 100644 (file)
index 0000000..59bbeba
--- /dev/null
@@ -0,0 +1,520 @@
+! Fast memmove/memcpy/bcopy
+! Copyright Australian National University, 1995
+! This file may be used under the terms of the GNU Public License
+! Author: Paul Mackerras, September 95
+! Minor beautifications David S. Miller
+
+#include <asm/cprefix.h>
+
+       .globl  C_LABEL(bcopy)
+C_LABEL(bcopy):
+       mov     %o0,%o3
+       mov     %o1,%o0
+       mov     %o3,%o1
+
+       .globl  C_LABEL(amemmove)
+C_LABEL(amemmove):
+       .globl  C_LABEL(memmove)
+       .globl  C_LABEL(memcpy)
+C_LABEL(memmove):
+C_LABEL(memcpy):
+       save    %sp,-96,%sp
+       mov     %i0,%l7
+
+       cmp     %i0,%i1         ! check for dest within source area
+       bleu,a  1f
+       andcc   %i0,3,%l1
+       add     %i1,%i2,%l0
+       cmp     %i0,%l0
+       blu,a   Lback
+       mov     %l0,%i1
+
+       ! copying forwards
+       ! first get dest to be word-aligned
+       andcc   %i0,3,%l1
+1:
+       be,a    Lwalign         ! if dest already word-aligned
+       cmp     %i2,4
+       mov     4,%l2
+       sub     %l2,%l1,%l2     ! #bytes until word-aligned
+       subcc   %i2,%l2,%i2
+       ble,a   Lend            ! not copying enough to get past word bdry
+       addcc   %i2,%l2,%i2
+
+1:
+       ldub    [%i1],%o0       ! copy single bytes until word-aligned
+       add     %i1,1,%i1
+       subcc   %l2,1,%l2
+       stb     %o0,[%i0]
+       bgt     1b
+       add     %i0,1,%i0
+       cmp     %i2,4
+
+Lwalign:                       ! dest now word aligned
+       blt,a   Lend
+       orcc    %i2,%g0,%g0
+
+       andcc   %i1,3,%l0
+       be,a    Ldoword         ! if dest word aligned wrt src
+       andcc   %i0,4,%g0
+
+       ! yucky cases where we have to shift
+
+       mov     4,%l2
+       sub     %l2,%l0,%l2     ! address adjustment, used at Lendn
+       sll     %l0,3,%l0       ! bit offset = shift left count
+       sll     %l2,3,%l1       ! shift right count
+       add     %i1,%l2,%i1     ! round up to next word
+       ld      [%i1-4],%o0     ! get first word
+
+       andcc   %i0,4,%g0       ! get destination double-word aligned
+       be,a    1f
+       andcc   %i1,4,%g0
+       ld      [%i1],%o1       ! by constructing and storing one word
+       add     %i0,4,%i0
+       add     %i1,4,%i1
+       sub     %i2,4,%i2
+       sll     %o0,%l0,%o0
+       srl     %o1,%l1,%l6
+       or      %o0,%l6,%o0
+       st      %o0,[%i0-4]
+       mov     %o1,%o0
+
+       andcc   %i1,4,%g0       ! now construct & store pairs of double-words
+1:
+       bne,a   3f              ! if source now not double-word aligned
+       subcc   %i2,4,%i2
+       subcc   %i2,16,%i2
+       blt     2f
+       mov     %o0,%o1
+4:
+       ldd     [%i1],%o2
+       sll     %o1,%l0,%o4
+       ldd     [%i1+8],%o0
+       add     %i0,16,%i0
+       add     %i1,16,%i1
+       subcc   %i2,16,%i2
+       srl     %o2,%l1,%l6
+       or      %l6,%o4,%o4
+       sll     %o2,%l0,%o5
+       srl     %o3,%l1,%l6
+       or      %l6,%o5,%o5
+       std     %o4,[%i0-16]
+       sll     %o3,%l0,%o4
+       srl     %o0,%l1,%l6
+       or      %l6,%o4,%o4
+       sll     %o0,%l0,%o5
+       srl     %o1,%l1,%l6
+       or      %l6,%o5,%o5
+       bge     4b
+       std     %o4,[%i0-8]
+2:
+       addcc   %i2,12,%i2
+       blt,a   Lendn
+       addcc   %i2,4,%i2
+5:
+       ld      [%i1],%o2
+       add     %i0,4,%i0
+       add     %i1,4,%i1
+       subcc   %i2,4,%i2
+       sll     %o1,%l0,%o0
+       srl     %o2,%l1,%o1
+       or      %o1,%o0,%o0
+       st      %o0,[%i0-4]
+       bge     5b
+       mov     %o2,%o1
+       ba      Lendn
+       addcc   %i2,4,%i2
+
+3:
+       blt,a   Lendn
+       addcc   %i2,4,%i2
+       ld      [%i1],%o1
+       add     %i1,4,%i1
+       subcc   %i2,16,%i2
+       blt,a   8f
+       addcc   %i2,16,%i2
+7:
+       ldd     [%i1],%o2
+       sll     %o0,%l0,%o4
+       srl     %o1,%l1,%l6
+       or      %l6,%o4,%o4
+       sll     %o1,%l0,%o5
+       ldd     [%i1+8],%o0
+       add     %i0,16,%i0
+       add     %i1,16,%i1
+       subcc   %i2,16,%i2
+       srl     %o2,%l1,%l6
+       or      %l6,%o5,%o5
+       std     %o4,[%i0-16]
+       sll     %o2,%l0,%o4
+       srl     %o3,%l1,%l6
+       or      %l6,%o4,%o4
+       sll     %o3,%l0,%o5
+       srl     %o0,%l1,%l6
+       or      %l6,%o5,%o5
+       bge     7b
+       std     %o4,[%i0-8]
+       addcc   %i2,16,%i2
+8:
+       sll     %o0,%l0,%o4
+       srl     %o1,%l1,%l6
+       or      %l6,%o4,%o4
+       st      %o4,[%i0]
+       add     %i0,4,%i0
+       subcc   %i2,4,%i2
+       blt,a   Lendn
+       addcc   %i2,4,%i2
+       mov     %o1,%o0
+       ld      [%i1],%o1
+       ba      8b
+       add     %i1,4,%i1
+
+
+Ldoword:
+       ! here both dest and src are word-aligned
+       ! make dest double-word aligned
+       be,a    1f
+       andcc   %i1,4,%g0
+       ld      [%i1],%o0
+       add     %i0,4,%i0
+       add     %i1,4,%i1
+       sub     %i2,4,%i2
+       st      %o0,[%i0-4]
+       cmp     %i2,4
+       blt,a   Lend
+       orcc    %i2,%g0,%g0
+       andcc   %i1,4,%g0
+
+1:
+       be,a    Ldodble         ! if source double-word aligned now
+       subcc   %i2,32,%i2
+       ld      [%i1],%o5
+       add     %i1,4,%i1
+       subcc   %i2,36,%i2
+       blt,a   3f
+       add     %i2,32,%i2
+2:
+       ldd     [%i1],%o2
+       add     %i1,32,%i1
+       subcc   %i2,32,%i2
+       mov     %o5,%o0
+       ldd     [%i1-24],%o4
+       mov     %o2,%o1
+       std     %o0,[%i0]
+       mov     %o3,%o2
+       ldd     [%i1-16],%o0
+       mov     %o4,%o3
+       std     %o2,[%i0+8]
+       mov     %o5,%o2
+       ldd     [%i1-8],%o4
+       mov     %o0,%o3
+       std     %o2,[%i0+16]
+       mov     %o1,%o0
+       mov     %o4,%o1
+       std     %o0,[%i0+24]
+       bge     2b
+       add     %i0,32,%i0
+       add     %i2,32,%i2
+3:
+       st      %o5,[%i0]
+       add     %i0,4,%i0
+       subcc   %i2,4,%i2
+       blt,a   Lend
+       addcc   %i2,4,%i2
+       ld      [%i1],%o5
+       ba      3b
+       add     %i1,4,%i1
+
+Ldodble:
+       ! dest and source are both double-word aligned
+       blt,a   2f
+       addcc   %i2,28,%i2
+1:
+       ldd     [%i1],%o0       ! copy sets of 4 double-words
+       subcc   %i2,32,%i2
+       ldd     [%i1+8],%o2
+       add     %i1,32,%i1
+       ldd     [%i1-16],%o4
+       add     %i0,32,%i0
+       std     %o0,[%i0-32]
+       ldd     [%i1-8],%o0
+       std     %o2,[%i0-24]
+       std     %o4,[%i0-16]
+       bge     1b
+       std     %o0,[%i0-8]
+       addcc   %i2,28,%i2
+2:
+       blt,a   Lend
+       addcc   %i2,4,%i2
+3:
+       ld      [%i1],%o0       ! copy words
+       add     %i1,4,%i1
+       add     %i0,4,%i0
+       subcc   %i2,4,%i2
+       bge     3b
+       st      %o0,[%i0-4]
+       ba      Lend
+       addcc   %i2,4,%i2
+
+Lendn:
+       sub     %i1,%l2,%i1
+Lend:
+       ble     Lout
+       nop
+1:
+       ldub    [%i1],%o0
+       add     %i1,1,%i1
+       subcc   %i2,1,%i2
+       stb     %o0,[%i0]
+       bgt     1b
+       add     %i0,1,%i0
+
+       ba      Lout
+       nop
+
+Lback: ! Here we have to copy backwards
+       add     %i0,%i2,%i0
+       ! first get dest to be word-aligned
+       andcc   %i0,3,%l2       ! #bytes until word-aligned
+       be,a    Lbwal           ! if dest already word-aligned
+       cmp     %i2,4
+       subcc   %i2,%l2,%i2
+       ble,a   Lbend           ! not copying enough to get past word bdry
+       addcc   %i2,%l2,%i2
+
+1:
+       ldub    [%i1-1],%o0     ! copy single bytes until word-aligned
+       sub     %i1,1,%i1
+       subcc   %l2,1,%l2
+       stb     %o0,[%i0-1]
+       bgt     1b
+       sub     %i0,1,%i0
+       cmp     %i2,4
+
+Lbwal:                         ! dest now word aligned
+       blt,a   Lbend
+       orcc    %i2,%g0,%g0
+
+       andcc   %i1,3,%l2
+       be,a    Lbword          ! if dest word aligned wrt src
+       andcc   %i0,4,%g0
+
+       ! yucky cases where we have to shift
+       ! note %l2 used below at Lbendn
+
+       mov     4,%l0
+       sub     %l0,%l2,%l0     ! # bytes to right of src in word
+       sll     %l0,3,%l0       ! bit offset = shift right count
+       sll     %l2,3,%l1       ! shift left count
+       sub     %i1,%l2,%i1     ! round down to word boundary
+       ld      [%i1],%o1       ! get first word
+
+       andcc   %i0,4,%g0       ! get destination double-word aligned
+       be,a    1f
+       andcc   %i1,4,%g0
+       ld      [%i1-4],%o0     ! by constructing and storing one word
+       sub     %i0,4,%i0
+       sub     %i1,4,%i1
+       sub     %i2,4,%i2
+       srl     %o1,%l0,%o1
+       sll     %o0,%l1,%l6
+       or      %o1,%l6,%o1
+       st      %o1,[%i0]
+       mov     %o0,%o1
+
+       andcc   %i1,4,%g0       ! now construct & store pairs of double-words
+1:
+       bne,a   3f              ! if source now not double-word aligned
+       subcc   %i2,4,%i2
+       subcc   %i2,16,%i2
+       blt     2f
+       mov     %o1,%o0
+4:
+       ldd     [%i1-8],%o2
+       srl     %o0,%l0,%o5
+       ldd     [%i1-16],%o0
+       sub     %i0,16,%i0
+       sub     %i1,16,%i1
+       subcc   %i2,16,%i2
+       sll     %o3,%l1,%l6
+       or      %l6,%o5,%o5
+       srl     %o3,%l0,%o4
+       sll     %o2,%l1,%l6
+       or      %l6,%o4,%o4
+       std     %o4,[%i0+8]
+       srl     %o2,%l0,%o5
+       sll     %o1,%l1,%l6
+       or      %l6,%o5,%o5
+       srl     %o1,%l0,%o4
+       sll     %o0,%l1,%l6
+       or      %l6,%o4,%o4
+       bge     4b
+       std     %o4,[%i0]
+2:
+       addcc   %i2,12,%i2
+       blt,a   Lbendn
+       addcc   %i2,4,%i2
+5:
+       ld      [%i1-4],%o2
+       sub     %i0,4,%i0
+       sub     %i1,4,%i1
+       subcc   %i2,4,%i2
+       srl     %o0,%l0,%o0
+       sll     %o2,%l1,%o1
+       or      %o1,%o0,%o0
+       st      %o0,[%i0]
+       bge     5b
+       mov     %o2,%o0
+       ba      Lbendn
+       addcc   %i2,4,%i2
+
+3:
+       blt,a   Lbendn
+       addcc   %i2,4,%i2
+       ld      [%i1-4],%o0
+       sub     %i1,4,%i1
+       subcc   %i2,16,%i2
+       blt,a   8f
+       addcc   %i2,16,%i2
+7:
+       ldd     [%i1-8],%o2
+       srl     %o1,%l0,%o5
+       sll     %o0,%l1,%l6
+       or      %l6,%o5,%o5
+       srl     %o0,%l0,%o4
+       ldd     [%i1-16],%o0
+       sub     %i0,16,%i0
+       sub     %i1,16,%i1
+       subcc   %i2,16,%i2
+       sll     %o3,%l1,%l6
+       or      %l6,%o4,%o4
+       std     %o4,[%i0+8]
+       srl     %o3,%l0,%o5
+       sll     %o2,%l1,%l6
+       or      %l6,%o5,%o5
+       srl     %o2,%l0,%o4
+       sll     %o1,%l1,%l6
+       or      %l6,%o4,%o4
+       bge     7b
+       std     %o4,[%i0]
+       addcc   %i2,16,%i2
+8:
+       srl     %o1,%l0,%o5
+       sll     %o0,%l1,%l6
+       or      %l6,%o5,%o5
+       st      %o5,[%i0-4]
+       sub     %i0,4,%i0
+       subcc   %i2,4,%i2
+       blt,a   Lbendn
+       addcc   %i2,4,%i2
+       mov     %o0,%o1
+       ld      [%i1-4],%o0
+       ba      8b
+       sub     %i1,4,%i1
+
+
+Lbword:
+       ! here both dest and src are word-aligned
+       ! make dest double-word aligned
+       be,a    1f
+       andcc   %i1,4,%g0
+       ld      [%i1-4],%o0
+       sub     %i0,4,%i0
+       sub     %i1,4,%i1
+       sub     %i2,4,%i2
+       st      %o0,[%i0]
+       cmp     %i2,4
+       blt,a   Lbend
+       orcc    %i2,%g0,%g0
+       andcc   %i1,4,%g0
+
+1:
+       be,a    Lbdble          ! if source double-word aligned now
+       subcc   %i2,32,%i2
+       ld      [%i1-4],%o4
+       sub     %i1,4,%i1
+       subcc   %i2,36,%i2
+       blt,a   3f
+       add     %i2,32,%i2
+2:
+       ldd     [%i1-8],%o2
+       sub     %i1,32,%i1
+       subcc   %i2,32,%i2
+       mov     %o4,%o1
+       ldd     [%i1+16],%o4
+       mov     %o3,%o0
+       std     %o0,[%i0-8]
+       mov     %o2,%o3
+       ldd     [%i1+8],%o0
+       mov     %o5,%o2
+       std     %o2,[%i0-16]
+       mov     %o4,%o3
+       ldd     [%i1],%o4
+       mov     %o1,%o2
+       std     %o2,[%i0-24]
+       mov     %o0,%o1
+       mov     %o5,%o0
+       std     %o0,[%i0-32]
+       bge     2b
+       sub     %i0,32,%i0
+       add     %i2,32,%i2
+3:
+       st      %o4,[%i0-4]
+       sub     %i0,4,%i0
+       subcc   %i2,4,%i2
+       blt,a   Lbend
+       addcc   %i2,4,%i2
+       ld      [%i1-4],%o4
+       ba      3b
+       sub     %i1,4,%i1
+
+Lbdble:
+       ! dest and source are both double-word aligned
+       blt,a   2f
+       addcc   %i2,28,%i2
+1:
+       ldd     [%i1-8],%o0     ! copy sets of 4 double-words
+       subcc   %i2,32,%i2
+       ldd     [%i1-16],%o2
+       sub     %i1,32,%i1
+       ldd     [%i1+8],%o4
+       sub     %i0,32,%i0
+       std     %o0,[%i0+24]
+       ldd     [%i1],%o0
+       std     %o2,[%i0+16]
+       std     %o4,[%i0+8]
+       bge     1b
+       std     %o0,[%i0]
+       addcc   %i2,28,%i2
+2:
+       blt,a   Lbend
+       addcc   %i2,4,%i2
+3:
+       ld      [%i1-4],%o0     ! copy words
+       sub     %i1,4,%i1
+       sub     %i0,4,%i0
+       subcc   %i2,4,%i2
+       bge     3b
+       st      %o0,[%i0]
+       ba      Lbend
+       addcc   %i2,4,%i2
+
+Lbendn:
+       add     %i1,%l2,%i1
+Lbend:
+       ble     Lout
+       nop
+1:
+       ldub    [%i1-1],%o0
+       sub     %i1,1,%i1
+       subcc   %i2,1,%i2
+       stb     %o0,[%i0-1]
+       bgt     1b
+       sub     %i0,1,%i0
+
+Lout:
+       ret
+       restore %l7,0,%o0
+
+
index 14683e8eedb09df92924a9aef7b6d7156bbeb334..3e084f17ac848cd4aeefff8a017dbf73dba71859 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.14 1995/11/25 00:59:17 davem Exp $
+# $Id: Makefile,v 1.17 1996/01/03 03:35:15 davem Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -7,21 +7,7 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-# Also note that s4ctlb.o _must_ be the last object file
-
-#.S.s:
-#      $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
-.S.o:
-       $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-
-all: mm.o
 O_TARGET := mm.o
-O_OBJS   := fault.o sun4c_vac.o init.o sun4c.o srmmu.o loadmmu.o mbus.o \
-            s4cflush.o
-
-#s4cflush.o: s4cflush.s
-
-s4cflush.o: s4cflush.S
-       $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+O_OBJS   := fault.o init.o sun4c.o srmmu.o loadmmu.o
 
 include $(TOPDIR)/Rules.make
index 4ce01473a7e5a4136f0a9f23a62df6458e6f8c98..d39663ae0ff51c4cceacdd8a1eaecc8956f6cc03 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.42 1995/11/25 00:59:20 davem Exp $
+/* $Id: fault.c,v 1.53 1996/03/01 07:16:17 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 extern int prom_node_root;
 
-extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void die_if_kernel(char *,struct pt_regs *);
 
 struct linux_romvec *romvec;
 
-/* foo */
-
-int tbase_needs_unmapping;
-
 /* At boot time we determine these two values necessary for setting
  * up the segment maps and page table entries (pte's).
  */
@@ -49,13 +45,6 @@ int vac_size, vac_linesize, vac_do_hw_vac_flushes;
 int vac_entries_per_context, vac_entries_per_segment;
 int vac_entries_per_page;
 
-/*
- * Define this if things work differently on a i386 and a i486:
- * it will (on a i486) warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
- */
-#undef CONFIG_TEST_VERIFY_AREA
-
 /* Nice, simple, prom library does all the sweating for us. ;) */
 int prom_probe_memory (void)
 {
@@ -109,11 +98,14 @@ probe_memory(void)
        return total;
 }
 
+extern void sun4c_complete_all_stores(void);
+
 /* Whee, a level 15 NMI interrupt memory error.  Let's have fun... */
 asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
                                unsigned long svaddr, unsigned long aerr,
                                unsigned long avaddr)
 {
+       sun4c_complete_all_stores();
        printk("FAULT: NMI received\n");
        printk("SREGS: Synchronous Error %08lx\n", serr);
        printk("       Synchronous Vaddr %08lx\n", svaddr);
@@ -124,33 +116,22 @@ asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
        prom_halt();
 }
 
-/* Whee, looks like an i386 to me ;-) */
-asmlinkage void do_sparc_fault(struct pt_regs *regs, unsigned long tbr)
+asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
+                              unsigned long address)
 {
        struct vm_area_struct *vma;
-       unsigned long address, error_code, trap_type;
-       unsigned long from_user;
+       int from_user = !(regs->psr & PSR_PS);
 
-       from_user = (((regs->psr & PSR_PS) >> 4) ^ FAULT_CODE_USER);
-       if(get_fault_info(&address, &error_code, from_user))
-               goto bad_area;
-       trap_type = ((tbr>>4)&0xff);
-       if(trap_type == SP_TRAP_TFLT) {
-               /* We play it 'safe'... */
+       if(text_fault)
                address = regs->pc;
-               error_code = (from_user); /* no page, read */
-       } else if(trap_type != SP_TRAP_DFLT)
-               panic("Bad sparc trap, trap_type not data or text fault...");
 
        /* Now actually handle the fault.  Do kernel faults special,
         * because on the sun4c we could have faulted trying to read
         * the vma area of the task and without the following code
         * we'd fault recursively until all our stack is gone. ;-(
-        *
-        * XXX I think there are races with this maneuver. XXX
         */
        if(!from_user && address >= KERNBASE) {
-               update_mmu_cache(0, address, __pte(0));
+               quick_kernel_fault(address);
                return;
        }
 
@@ -168,7 +149,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, unsigned long tbr)
         * we can handle it..
         */
 good_area:
-       if(error_code & FAULT_CODE_WRITE) {
+       if(write) {
                if(!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
        } else {
@@ -176,14 +157,14 @@ good_area:
                if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
-       handle_mm_fault(vma, address, error_code & FAULT_CODE_WRITE);
+       handle_mm_fault(vma, address, write);
        return;
        /*
         * Something tried to access memory that isn't in our memory map..
         * Fix it, but check if it's kernel or user first..
         */
 bad_area:
-       if(error_code & FAULT_CODE_USER) {
+       if(from_user) {
                current->tss.sig_address = address;
                current->tss.sig_desc = SUBSIG_NOMAPPING;
                send_sig(SIGSEGV, current, 1);
@@ -204,100 +185,64 @@ bad_area:
        } else
                printk(KERN_ALERT "Unable to handle kernel paging request");
        printk(" at virtual address %08lx\n",address);
-       printk("At PC %08lx nPC %08lx\n", (unsigned long) regs->pc,
-              (unsigned long) regs->npc);
-       printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
-              (unsigned long) current->tss.pgd_ptr);
-       show_regs(regs);
-       panic("KERNAL FAULT");
+       printk(KERN_ALERT "current->mm->context = %08lx\n",
+              (unsigned long) current->mm->context);
+       printk(KERN_ALERT "current->mm->pgd = %08lx\n",
+              (unsigned long) current->mm->pgd);
+       die_if_kernel("Oops", regs);
 }
 
-/* When the user does not have a mapped stack and we either
- * need to read the users register window from that stack or
- * we need to save a window to that stack, control flow
- * ends up here to investigate the situation.  This is a
- * very odd situation where a 'user fault' happens from
- * kernel space.
- */
+/* This always deals with user addresses. */
+inline void force_user_fault(unsigned long address, int write)
+{
+       struct vm_area_struct *vma;
+
+       vma = find_vma(current, address);
+       if(!vma)
+               goto bad_area;
+       if(vma->vm_start <= address)
+               goto good_area;
+       if(!(vma->vm_flags & VM_GROWSDOWN))
+               goto bad_area;
+       if(expand_stack(vma, address))
+               goto bad_area;
+good_area:
+       if(write)
+               if(!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;
+       else
+               if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                       goto bad_area;
+       handle_mm_fault(vma, address, write);
+       return;
+bad_area:
+       current->tss.sig_address = address;
+       current->tss.sig_desc = SUBSIG_NOMAPPING;
+       send_sig(SIGSEGV, current, 1);
+       return;
+}
 
-/* #define DEBUG_WINFAULT */
-extern void show_regwindow(struct reg_window *);
-asmlinkage void do_sparc_winfault(struct pt_regs *regs, int push)
+void window_overflow_fault(void)
 {
-       int wincount = 0;
-       int signal = 0;
-       struct thread_struct *tsp = &current->tss;
+       unsigned long sp = current->tss.rwbuf_stkptrs[0];
 
-       flush_user_windows();
-#ifdef DEBUG_WINFAULT
-       {
-               int i;
-               printk("%s[%d]wfault<%d>: WINDOW DUMP --> ", current->comm,
-                      current->pid, push);
-               if(push==1)
-                       for(i = 0; i < tsp->w_saved; i++)
-                               printk("w[%d]sp<%08lx>, ",
-                                      i, tsp->rwbuf_stkptrs[i]);
-               else
-                       printk("w[0]sp<%08lx>", regs->u_regs[UREG_FP]);
-               if(push!=2)
-                       printk("\n");
-       }
-#endif
-       if(push==1) {
-               /* We failed to push a window to users stack. */
-               while(wincount < tsp->w_saved) {
-                       if ((tsp->rwbuf_stkptrs[wincount] & 7) ||
-                           (tsp->rwbuf_stkptrs[wincount] > KERNBASE) ||
-                           verify_area(VERIFY_WRITE,
-                                       (char *) tsp->rwbuf_stkptrs[wincount],
-                                       sizeof(struct reg_window))) {
-                               signal = SIGILL;
-                               break;
-                       }                       
-                       /* Do it! */
-                       memcpy((char *) tsp->rwbuf_stkptrs[wincount],
-                              (char *)&tsp->reg_window[wincount],
-                              sizeof(struct reg_window));
-                       wincount++;
-               }
-       } else {
-               /* We failed to pull a window from users stack.
-                * For a window underflow from userland we need
-                * to verify two stacks, for a return from trap
-                * we need only inspect the one at UREG_FP.
-                */
-               if((regs->u_regs[UREG_FP] & 7) ||
-                  (regs->u_regs[UREG_FP] > KERNBASE) ||
-                  verify_area(VERIFY_READ,
-                              (char *) regs->u_regs[UREG_FP],
-                              sizeof(struct reg_window)))
-                       signal = SIGILL;
-               else
-                       memcpy((char *)&tsp->reg_window[0],
-                              (char *) regs->u_regs[UREG_FP],
-                              sizeof(struct reg_window));
-               if(push==2 && !signal) {
-                       unsigned long sp = tsp->reg_window[0].ins[6];
-#ifdef DEBUG_WINFAULT
-                       printk(", w[1]sp<%08lx>\n", sp);
-                       show_regwindow(&tsp->reg_window[0]);
-#endif
-                       if((sp & 7) || (sp > KERNBASE) ||
-                          verify_area(VERIFY_READ, (char *) sp,
-                                      sizeof(struct reg_window)))
-                               signal = SIGILL;
-                       else
-                               memcpy((char *)&tsp->reg_window[1],
-                                      (char *) sp, sizeof(struct reg_window));
-               }
-       }
-       if(signal) {
-               printk("%s[%d]: User has trashed stack pointer pc<%08lx>sp<%08lx>\n",
-                      current->comm, current->pid, regs->pc, regs->u_regs[UREG_FP]);
-               tsp->sig_address = regs->pc;
-               tsp->sig_desc = SUBSIG_STACK;
-               send_sig(signal, current, 1);
-       } else
-               tsp->w_saved = 0;
+       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+               force_user_fault(sp + 0x38, 1);
+       force_user_fault(sp, 1);
+}
+
+void window_underflow_fault(unsigned long sp)
+{
+       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+               force_user_fault(sp + 0x38, 0);
+       force_user_fault(sp, 0);
+}
+
+void window_ret_fault(struct pt_regs *regs)
+{
+       unsigned long sp = regs->u_regs[UREG_FP];
+
+       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+               force_user_fault(sp + 0x38, 0);
+       force_user_fault(sp, 0);
 }
index aebd9cb2552b6c3bc3f7ab4b8d39b00da32860f9..e070eacffb83481e60cbedba4ec51b1397496787 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.26 1995/11/25 00:59:22 davem Exp $
+/*  $Id: init.c,v 1.33 1996/03/01 07:16:20 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -15,6 +15,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -52,12 +53,6 @@ pte_t __bad_page(void)
        return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
 }
 
-unsigned long __zero_page(void)
-{
-       memset((void *) ZERO_PGE, 0, PAGE_SIZE);
-       return (unsigned long) ZERO_PGE;
-}
-
 void show_mem(void)
 {
        int i,free = 0,total = 0,reserved = 0;
@@ -88,6 +83,26 @@ void show_mem(void)
 
 extern pgprot_t protection_map[16];
 
+unsigned long sparc_context_init(unsigned long start_mem, int numctx)
+{
+       int ctx;
+
+       ctx_list_pool = (struct ctx_list *) start_mem;
+       start_mem += (numctx * sizeof(struct ctx_list));
+       for(ctx = 0; ctx < numctx; ctx++) {
+               struct ctx_list *clist;
+
+               clist = (ctx_list_pool + ctx);
+               clist->ctx_number = ctx;
+               clist->ctx_mm = 0;
+       }
+       ctx_free.next = ctx_free.prev = &ctx_free;
+       ctx_used.next = ctx_used.prev = &ctx_used;
+       for(ctx = 0; ctx < numctx; ctx++)
+               add_to_free_ctxlist(ctx_list_pool + ctx);
+       return start_mem;
+}
+
 /*
  * paging_init() sets up the page tables: We call the MMU specific
  * init routine based upon the Sun model type on the Sparc.
@@ -95,7 +110,7 @@ extern pgprot_t protection_map[16];
  */
 extern unsigned long sun4c_paging_init(unsigned long, unsigned long);
 extern unsigned long srmmu_paging_init(unsigned long, unsigned long);
-extern unsigned long probe_devices(unsigned long);
+extern unsigned long device_scan(unsigned long);
 
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 {
@@ -109,10 +124,10 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
                start_mem = srmmu_paging_init(start_mem, end_mem);
                break;
        default:
-               printk("paging_init: Cannot init paging on this Sparc\n");
-               printk("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
-               printk("paging_init: Halting...\n");
-               panic("paging_init");
+               prom_printf("paging_init: Cannot init paging on this Sparc\n");
+               prom_printf("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
+               prom_printf("paging_init: Halting...\n");
+               prom_halt();
        };
 
        /* Initialize the protection map with non-constant values
@@ -134,13 +149,18 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        protection_map[13] = PAGE_READONLY;
        protection_map[14] = PAGE_SHARED;
        protection_map[15] = PAGE_SHARED;
-       return probe_devices(start_mem);
+       return device_scan(start_mem);
 }
 
 extern void sun4c_test_wp(void);
-extern void sun4c_lock_entire_kernel(unsigned long start_mem);
 extern void srmmu_test_wp(void);
 
+struct cache_palias *sparc_aliases;
+
+extern int min_free_pages;
+extern int free_pages_low;
+extern int free_pages_high;
+
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
        int codepages = 0;
@@ -148,6 +168,9 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
        unsigned long tmp2, addr;
        extern char etext;
 
+       /* Saves us work later. */
+       memset((void *) ZERO_PAGE, 0, PAGE_SIZE);
+
        end_mem &= PAGE_MASK;
        high_memory = end_mem;
 
@@ -189,10 +212,15 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
               codepages << (PAGE_SHIFT-10),
               datapages << (PAGE_SHIFT-10));
 
+       min_free_pages = nr_free_pages >> 7;
+       if(min_free_pages < 16)
+               min_free_pages = 16;
+       free_pages_low = min_free_pages + (min_free_pages >> 1);
+       free_pages_high = min_free_pages + min_free_pages;
+
        switch(sparc_cpu_model) {
        case sun4c:
        case sun4e:
-               sun4c_lock_entire_kernel(start_mem);
                sun4c_test_wp();
                break;
        case sun4m:
index e28c0ed9c3c78d96e6a4296080c9c3bd0783ae69..d5ee840af9d204c014b9c795e5b633efe79ddcad 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: loadmmu.c,v 1.13 1995/11/25 00:59:24 davem Exp $
+/* $Id: loadmmu.c,v 1.23 1996/02/21 17:56:35 miguel Exp $
  * loadmmu.c:  This code loads up all the mm function pointers once the
  *             machine type has been determined.  It also sets the static
  *             mmu values such as PAGE_NONE, etc.
@@ -16,22 +16,29 @@ struct ctx_list *ctx_list_pool;
 struct ctx_list ctx_free;
 struct ctx_list ctx_used;
 
-void (*mmu_exit_hook)(void *);
-void (*mmu_fork_hook)(void *, unsigned long);
-void (*mmu_release_hook)(void *);
-void (*mmu_flush_hook)(void *);
-void (*mmu_task_cacheflush)(void *);
+unsigned long (*alloc_kernel_stack)(struct task_struct *tsk);
+void (*free_kernel_stack)(unsigned long stack);
+struct task_struct *(*alloc_task_struct)(void);
+void (*free_task_struct)(struct task_struct *tsk);
+
+void (*quick_kernel_fault)(unsigned long);
+
+void (*mmu_exit_hook)(void);
+void (*mmu_flush_hook)(void);
 
 char *(*mmu_lockarea)(char *, unsigned long);
 void  (*mmu_unlockarea)(char *, unsigned long);
-char *(*mmu_get_scsi_buffer)(char *, unsigned long);
-void  (*mmu_release_scsi_buffer)(char *, unsigned long);
+char *(*mmu_get_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus);
+void  (*mmu_release_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus);
 
 
-int (*get_fault_info)(unsigned long *, unsigned long *, unsigned long);
 void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long address, pte_t pte);
 
-void (*invalidate)(void);
+void (*invalidate_all)(void);
+void (*invalidate_mm)(struct mm_struct *);
+void (*invalidate_range)(struct mm_struct *, unsigned long start, unsigned long end);
+void (*invalidate_page)(struct vm_area_struct *, unsigned long address);
+
 void (*set_pte)(pte_t *pteptr, pte_t pteval);
 
 unsigned int pmd_shift, pmd_size, pmd_mask;
@@ -39,9 +46,9 @@ unsigned int (*pmd_align)(unsigned int);
 unsigned int pgdir_shift, pgdir_size, pgdir_mask;
 unsigned int (*pgdir_align)(unsigned int);
 unsigned int ptrs_per_pte, ptrs_per_pmd, ptrs_per_pgd;
+unsigned int pg_iobits;
 
 pgprot_t page_none, page_shared, page_copy, page_readonly, page_kernel;
-pgprot_t page_invalid;
 
 unsigned long (*pte_page)(pte_t);
 unsigned long (*pmd_page)(pmd_t);
@@ -49,7 +56,7 @@ unsigned long (*pgd_page)(pgd_t);
 
 void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
 unsigned long (*(vmalloc_start))(void);
-void (*switch_to_context)(void *vtask);
+void (*switch_to_context)(struct task_struct *tsk);
 
 int (*pte_none)(pte_t);
 int (*pte_present)(pte_t);
@@ -72,6 +79,7 @@ void (*pgd_clear)(pgd_t *);
 void (*pgd_reuse)(pgd_t *);
 
 pte_t (*mk_pte)(unsigned long, pgprot_t);
+pte_t (*mk_pte_io)(unsigned long, pgprot_t);
 void (*pgd_set)(pgd_t *, pmd_t *);
 pte_t (*pte_modify)(pte_t, pgprot_t);
 pgd_t * (*pgd_offset)(struct mm_struct *, unsigned long);
@@ -91,28 +99,18 @@ void (*pgd_free)(pgd_t *);
 
 pgd_t * (*pgd_alloc)(void);
 
-int (*pte_read)(pte_t);
 int (*pte_write)(pte_t);
-int (*pte_exec)(pte_t);
 int (*pte_dirty)(pte_t);
 int (*pte_young)(pte_t);
-int (*pte_cow)(pte_t);
 
 pte_t (*pte_wrprotect)(pte_t);
-pte_t (*pte_rdprotect)(pte_t);
-pte_t (*pte_exprotect)(pte_t);
 pte_t (*pte_mkclean)(pte_t);
 pte_t (*pte_mkold)(pte_t);
-pte_t (*pte_uncow)(pte_t);
 pte_t (*pte_mkwrite)(pte_t);
-pte_t (*pte_mkread)(pte_t);
-pte_t (*pte_mkexec)(pte_t);
 pte_t (*pte_mkdirty)(pte_t);
 pte_t (*pte_mkyoung)(pte_t);
-pte_t (*pte_mkcow)(pte_t);
 
-unsigned long (*sparc_virt_to_phys)(unsigned long);
-unsigned long (*sparc_phys_to_virt)(unsigned long);
+char *(*mmu_info)(void);
 
 extern void ld_mmu_sun4c(void);
 extern void ld_mmu_srmmu(void);
diff --git a/arch/sparc/mm/s4cflsh.S b/arch/sparc/mm/s4cflsh.S
new file mode 100644 (file)
index 0000000..3f287f3
--- /dev/null
@@ -0,0 +1,49 @@
+/* s4cflsh.S: Low-level segment cache flush routines, shared by
+ *            the kernel and user in-window tlb refill routines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include "s4clow.h"
+
+/* %g1 -- base address of segment to flush
+ * %g4 -- pc of caller
+ */
+       .text
+       .align  4
+       .globl  sun4c_segment_cache_flush
+sun4c_segment_cache_flush:
+       std     %g0, [REGSAVE_BASE + FLUSHREGS + 0x0]
+       std     %g2, [REGSAVE_BASE + FLUSHREGS + 0x8]
+       set     C_LABEL(sun4c_vacinfo), %g2
+       ld      [%g2 + VACINFO_HWFLSH], %g3
+       cmp     %g3, 0x0
+       ld      [%g2 + VACINFO_SIZE], %g3
+       add     %g1, %g3, %g3
+       be,a    sw_flush
+        ld     [%g2 + VACINFO_LSIZE], %g2
+
+       /* Hardware flush */
+       sethi   %hi(PAGE_SIZE), %g2
+       sta     %g0, [%g1] 0x05
+1:
+       add     %g1, %g2, %g1
+       cmp     %g1, %g3
+       blu,a   1b
+        sta    %g0, [%g1] 0x05
+
+       ldd     [REGSAVE_BASE + FLUSHREGS + 0x0], %g0
+       jmpl    %g4, %g0
+        ldd    [REGSAVE_BASE + FLUSHREGS + 0x8], %g2
+
+sw_flush:
+       sta     %g0, [%g1] 0x0c
+2:
+       add     %g1, %g2, %g1
+       cmp     %g1, %g3
+       blu,a   2b
+        sta    %g0, [%g1] 0x0c
+
+       ldd     [REGSAVE_BASE + FLUSHREGS + 0x0], %g0
+       jmpl    %g4, %g0
+        ldd    [REGSAVE_BASE + FLUSHREGS + 0x8], %g2
diff --git a/arch/sparc/mm/s4cflush.S b/arch/sparc/mm/s4cflush.S
deleted file mode 100644 (file)
index 92c9ec0..0000000
+++ /dev/null
@@ -1,575 +0,0 @@
-/* $Id: s4cflush.S,v 1.8 1995/11/25 00:59:29 davem Exp $
- * s4cflush.S: Inline management of the sun4c cache.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/head.h>
-#include <asm/cprefix.h>
-#include <asm/asi.h>
-#include <asm/page.h>
-
-/* We need to be able to call a routine which will in low-level
- * assembly flush an entire segment from the virtual cache using
- * a base virtual address and that will use as few registers as
- * possible.  The address of that function is stored here.
- * The register usage for this routine is defined as
- * %l2 -- Address of Segment to flush
- * %l4 -- Return address
- * %l6 -- scratch
- * %l7 -- scratch
- */
-       .align  4
-       .globl  C_LABEL(sun4c_ctxflush), C_LABEL(sun4c_segflush)
-       .globl  C_LABEL(sun4c_pgflush)
-C_LABEL(sun4c_ctxflush):       .word   C_LABEL(sun4c_ctxflush_sw64KB16B)
-C_LABEL(sun4c_segflush):       .word   C_LABEL(sun4c_segflush_sw64KB16B)
-C_LABEL(sun4c_pgflush):                .word   C_LABEL(sun4c_pgflush_sw64KB16B)
-
-       .text
-
-       /* Here are the assembly in-line virtual cache flushing
-        * routines on the sun4c.
-        */
-
-       .align 4
-       .globl C_LABEL(sun4c_ctxflush_hw64KB16B)
-
-       /* Flush an entire context using hardware assisted flushes
-        * for a cache of size 64KB with 16B lines.
-        */
-C_LABEL(sun4c_ctxflush_hw64KB16B):
-       sethi   %hi(PAGE_SIZE), %l6
-       /* Now flush 16 pages starting at virtual address zero */
-       or      %g0, %g0, %l7   
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* One */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Two */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Three */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Four */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Five */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Six */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Seven */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Eight */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Nine */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Ten */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Eleven */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Twelve */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Thirteen */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Fourteen */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Fifteen */
-       add     %l7, %l6, %l7
-
-       /* Return to caller and flush the last page */
-       jmpl    %l4 + 0x8, %g0
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Sixteen */
-
-
-       .globl C_LABEL(sun4c_ctxflush_sw64KB16B)
-
-       /* Flush an entire context using software flushes
-        * for a cache of size 64KB with 16B lines.
-        */
-C_LABEL(sun4c_ctxflush_sw64KB16B):
-       /* Starting at virtual address zero, software flush
-        * 4096 lines at 16 byte intervals.
-        */
-#define SWFLUSHCTX16_2LINES \
-       sta     %g0, [%l7] ASI_FLUSHCTX; \
-       add     %l7, 0x10, %l7; \
-       sta     %g0, [%l7] ASI_FLUSHCTX; \
-       add     %l7, 0x10, %l7; \
-
-#define SWFLUSHCTX16_4LINES \
-       SWFLUSHCTX16_2LINES \
-       SWFLUSHCTX16_2LINES \
-       
-#define SWFLUSHCTX16_8LINES \
-       SWFLUSHCTX16_4LINES \
-       SWFLUSHCTX16_4LINES \
-       
-#define SWFLUSHCTX16_16LINES \
-       SWFLUSHCTX16_8LINES \
-       SWFLUSHCTX16_8LINES \
-       
-#define SWFLUSHCTX16_32LINES \
-       SWFLUSHCTX16_16LINES \
-       SWFLUSHCTX16_16LINES \
-       
-#define SWFLUSHCTX16_64LINES \
-       SWFLUSHCTX16_32LINES \
-       SWFLUSHCTX16_32LINES \
-       
-#define SWFLUSHCTX16_128LINES \
-       SWFLUSHCTX16_64LINES \
-       SWFLUSHCTX16_64LINES \
-       
-#define SWFLUSHCTX16_256LINES \
-       SWFLUSHCTX16_128LINES \
-       SWFLUSHCTX16_128LINES \
-       
-       /* WHEE! */
-       or      %g0, %g0, %l7           /* Base register */
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-
-       /* Done, return to caller */
-       jmpl    %l4 + 0x8, %g0
-       nop
-
-       .globl C_LABEL(sun4c_ctxflush_hw64KB32B)
-       /* Flush an entire context using hardware assisted flushes
-        * for a cache of size 64KB with 32B lines.
-        */
-C_LABEL(sun4c_ctxflush_hw64KB32B):
-       sethi   %hi(PAGE_SIZE), %l6
-       /* Now flush 16 pages starting at virtual address zero */
-       or      %g0, %g0, %l7   
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* One */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Two */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Three */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Four */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Five */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Six */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Seven */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Eight */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Nine */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Ten */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Eleven */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Twelve */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Thirteen */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Fourteen */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Fifteen */
-       add     %l7, %l6, %l7
-
-       /* Return to caller and flush the last page */
-       jmpl    %l4 + 0x8, %g0
-       sta     %g0, [%l7] ASI_HWFLUSHCONTEXT   /* Sixteen */
-
-       .globl C_LABEL(sun4c_ctxflush_sw64KB32B)
-
-       /* Flush an entire context using software flushes
-        * for a cache of size 64KB with 32B lines.
-        */
-C_LABEL(sun4c_ctxflush_sw64KB32B):
-       /* Starting at virtual address zero, software flush
-        * 2048 lines at 32 byte intervals.
-        */
-#define SWFLUSHCTX32_2LINES \
-       sta     %g0, [%l7] ASI_FLUSHCTX; \
-       add     %l7, 0x20, %l7; \
-       sta     %g0, [%l7] ASI_FLUSHCTX; \
-       add     %l7, 0x20, %l7; \
-       
-#define SWFLUSHCTX32_4LINES \
-       SWFLUSHCTX32_2LINES \
-       SWFLUSHCTX32_2LINES \
-
-#define SWFLUSHCTX32_8LINES \
-       SWFLUSHCTX32_4LINES \
-       SWFLUSHCTX32_4LINES \
-
-#define SWFLUSHCTX32_16LINES \
-       SWFLUSHCTX32_8LINES \
-       SWFLUSHCTX32_8LINES \
-
-#define SWFLUSHCTX32_32LINES \
-       SWFLUSHCTX32_16LINES \
-       SWFLUSHCTX32_16LINES \
-
-#define SWFLUSHCTX32_64LINES \
-       SWFLUSHCTX32_32LINES \
-       SWFLUSHCTX32_32LINES \
-
-#define SWFLUSHCTX32_128LINES \
-       SWFLUSHCTX32_64LINES \
-       SWFLUSHCTX32_64LINES \
-
-       /* WHEE! */
-       or      %g0, %g0, %l7           /* Base register */
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX32_128LINES
-       SWFLUSHCTX16_256LINES
-       SWFLUSHCTX16_256LINES
-
-       jmpl    %l4 + 0x8, %g0
-       nop
-
-       .align 4
-       .globl C_LABEL(sun4c_segflush_hw64KB16B)
-
-       /* Flush an entire segment using hardware assisted flushes
-        * for a cache of size 64KB with 16B lines.
-        */
-C_LABEL(sun4c_segflush_hw64KB16B):
-       sethi   %hi(PAGE_SIZE), %l6     /* Increment */
-       sethi   %hi(0xfffc0000), %l7
-       and     %l2, %l7, %l7           /* Base address */
-
-       /* Now flush 16 pages starting at beginning of vseg */
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* One */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Two */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Three */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Four */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Five */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Six */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Seven */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Eight */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Nine */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Ten */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Eleven */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Twelve */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Thirteen */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Fourteen */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Fifteen */
-       add     %l7, %l6, %l7
-
-       /* Return to caller and flush the last page */
-       jmpl    %l4 + 0x8, %g0
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Sixteen */
-
-       .globl C_LABEL(sun4c_segflush_sw64KB16B)
-
-       /* Flush an entire segment using software flushes
-        * for a cache of size 64KB with 16B lines.
-        */
-C_LABEL(sun4c_segflush_sw64KB16B):
-       /* Starting at virtual address in %l2, software flush
-        * 4096 lines at 16 byte intervals.
-        */
-#define SWFLUSHSEG16_2LINES \
-       sta     %g0, [%l7] ASI_FLUSHSEG; \
-       add     %l7, 0x10, %l7; \
-       sta     %g0, [%l7] ASI_FLUSHSEG; \
-       add     %l7, 0x10, %l7; \
-
-#define SWFLUSHSEG16_4LINES \
-       SWFLUSHSEG16_2LINES \
-       SWFLUSHSEG16_2LINES \
-
-#define SWFLUSHSEG16_8LINES \
-       SWFLUSHSEG16_4LINES \
-       SWFLUSHSEG16_4LINES \
-
-#define SWFLUSHSEG16_16LINES \
-       SWFLUSHSEG16_8LINES \
-       SWFLUSHSEG16_8LINES \
-
-#define SWFLUSHSEG16_32LINES \
-       SWFLUSHSEG16_16LINES \
-       SWFLUSHSEG16_16LINES \
-
-#define SWFLUSHSEG16_64LINES \
-       SWFLUSHSEG16_32LINES \
-       SWFLUSHSEG16_32LINES \
-
-#define SWFLUSHSEG16_128LINES \
-       SWFLUSHSEG16_64LINES \
-       SWFLUSHSEG16_64LINES \
-
-#define SWFLUSHSEG16_256LINES \
-       SWFLUSHSEG16_128LINES \
-       SWFLUSHSEG16_128LINES \
-
-       sethi   %hi(0xfffc0000), %l7
-       and     %l2, %l7, %l7           /* Base register */
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-       SWFLUSHSEG16_256LINES
-
-       /* Done, return to caller */
-       jmpl    %l4 + 0x8, %g0
-       nop
-
-       .globl C_LABEL(sun4c_segflush_hw64KB32B)
-
-       /* Flush an entire segment using hardware assisted flushes
-        * for a cache of size 64KB with 32B lines.
-        */
-C_LABEL(sun4c_segflush_hw64KB32B):
-       sethi   %hi(PAGE_SIZE), %l6     /* Increment */
-       sethi   %hi(0xfffc0000), %l7
-       and     %l2, %l7, %l7           /* Base register */
-
-       /* Now flush 16 pages starting at virtual address in %l7 */
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* One */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Two */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Three */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Four */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Five */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Six */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Seven */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Eight */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Nine */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Ten */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Eleven */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Twelve */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Thirteen */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Fourteen */
-       add     %l7, %l6, %l7
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Fifteen */
-       add     %l7, %l6, %l7
-
-       /* Return to caller and flush the last page */
-       jmpl    %l4 + 0x8, %g0
-       sta     %g0, [%l7] ASI_HWFLUSHSEG   /* Sixteen */
-       
-       .globl C_LABEL(sun4c_segflush_sw64KB32B)
-
-       /* Flush an entire segment using software flushes
-        * for a cache of size 64KB with 32B lines.
-        */
-C_LABEL(sun4c_segflush_sw64KB32B):
-       /* Starting at virtual address passed in %l2, software
-        * flush 2048 lines at 32 byte intervals.
-        */
-#define SWFLUSHSEG32_2LINES \
-       sta     %g0, [%l7] ASI_FLUSHSEG; \
-       add     %l7, 0x20, %l7; \
-       sta     %g0, [%l7] ASI_FLUSHSEG; \
-       add     %l7, 0x20, %l7; \
-
-#define SWFLUSHSEG32_4LINES \
-       SWFLUSHSEG32_2LINES \
-       SWFLUSHSEG32_2LINES \
-
-#define SWFLUSHSEG32_8LINES \
-       SWFLUSHSEG32_4LINES \
-       SWFLUSHSEG32_4LINES \
-
-#define SWFLUSHSEG32_16LINES \
-       SWFLUSHSEG32_8LINES \
-       SWFLUSHSEG32_8LINES \
-
-#define SWFLUSHSEG32_32LINES \
-       SWFLUSHSEG32_16LINES \
-       SWFLUSHSEG32_16LINES \
-
-#define SWFLUSHSEG32_64LINES \
-       SWFLUSHSEG32_32LINES \
-       SWFLUSHSEG32_32LINES \
-
-#define SWFLUSHSEG32_128LINES \
-       SWFLUSHSEG32_64LINES \
-       SWFLUSHSEG32_64LINES \
-
-       /* WHEE! */
-       sethi   %hi(0xfffc0000), %l7
-       and     %l2, %l7, %l7           /* Base register */
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-       SWFLUSHSEG32_128LINES
-
-       jmpl    %l4 + 0x8, %g0
-       nop
-
-       .align 4
-       .globl C_LABEL(sun4c_pgflush_hw64KB16B)
-       .globl C_LABEL(sun4c_pgflush_hw64KB32B)
-
-       /* Flush a page using hardware assisted flushes
-        * for a cache of size 64KB with 16B or 32B lines.
-        */
-C_LABEL(sun4c_pgflush_hw64KB16B):
-C_LABEL(sun4c_pgflush_hw64KB32B):
-       /* Easiest flush possible on sun4c */
-       jmpl    %l4 + 0x8, %g0
-       sta     %g0, [%l2] ASI_HWFLUSHPAGE
-
-       .globl  C_LABEL(sun4c_pgflush_sw64KB16B)
-       /* Flush a page using software flushes for a cache
-        * of size 64KB with 16B lines.
-        */
-C_LABEL(sun4c_pgflush_sw64KB16B):
-       /* Flush every line within the page */
-#define SWFLUSHPG16_2LINES \
-       sta     %g0, [%l7] ASI_FLUSHPG; \
-       add     %l7, 0x10, %l7; \
-       sta     %g0, [%l7] ASI_FLUSHPG; \
-       add     %l7, 0x10, %l7; \
-
-#define SWFLUSHPG16_4LINES \
-       SWFLUSHPG16_2LINES \
-       SWFLUSHPG16_2LINES \
-
-#define SWFLUSHPG16_8LINES \
-       SWFLUSHPG16_4LINES \
-       SWFLUSHPG16_4LINES \
-
-#define SWFLUSHPG16_16LINES \
-       SWFLUSHPG16_8LINES \
-       SWFLUSHPG16_8LINES \
-
-#define SWFLUSHPG16_32LINES \
-       SWFLUSHPG16_16LINES \
-       SWFLUSHPG16_16LINES \
-
-#define SWFLUSHPG16_64LINES \
-       SWFLUSHPG16_32LINES \
-       SWFLUSHPG16_32LINES \
-
-#define SWFLUSHPG16_128LINES \
-       SWFLUSHPG16_64LINES \
-       SWFLUSHPG16_64LINES \
-
-#define SWFLUSHPG16_256LINES \
-       SWFLUSHPG16_128LINES \
-       SWFLUSHPG16_128LINES \
-
-       or      %l2, %g0, %l7           /* Base address of page */
-       SWFLUSHPG16_256LINES
-
-       /* Return to caller and flush last line */
-       jmpl    %l4 + 0x8, %g0
-       nop
-
-       .globl  C_LABEL(sun4c_pgflush_sw64KB32B)
-       /* Flush a page using software flushes for a cache
-        * of size 64KB with 32B lines.
-        */
-C_LABEL(sun4c_pgflush_sw64KB32B):
-       /* Flush every line within the page */
-#define SWFLUSHPG32_2LINES \
-       sta     %g0, [%l7] ASI_FLUSHPG; \
-       add     %l7, 0x20, %l7; \
-       sta     %g0, [%l7] ASI_FLUSHPG; \
-       add     %l7, 0x20, %l7; \
-
-#define SWFLUSHPG32_4LINES \
-       SWFLUSHPG32_2LINES \
-       SWFLUSHPG32_2LINES \
-
-#define SWFLUSHPG32_8LINES \
-       SWFLUSHPG32_4LINES \
-       SWFLUSHPG32_4LINES \
-
-#define SWFLUSHPG32_16LINES \
-       SWFLUSHPG32_8LINES \
-       SWFLUSHPG32_8LINES \
-
-#define SWFLUSHPG32_32LINES \
-       SWFLUSHPG32_16LINES \
-       SWFLUSHPG32_16LINES \
-
-#define SWFLUSHPG32_64LINES \
-       SWFLUSHPG32_32LINES \
-       SWFLUSHPG32_32LINES \
-
-#define SWFLUSHPG32_128LINES \
-       SWFLUSHPG32_64LINES \
-       SWFLUSHPG32_64LINES \
-
-       or      %l2, %g0, %l7           /* Base address of page */
-       SWFLUSHPG32_128LINES
-
-       /* Return to caller and flush last line */
-       jmpl    %l4 + 0x8, %g0
-       nop
-
-/* All that crap just to flush a fucking virtual cache, sheesh... */
diff --git a/arch/sparc/mm/s4ckflt.S b/arch/sparc/mm/s4ckflt.S
new file mode 100644 (file)
index 0000000..bb006ba
--- /dev/null
@@ -0,0 +1,105 @@
+/* s4ckflt.S:  Quick in window kernel faults on the sun4c.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include "s4clow.h"
+
+       .text
+       .align 8
+       .globl  sun4c_quick_kernel_fault
+sun4c_quick_kernel_fault:
+       sethi   %hi(REAL_PGDIR_MASK), %l5
+       and     %l7, %l5, %l7
+       sethi   %hi(C_LABEL(invalid_segment)), %l5
+       lduba   [%l7] 0x3, %l4
+       ld      [%l5 + %lo(C_LABEL(invalid_segment))], %l5
+       cmp     %l4, %l5
+       bne     segment_loaded
+        nop
+
+       /* We need some breathing room to pull this off, save
+        * away some globals.
+        */
+       std     %g0, [REGSAVE_BASE + KFLTREGS + 0x00]
+       std     %g2, [REGSAVE_BASE + KFLTREGS + 0x08]
+       std     %g4, [REGSAVE_BASE + KFLTREGS + 0x10]
+       std     %g6, [REGSAVE_BASE + KFLTREGS + 0x18]
+       std     %l0, [REGSAVE_BASE + KFLTREGS + 0x20]
+       std     %l2, [REGSAVE_BASE + KFLTREGS + 0x28]
+
+       set     C_LABEL(sun4c_kfree_ring), %g1
+       ld      [%g1 + RING_NENTRIES], %g2
+       cmp     %g2, 0x0
+       be,a    pseg_steal
+        nop
+
+       b       distribute_segmap
+        ld     [%g1 + RING_RINGHD + MMU_ENTRY_NEXT], %g2
+
+pseg_steal:
+       /* This is the hard case. */    
+       set     C_LABEL(sun4c_kernel_ring), %g1
+       ld      [%g1 + RING_RINGHD + MMU_ENTRY_PREV], %g2
+       b       kernel_segment_cache_flush
+        ld     [%g2 + MMU_ENTRY_VADDR], %l0
+
+pseg_steal_after_flush:
+       ld      [%g2 + MMU_ENTRY_VADDR], %l0
+       sethi   %hi(0x30000000), %l1
+       lduba   [%l1] 0x02, %g7
+       sethi   %hi(C_LABEL(num_contexts)), %g6
+       mov     0, %g5
+       ld      [%g6 + %lo(C_LABEL(num_contexts))], %g6
+1:
+       stba    %g5, [%l1] 0x02
+       add     %g5, 1, %g5
+       cmp     %g5, %g6
+       bl      1b
+        stba   %l5, [%l0] 0x03
+
+       stba    %g7, [%l1] 0x02
+
+       
+
+distribute_segmap:
+       st      %l7, [%g2 + MMU_ENTRY_VADDR]
+       ldub    [%g2 + MMU_ENTRY_PSEG], %g3
+       sethi   %hi(0x30000000), %l0
+       lduba   [%l0] 0x02, %g7
+       sethi   %hi(C_LABEL(num_contexts)), %g6
+       mov     0, %g5
+       ld      [%g6 + %lo(C_LABEL(num_contexts))], %g6
+1:
+       stba    %g5, [%l0] 0x02
+       add     %g5, 1, %g5
+       cmp     %g5, %g6
+       bl      1b
+        stba   %g3, [%l7] 0x03
+
+       stba    %g7, [%l0] 0x02
+
+segment_loaded:
+       sethi   %hi(VMALLOC_START), %l4
+       cmp     %l7, %l4
+       bge     vmalloc_kernel_fault
+        nop
+
+
+
+
+
+vmalloc_kernel_fault:
+
+
+qkf_exit:
+       /* Fault serviced, return from trap, but reload
+        * registers first.
+        */
+       ldd     [REGSAVE_BASE + KFLTREGS + 0x00], %g0
+       ldd     [REGSAVE_BASE + KFLTREGS + 0x08], %g2
+       ldd     [REGSAVE_BASE + KFLTREGS + 0x10], %g4
+       ldd     [REGSAVE_BASE + KFLTREGS + 0x18], %g6
+       ldd     [REGSAVE_BASE + KFLTREGS + 0x20], %l0
+       ldd     [REGSAVE_BASE + KFLTREGS + 0x28], %l2
+
diff --git a/arch/sparc/mm/s4clow.h b/arch/sparc/mm/s4clow.h
new file mode 100644 (file)
index 0000000..3c568f0
--- /dev/null
@@ -0,0 +1,48 @@
+/* s4clow.h: Defines for in-window low level tlb refill code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+#ifndef _SPARC_S4CLOW_H
+#define _SPARC_S4CLOW_H
+
+#define         PAGE_SIZE       0x00001000
+#define                REAL_PGDIR_MASK 0xfffc0000
+#define                VMALLOC_START   0xfe100000
+
+#define                RING_RINGHD     0x00
+#define                RING_NENTRIES   0x10
+
+#define                MMU_ENTRY_NEXT  0x00
+#define                MMU_ENTRY_PREV  0x04
+#define                MMU_ENTRY_VADDR 0x08
+#define                MMU_ENTRY_PSEG  0x0c
+#define                MMU_ENTRY_LCK   0x0d
+
+#define                VACINFO_SIZE    0x00
+#define                VACINFO_HWFLSH  0x08
+#define                VACINFO_LSIZE   0x0c
+
+/* Each of the routines could get called by any of the
+ * other low level sun4c tlb routines.  Well... at least
+ * we code it that way.  Because we are in window we need
+ * a way to make a routine completely self contained and
+ * only need to worry about saving it's own set of registers
+ * which it in fact uses.  With traps off this is difficult
+ * ... however...
+ *
+ * The Sparc can address anywhere in the two ranges
+ * 0 --> PAGE_SIZE and -PAGE_SIZE --> -1 without any
+ * address calculation registers.  So we pull a trick,
+ * we map a special page for these low level tlb routines
+ * since they must be as quick as possible.  Since the low
+ * page is the NULL unmapped page and in user space we use
+ * the high one for simplicity.  Kids, do not try this at
+ * home.
+ */
+#define          REGSAVE_BASE   (-PAGE_SIZE)
+
+#define          FLUSHREGS      0
+#define          KFLTREGS       256
+#define          UFLTREGS       512
+
+#endif /* !(_SPARC_S4CLOW_H) */
diff --git a/arch/sparc/mm/s4cuflt.S b/arch/sparc/mm/s4cuflt.S
new file mode 100644 (file)
index 0000000..7b11731
--- /dev/null
@@ -0,0 +1,20 @@
+/* s4cuflt.S:  Quick in window user tlb faults on the sun4c.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+       .data
+
+       .align  8
+.g0g1: .quad   0
+.g2g3: .quad   0
+.g4g5: .quad   0
+.g6g7: .quad   0
+
+#include "srclow.h"
+
+       .text
+
+       .align  8
+       .globl  sun4c_quick_user_fault
+sun4c_quick_user_fault:
index f11b059ea86624859a7962d3662c463eefa76228..0bd67118e60c8085dd2136976e69c3c726730c7d 100644 (file)
-/* $Id: srmmu.c,v 1.22 1995/11/25 00:59:33 davem Exp $
+/* $Id: srmmu.c,v 1.34 1996/03/01 07:16:23 davem 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@lab.ipmce.su)
+ * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru)
  */
 
-#include <linux/kernel.h>  /* for printk */
+#include <linux/kernel.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/io.h>
 #include <asm/kdebug.h>
 #include <asm/vaddrs.h>
 #include <asm/traps.h>
 #include <asm/mp.h>
+#include <asm/mbus.h>
 #include <asm/cache.h>
 #include <asm/oplib.h>
+#include <asm/sbus.h>
+#include <asm/iommu.h>
 
-extern unsigned long free_area_init(unsigned long, unsigned long);
+/* Now the cpu specific definitions. */
+#include <asm/viking.h>
+#include <asm/ross.h>
+#include <asm/tsunami.h>
+#include <asm/swift.h>
+
+enum mbus_module srmmu_modtype;
+unsigned int hwbug_bitmask;
+
+int hyper_cache_size;
 
-unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); }
-unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); }
+ctxd_t *srmmu_context_table;
 
-unsigned long
-srmmu_vmalloc_start(void)
+/* In general all page table modifications should use the V8 atomic
+ * swap instruction.  This insures the mmu and the cpu are in sync
+ * with respect to ref/mod bits in the page tables.
+ */
+static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value)
 {
-       return ((high_memory + SRMMU_VMALLOC_OFFSET) & ~(SRMMU_VMALLOC_OFFSET-1));
+       __asm__ __volatile__("swap [%1], %0\n\t" :
+                            "=&r" (value), "=&r" (addr) :
+                            "0" (value), "1" (addr));
+       return value;
 }
 
-unsigned long 
-srmmu_pmd_page(pmd_t pmd)
-{
-       unsigned long page;
+/* Functions really use this, not srmmu_swap directly. */
+#define srmmu_set_entry(ptr, newentry) \
+        srmmu_swap((unsigned long *) (ptr), (newentry))
 
-       page = (pmd_val(pmd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT;
-       return (page + PAGE_OFFSET);
-}
+/* We still don't use these at all, perhaps we don't need them
+ * at all.
+ */
+unsigned long (*srmmu_read_physical)(unsigned long paddr);
+void (*srmmu_write_physical)(unsigned long paddr, unsigned long word);
 
-unsigned long
-srmmu_pgd_page(pgd_t pgd)
+static unsigned long gensrmmu_read_physical(unsigned long paddr)
 {
-       unsigned long page;
+       unsigned long word;
 
-       page = (pgd_val(pgd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT;
-       return (page + PAGE_OFFSET);
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (word) :
+                            "r" (paddr), "i" (ASI_M_BYPASS) :
+                            "memory");
+       return word;
 }
 
-unsigned long 
-srmmu_pte_page(pte_t pte)
+static unsigned long msparc_read_physical(unsigned long paddr)
 {
-       unsigned long page;
+       unsigned long word, flags;
+
+       save_flags(flags); cli();
+       __asm__ __volatile__("lda [%%g0] %3, %%g1\n\t"
+                            "or  %%g1, %4, %%g2\n\t"
+                            "sta %%g2, [%%g0] %3\n\t"
+                            "lda [%1] %2, %0\n\t"
+                            "sta %%g1, [%%g0] %3\n\t" :
+                            "=r" (word) :
+                            "r" (paddr), "i" (ASI_M_BYPASS),
+                            "i" (ASI_M_MMUREGS), "r" (VIKING_ACENABLE) :
+                            "g1", "g2", "memory");
+       restore_flags(flags);
+       return word;
+}
 
-       page = (pte_val(pte) & (SRMMU_PTE_PPN_MASK)) << SRMMU_PTE_PPN_PADDR_SHIFT;
-       return (page + PAGE_OFFSET);
+static void gensrmmu_write_physical(unsigned long paddr, unsigned long word)
+{
+       __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+                            "r" (word), "r" (paddr), "i" (ASI_M_BYPASS) :
+                            "memory");
 }
 
-int srmmu_pte_none(pte_t pte)          { return !pte_val(pte); }
-int srmmu_pte_present(pte_t pte)       { return pte_val(pte) & SRMMU_ET_PTE; }
-int srmmu_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
-void srmmu_pte_clear(pte_t *ptep)      { pte_val(*ptep) = 0; }
-void srmmu_pte_reuse(pte_t *ptep)
+static void msparc_write_physical(unsigned long paddr, unsigned long word)
 {
-  if(!mem_map[MAP_NR(ptep)].reserved)
-    mem_map[MAP_NR(ptep)].count++;
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       __asm__ __volatile__("lda [%%g0] %3, %%g1\n\t"
+                            "or  %%g1, %4, %%g2\n\t"
+                            "sta %%g2, [%%g0] %3\n\t"
+                            "sta %0, [%1] %2\n\t"
+                            "sta %%g1, [%%g0] %3\n\t" : :
+                            "r" (word), "r" (paddr), "i" (ASI_M_BYPASS),
+                            "i" (ASI_M_MMUREGS), "r" (VIKING_ACENABLE) :
+                            "g1", "g2", "memory");
+       restore_flags(flags);
 }
 
-int srmmu_pmd_none(pmd_t pmd)          { return !pmd_val(pmd); }
-int srmmu_pmd_bad(pmd_t pmd)
+static unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); }
+static unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); }
+
+static unsigned long srmmu_vmalloc_start(void)
 {
-       return ((pmd_val(pmd)&SRMMU_ET_PTDBAD)==SRMMU_ET_PTDBAD) ||
-               (srmmu_pmd_page(pmd) > high_memory);
+       return SRMMU_VMALLOC_START;
 }
 
-int srmmu_pmd_present(pmd_t pmd)       { return pmd_val(pmd) & SRMMU_ET_PTD; }
-int srmmu_pmd_inuse(pmd_t *pmdp)        { return mem_map[MAP_NR(pmdp)].reserved || mem_map[MAP_NR(pmdp)].count != 1; }
-void srmmu_pmd_clear(pmd_t *pmdp)      { pmd_val(*pmdp) = 0; }
-void srmmu_pmd_reuse(pmd_t * pmdp)
+static unsigned long srmmu_pgd_page(pgd_t pgd)
+{ return PAGE_OFFSET + ((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); }
+
+static unsigned long srmmu_pmd_page(pmd_t pmd)
+{ return PAGE_OFFSET + ((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); }
+
+static unsigned long srmmu_pte_page(pte_t pte)
+{ return PAGE_OFFSET + ((pte_val(pte) & SRMMU_PTE_PMASK) << 4); }
+
+static int srmmu_pte_none(pte_t pte)          { return !pte_val(pte); }
+static int srmmu_pte_present(pte_t pte)
+{ return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); }
+
+static int srmmu_pte_inuse(pte_t *ptep)
+{ return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
+
+static void srmmu_pte_clear(pte_t *ptep)      { pte_val(*ptep) = 0; }
+static void srmmu_pte_reuse(pte_t *ptep)
 {
-        if (!mem_map[MAP_NR(pmdp)].reserved)
-                mem_map[MAP_NR(pmdp)].count++;
+       if(!mem_map[MAP_NR(ptep)].reserved)
+               mem_map[MAP_NR(ptep)].count++;
 }
 
-int srmmu_pgd_none(pgd_t pgd)          { return !pgd_val(pgd); }
-int srmmu_pgd_bad(pgd_t pgd)
+static int srmmu_pmd_none(pmd_t pmd)          { return !pmd_val(pmd); }
+static int srmmu_pmd_bad(pmd_t pmd)
+{ return (pmd_val(pmd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }
+
+static int srmmu_pmd_present(pmd_t pmd)
+{ return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); }
+
+static int srmmu_pmd_inuse(pmd_t *pmdp)
+{ return mem_map[MAP_NR(pmdp)].reserved || mem_map[MAP_NR(pmdp)].count != 1; }
+
+static void srmmu_pmd_clear(pmd_t *pmdp)      { pmd_val(*pmdp) = 0; }
+static void srmmu_pmd_reuse(pmd_t * pmdp)
 {
-       return ((pgd_val(pgd)&SRMMU_ET_PTDBAD)==SRMMU_ET_PTDBAD) ||
-               (srmmu_pgd_page(pgd) > high_memory);
+       if (!mem_map[MAP_NR(pmdp)].reserved)
+               mem_map[MAP_NR(pmdp)].count++;
 }
-int srmmu_pgd_present(pgd_t pgd)       { return pgd_val(pgd) & SRMMU_ET_PTD; }
-int srmmu_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)].reserved; }
-void srmmu_pgd_clear(pgd_t * pgdp)     { pgd_val(*pgdp) = 0; }
-void srmmu_pgd_reuse(pgd_t *pgdp)
+
+static int srmmu_pgd_none(pgd_t pgd)          { return !pgd_val(pgd); }
+static int srmmu_pgd_bad(pgd_t pgd)
+{ return (pgd_val(pgd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }
+
+static int srmmu_pgd_present(pgd_t pgd)
+{ return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); }
+
+static int srmmu_pgd_inuse(pgd_t *pgdp)       { return mem_map[MAP_NR(pgdp)].reserved; }
+static void srmmu_pgd_clear(pgd_t * pgdp)     { pgd_val(*pgdp) = 0; }
+static void srmmu_pgd_reuse(pgd_t *pgdp)
 {
-  if (!mem_map[MAP_NR(pgdp)].reserved)
-    mem_map[MAP_NR(pgdp)].count++;
+       if (!mem_map[MAP_NR(pgdp)].reserved)
+               mem_map[MAP_NR(pgdp)].count++;
 }
 
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-int srmmu_pte_read(pte_t pte)          { return (pte_val(pte) & _SRMMU_PAGE_RDONLY) || (pte_val(pte) & _SRMMU_PAGE_WRITE_USR); }
-int srmmu_pte_write(pte_t pte)         { return pte_val(pte) & _SRMMU_PAGE_WRITE_USR; }
-int srmmu_pte_exec(pte_t pte)          { return pte_val(pte) & _SRMMU_PAGE_EXEC; }
-int srmmu_pte_dirty(pte_t pte)         { return pte_val(pte) & _SRMMU_PAGE_DIRTY; }
-int srmmu_pte_young(pte_t pte)         { return pte_val(pte) & _SRMMU_PAGE_REF; }
-int srmmu_pte_cow(pte_t pte)           { return pte_val(pte) & _SRMMU_PAGE_COW; }
-
-/* When we change permissions, we first clear all bits in the ACCESS field
- * then apply the wanted bits.
- */
-pte_t srmmu_pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_EXEC; return pte; }
-pte_t srmmu_pte_rdprotect(pte_t pte)   { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_NOREAD; return pte; }
-pte_t srmmu_pte_exprotect(pte_t pte)   { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_WRITE_USR; return pte; }
-pte_t srmmu_pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_SRMMU_PAGE_DIRTY; return pte; }
-pte_t srmmu_pte_mkold(pte_t pte)       { pte_val(pte) &= ~_SRMMU_PAGE_REF; return pte; }
-pte_t srmmu_pte_uncow(pte_t pte)       { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_UNCOW; return pte; }
-pte_t srmmu_pte_mkwrite(pte_t pte)     { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_WRITE_USR; return pte; }
-pte_t srmmu_pte_mkread(pte_t pte)      { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_RDONLY; return pte; }
-pte_t srmmu_pte_mkexec(pte_t pte)      { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_EXEC; return pte; }
-pte_t srmmu_pte_mkdirty(pte_t pte)     { pte_val(pte) |= _SRMMU_PAGE_DIRTY; return pte; }
-pte_t srmmu_pte_mkyoung(pte_t pte)     { pte_val(pte) |= _SRMMU_PAGE_REF; return pte; }
-pte_t srmmu_pte_mkcow(pte_t pte)       { pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_COW; return pte; }
+static int srmmu_pte_write(pte_t pte)         { return pte_val(pte) & SRMMU_WRITE; }
+static int srmmu_pte_dirty(pte_t pte)         { return pte_val(pte) & SRMMU_DIRTY; }
+static int srmmu_pte_young(pte_t pte)         { return pte_val(pte) & SRMMU_REF; }
+
+static pte_t srmmu_pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~SRMMU_WRITE; return pte;}
+static pte_t srmmu_pte_mkclean(pte_t pte)     { pte_val(pte) &= ~SRMMU_DIRTY; return pte; }
+static pte_t srmmu_pte_mkold(pte_t pte)       { pte_val(pte) &= ~SRMMU_REF; return pte; }
+static pte_t srmmu_pte_mkwrite(pte_t pte)     { pte_val(pte) |= SRMMU_WRITE; return pte; }
+static pte_t srmmu_pte_mkdirty(pte_t pte)     { pte_val(pte) |= SRMMU_DIRTY; return pte; }
+static pte_t srmmu_pte_mkyoung(pte_t pte)     { pte_val(pte) |= SRMMU_REF; return pte; }
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-pte_t
-srmmu_mk_pte(unsigned long page, pgprot_t pgprot)
-{
-       pte_t pte;
-
-       if(page & (~PAGE_MASK)) panic("srmmu_mk_pte() called with unaligned page");
-       page = ((page - PAGE_OFFSET) >> SRMMU_PTE_PPN_PADDR_SHIFT);
-       pte_val(pte) = (page & SRMMU_PTE_PPN_MASK);
-       pte_val(pte) |= pgprot_val(pgprot);
-       return pte;
-}
+static pte_t srmmu_mk_pte(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = ((page - PAGE_OFFSET) >> 4) | pgprot_val(pgprot); return pte; }
 
-void
-srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{
-       unsigned long page = (unsigned long) pmdp;
-
-       page = ((page - PAGE_OFFSET) >> SRMMU_PTD_PTP_PADDR_SHIFT);
+static pte_t srmmu_mk_pte_io(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = ((page) >> 4) | pgprot_val(pgprot); return pte; }
 
-       pgd_val(*pgdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD);
-}
-
-void
-srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
-{
-       unsigned long page = (unsigned long) ptep;
+static void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
+{ srmmu_set_entry(ctxp, (SRMMU_ET_PTD | ((((unsigned long) pgdp) - PAGE_OFFSET) >> 4))); }
 
-       page = ((page - PAGE_OFFSET) >> SRMMU_PTD_PTP_PADDR_SHIFT);
+static void srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{ srmmu_set_entry(pgdp, (SRMMU_ET_PTD | ((((unsigned long) pmdp) - PAGE_OFFSET) >> 4))); }
 
-       pmd_val(*pmdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD);
-}
+static void srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{ srmmu_set_entry(pmdp, (SRMMU_ET_PTD | ((((unsigned long) ptep) - PAGE_OFFSET) >> 4))); }
 
-pte_t
-srmmu_pte_modify(pte_t pte, pgprot_t newprot)
-{
-       pte_val(pte) = (pte_val(pte) & (~SRMMU_PTE_ACC_MASK)) | pgprot_val(newprot);
-       return pte;
-}
+static pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & ~0xff) | pgprot_val(newprot); return pte; }
 
 /* to find an entry in a top-level page table... */
-pgd_t *
-srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
+static pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
 {
        return mm->pgd + ((address >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1));
 }
 
 /* Find an entry in the second-level page table.. */
-pmd_t *
-srmmu_pmd_offset(pgd_t * dir, unsigned long address)
+static pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address)
 {
-       return ((pmd_t *) pgd_page(*dir)) +
-               ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
+       return (pmd_t *) pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
 }
 
 /* Find an entry in the third-level page table.. */ 
-pte_t *
-srmmu_pte_offset(pmd_t * dir, unsigned long address)
+static pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address)
 {
-       return ((pte_t *) pmd_page(*dir)) +
-               ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
+       return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
 }
 
-/* This must update the context register for this process. */
-void
-srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir) 
+/* This must update the context table entry for this process. */
+static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) 
 {
-       /* See if this process has a context entry already, like after execve() */
-       if(tsk->tss.context != -1) {
-               pgd_t *ctable_ptr = 0;
-               ctable_ptr = (pgd_t *) (srmmu_get_ctable_ptr() + PAGE_OFFSET);
-               ctable_ptr += tsk->tss.context;
-               srmmu_pgd_set(ctable_ptr, (pmd_t *) pgdir);
-               /* Should flush caches here too... */
-               srmmu_flush_whole_tlb();
-       }
-
-       tsk->tss.pgd_ptr = (unsigned long) pgdir;
-
-       return;
+       if(tsk->mm->context != NO_CONTEXT)
+               srmmu_ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
 }
 
 /*
@@ -212,346 +233,705 @@ srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
  * used to allocate a kernel page table - this turns on ASN bits
  * if any, and marks the page tables reserved.
  */
-void
-srmmu_pte_free_kernel(pte_t *pte)
+static void srmmu_pte_free_kernel(pte_t *pte)
 {
        mem_map[MAP_NR(pte)].reserved = 0;
        free_page((unsigned long) pte);
 }
 
-pte_t *
-srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+static pte_t *srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
-       pte_t *page;
-
        address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
-       if (srmmu_pmd_none(*pmd)) {
-               page = (pte_t *) get_free_page(GFP_KERNEL);
-               if (srmmu_pmd_none(*pmd)) {
-                       if (page) {
+       if(srmmu_pmd_none(*pmd)) {
+               pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
+               if(srmmu_pmd_none(*pmd)) {
+                       if(page) {
                                srmmu_pmd_set(pmd, page);
                                mem_map[MAP_NR(page)].reserved = 1;
                                return page + address;
                        }
-                       srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+                       srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
                        return NULL;
                }
                free_page((unsigned long) page);
        }
-       if (srmmu_pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-               srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+       if(srmmu_pmd_bad(*pmd)) {
+               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+               srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
                return NULL;
        }
        return (pte_t *) srmmu_pmd_page(*pmd) + address;
 }
 
-/* Full three level on SRMMU */
-void
-srmmu_pmd_free_kernel(pmd_t *pmd)
+static void srmmu_pmd_free_kernel(pmd_t *pmd)
 {
        mem_map[MAP_NR(pmd)].reserved = 0;
        free_page((unsigned long) pmd);
 }
 
-pmd_t *
-srmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+static pmd_t *srmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
 {
-       pmd_t *page;
-
        address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
-       if (srmmu_pgd_none(*pgd)) {
-               page = (pmd_t *) get_free_page(GFP_KERNEL);
-               if (srmmu_pgd_none(*pgd)) {
-                       if (page) {
+       if(srmmu_pgd_none(*pgd)) {
+               pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
+               if(srmmu_pgd_none(*pgd)) {
+                       if(page) {
                                srmmu_pgd_set(pgd, page);
                                mem_map[MAP_NR(page)].reserved = 1;
                                return page + address;
                        }
-                       srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+                       srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
                        return NULL;
                }
                free_page((unsigned long) page);
        }
-       if (srmmu_pgd_bad(*pgd)) {
-               printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
-               srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+       if(srmmu_pgd_bad(*pgd)) {
+               printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+               srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
                return NULL;
        }
-       return (pmd_t *) srmmu_pgd_page(*pgd) + address;
+       return (pmd_t *) pgd_page(*pgd) + address;
 }
 
-void
-srmmu_pte_free(pte_t *pte)
+static void srmmu_pte_free(pte_t *pte)
 {
        free_page((unsigned long) pte);
 }
 
-pte_t *
-srmmu_pte_alloc(pmd_t * pmd, unsigned long address)
+static pte_t *srmmu_pte_alloc(pmd_t * pmd, unsigned long address)
 {
-       pte_t *page;
-
        address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
-       if (srmmu_pmd_none(*pmd)) {
-               page = (pte_t *) get_free_page(GFP_KERNEL);
-               if (srmmu_pmd_none(*pmd)) {
-                       if (page) {
+       if(srmmu_pmd_none(*pmd)) {
+               pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
+               if(srmmu_pmd_none(*pmd)) {
+                       if(page) {
                                srmmu_pmd_set(pmd, page);
                                return page + address;
                        }
-                       srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+                       srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
                        return NULL;
                }
                free_page((unsigned long) page);
        }
-       if (srmmu_pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-               srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+       if(srmmu_pmd_bad(*pmd)) {
+               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+               srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
                return NULL;
        }
-       return (pte_t *) srmmu_pmd_page(*pmd) + address;
+       return (pte_t *) pmd_page(*pmd) + address;
 }
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-void 
-srmmu_pmd_free(pmd_t * pmd)
+/* Real three-level page tables on SRMMU. */
+static void srmmu_pmd_free(pmd_t * pmd)
 {
        free_page((unsigned long) pmd);
 }
 
-pmd_t *
-srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
+static pmd_t *srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
 {
-       pmd_t *page;
-
        address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
-       if (srmmu_pgd_none(*pgd)) {
-               page = (pmd_t *) get_free_page(GFP_KERNEL);
-               if (srmmu_pgd_none(*pgd)) {
-                       if (page) {
+       if(srmmu_pgd_none(*pgd)) {
+               pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
+               if(srmmu_pgd_none(*pgd)) {
+                       if(page) {
                                srmmu_pgd_set(pgd, page);
                                return page + address;
                        }
-                       srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+                       srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
                        return NULL;
                }
                free_page((unsigned long) page);
        }
-       if (srmmu_pgd_bad(*pgd)) {
-               printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
-               srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+       if(srmmu_pgd_bad(*pgd)) {
+               printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+               srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
                return NULL;
        }
        return (pmd_t *) srmmu_pgd_page(*pgd) + address;
 }
 
-void
-srmmu_pgd_free(pgd_t *pgd)
+static void srmmu_pgd_free(pgd_t *pgd)
 {
        free_page((unsigned long) pgd);
 }
 
-/* A page directory on the srmmu needs 1k, but for now to simplify the
- * alignment constraints and allocation we just grab a whole page.
+static pgd_t *srmmu_pgd_alloc(void)
+{
+       return (pgd_t *) get_free_page(GFP_KERNEL);
+}
+
+/* Tsunami invalidates.  It's page level tlb invalidation is not very
+ * useful at all, you must be in the context that page exists in to
+ * get a match.  It might be worthwhile to try someday though...
  */
+/* static */ inline void tsunami_invalidate_all(void)
+{
+       tsunami_invalidate_icache();
+       tsunami_invalidate_dcache();
+       srmmu_flush_whole_tlb();
+}
+static void tsunami_invalidate_mm(struct mm_struct *mm)
+{
+       tsunami_invalidate_all();
+}
 
-pgd_t *
-srmmu_pgd_alloc(void)
+static void tsunami_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-       return (pgd_t *) get_free_page(GFP_KERNEL);
+       tsunami_invalidate_all();
+}
+
+/* XXX do page level tlb flushes at some point XXX */
+static void tsunami_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+{
+       tsunami_invalidate_all();
 }
 
-/* Just flush the whole thing for now. We will need module
- * specific invalidate routines in certain circumstances,
- * because of different flushing facilities and hardware
- * bugs.
+/* Swift invalidates.  It has the recommended SRMMU specification flushing
+ * facilities, so we can do things in a more fine grained fashion than we
+ * could on the tsunami.  Let's watch out for HARDWARE BUGS...
  */
-void
-srmmu_invalidate(void)
+static inline void swift_invalidate_all(void)
 {
+       unsigned long addr = 0;
+
+       /* Invalidate all cache tags */
+       for(addr = 0; addr < (PAGE_SIZE << 2); addr += 16) {
+               swift_inv_insn_tag(addr); /* whiz- */
+               swift_inv_data_tag(addr); /* bang */
+       }
        srmmu_flush_whole_tlb();
-       return;
 }
 
-/* XXX Needs to be written */
-void srmmu_set_pte(pte_t *ptep, pte_t pteval)
+static void swift_invalidate_mm(struct mm_struct *mm)
 {
-       /* More than this is needed. */
-       *ptep = pteval;
+       unsigned long flags;
+       int cc, ncc = mm->context;
+
+       if(ncc == NO_CONTEXT)
+               return;
+
+       /* have context will travel... */
+       save_flags(flags); cli();
+       cc = srmmu_get_context();
+       if(cc != ncc)
+               srmmu_set_context(ncc);
+
+       swift_flush_context(); /* POOF! */
+       srmmu_flush_tlb_ctx(); /* POW! */
+
+       if(cc != ncc)
+               srmmu_set_context(cc);
+       restore_flags(flags);
 }
 
-/* XXX Needs to be written */
-void
-srmmu_switch_to_context(void *vtask)
+static void swift_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-       struct task_struct *tsk = vtask;
-       printk("switching to context %d\n", tsk->tss.context);
+       unsigned long flags, addr;
+       int cc, ncc = mm->context;
+
+       if(ncc == NO_CONTEXT)
+               return;
+
+       save_flags(flags); cli();
+       cc = srmmu_get_context();
+       if(cc != ncc)
+               srmmu_set_context(ncc);
+
+       /* XXX Inefficient, we don't do the best we can... XXX */
+       addr = start & SRMMU_PGDIR_MASK;
+       while(addr < end) {
+               swift_flush_region(addr);
+               srmmu_flush_tlb_region(addr);
+               addr += SRMMU_PGDIR_SIZE;
+       }
 
-       return;
+       if(cc != ncc)
+               srmmu_set_context(cc);
+       restore_flags(flags);
 }
 
-/* Low level IO area allocation on the SRMMU.
- *
- * I think we can get away with just using a regular page translation,
- * just making sure the cacheable bit is off.  I would like to avoid
- * having to mess with the IOMMU if at all possible at first.
+static void swift_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+{
+       unsigned long flags;
+       int cc, ncc = vmp->vm_mm->context;
+
+       if(ncc == NO_CONTEXT)
+               return;
+
+       save_flags(flags); cli();
+       cc = srmmu_get_context();
+       if(cc != ncc)
+               srmmu_set_context(ncc);
+
+       swift_flush_page(page);
+       srmmu_flush_tlb_page(page);
+
+       if(cc != ncc)
+               srmmu_set_context(cc);
+       restore_flags(flags);
+}
+
+/* The following are all MBUS based SRMMU modules, and therefore could
+ * be found in a multiprocessor configuration.
+ */
+
+/* Viking invalidates.  For Sun's mainline MBUS processor it is pretty much
+ * a crappy mmu.  The on-chip I&D caches only have full flushes, no fine
+ * grained cache invalidations.  It only has these "flash clear" things
+ * just like the MicroSparcI.  Added to this many revs of the chip are
+ * teaming with hardware buggery.
  *
- * Aparently IOMMU is only necessary for SBus devices, maybe VME too.
- * We'll see...
+ * XXX need to handle SMP broadcast invalidations! XXX
  */
-void
-srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
-               int bus_type, int rdonly)
+static inline void viking_invalidate_all(void)
+{
+       viking_flush_icache();
+       viking_flush_dcache();
+       srmmu_flush_whole_tlb();
+}
+static void viking_invalidate_mm(struct mm_struct *mm)
 {
-  pgd_t *pgdp;
-  pmd_t *pmdp;
-  pte_t *ptep;
+       unsigned long flags;
+       int cc, ncc = mm->context;
 
-  pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
-  pmdp = srmmu_pmd_offset(pgdp, virt_addr);
-  ptep = srmmu_pte_offset(pmdp, virt_addr);
-  pte_val(*ptep) = (physaddr >> SRMMU_PTE_PPN_PADDR_SHIFT) & SRMMU_PTE_PPN_MASK;
+       if(ncc == NO_CONTEXT)
+               return;
 
-  if(!rdonly)
-         pte_val(*ptep) |= (SRMMU_ACC_S_RDWREXEC | SRMMU_ET_PTE);
-  else
-         pte_val(*ptep) |= (SRMMU_ACC_S_RDEXEC | SRMMU_ET_PTE);
+       save_flags(flags); cli();
+       cc = srmmu_get_context();
+       if(cc != ncc)
+               srmmu_set_context(ncc);
 
-  pte_val(*ptep) |= (bus_type << 28);
-  pte_val(*ptep) &= ~(SRMMU_PTE_C_MASK); /* Make sure cacheable bit is off. */
-  srmmu_flush_whole_tlb();
-  flush_ei_ctx(0x0);
+       viking_flush_icache();
+       viking_flush_dcache();
+       srmmu_flush_tlb_ctx();
 
-  return;
+       if(cc != ncc)
+               srmmu_set_context(cc);
+       restore_flags(flags);
 }
 
-char *srmmu_lockarea(char *vaddr, unsigned long len)
+static void viking_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-       return vaddr;
+       unsigned long flags, addr;
+       int cc, ncc = mm->context;
+
+       if(ncc == NO_CONTEXT)
+               return;
+
+       save_flags(flags); cli();
+       cc = srmmu_get_context();
+       if(cc != ncc)
+               srmmu_set_context(ncc);
+
+       /* XXX Inefficient, we don't do the best we can... XXX */
+       viking_flush_icache();
+       viking_flush_dcache();
+       addr = start & SRMMU_PGDIR_MASK;
+       while(addr < end) {
+               srmmu_flush_tlb_region(addr);
+               addr += SRMMU_PGDIR_SIZE;
+       }
+
+       if(cc != ncc)
+               srmmu_set_context(cc);
+       restore_flags(flags);
+}
+static void viking_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+{
+       unsigned long flags;
+       int cc, ncc = vmp->vm_mm->context;
+
+       if(ncc == NO_CONTEXT)
+               return;
+
+       save_flags(flags); cli();
+       cc = srmmu_get_context();
+       if(cc != ncc)
+               srmmu_set_context(ncc);
+
+       viking_flush_icache();
+       viking_flush_dcache();
+       srmmu_flush_tlb_page(page);
+
+       if(cc != ncc)
+               srmmu_set_context(cc);
+       restore_flags(flags);
 }
 
-void srmmu_unlockarea(char *vaddr, unsigned long len)
+/* Cypress invalidates. */
+static inline void cypress_invalidate_all(void)
 {
+       srmmu_flush_whole_tlb();
 }
+static void cypress_invalidate_mm(struct mm_struct *mm)
+{
+       unsigned long flags;
+       int cc, ncc = mm->context;
+
+       if(ncc == NO_CONTEXT)
+               return;
+
+       /* have context will travel... */
+       save_flags(flags); cli();
+       cc = srmmu_get_context();
+       if(cc != ncc)
+               srmmu_set_context(ncc);
+
+       cypress_flush_context(); /* POOF! */
+       srmmu_flush_whole_tlb(); /* POW! */
 
-char *srmmu_get_scsi_buffer(char *vaddr, unsigned long len)
+       if(cc != ncc)
+               srmmu_set_context(cc);
+       restore_flags(flags);
+}
+static void cypress_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-       panic("sun4m: get_scsi_buffer() not implemented yet.");
+       unsigned long flags, addr;
+       int cc, ncc = mm->context;
+
+       if(ncc == NO_CONTEXT)
+               return;
+
+       save_flags(flags); cli();
+       cc = srmmu_get_context();
+       if(cc != ncc)
+               srmmu_set_context(ncc);
+
+       /* XXX Inefficient, we don't do the best we can... XXX */
+       addr = start & SRMMU_PGDIR_MASK;
+       while(addr < end) {
+               cypress_flush_region(addr);
+               addr += SRMMU_PGDIR_SIZE;
+       }
+       srmmu_flush_whole_tlb();
+
+       if(cc != ncc)
+               srmmu_set_context(cc);
+       restore_flags(flags);
 }
 
-void srmmu_release_scsi_buffer(char *vaddr, unsigned long len)
+static void cypress_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
 {
-       panic("sun4m: release_scsi_buffer() not implemented yet.");
+       unsigned long flags;
+       int cc, ncc = vmp->vm_mm->context;
+
+       if(ncc == NO_CONTEXT)
+               return;
+
+       save_flags(flags); cli();
+       cc = srmmu_get_context();
+       if(cc != ncc)
+               srmmu_set_context(ncc);
+
+       swift_flush_page(page);
+       srmmu_flush_whole_tlb();
+
+       if(cc != ncc)
+               srmmu_set_context(cc);
+       restore_flags(flags);
 }
 
-/* Perfom a some soft of MMU tablewalk.
- * Long contiguous mappings are not supported (yet ?).
- *
- * Origionally written by Peter Zaitcev, modified by David S.
- * Miller.  This is only used to copy over the PROM/KADB mappings
- * in srmmu_paging_init().
- *
- * The return value encodes at what level the entry was found,
- * basically this is found in the lower 2 bits of the return
- * value.  If the return value is zero, there was no valid mapping
- * found at all, the low bits for a non-zero return value
- * are:
- *         0 -- Level 1 PTE
- *         1 -- Level 2 PTE
- *         2 -- Normal level 3 PTE
- *         3 -- Context Table PTE (unlikely, but still)
- * 
- * Also note that this is called before the context table pointer
- * register is changed, so the PROMs entry is still in there.  Also,
- * it is safe to assume that the context 0 contains the mappings.
- */
-/* TODO chop out 'trace' when stable */
-unsigned int
-srmmu_init_twalk(unsigned virt, int trace)
+/* Hypersparc invalidates. */
+static inline void hypersparc_invalidate_all(void)
 {
-       unsigned int wh, root;
 
-       root = (unsigned int) srmmu_get_ctable_ptr();
-       if(trace) printk(":0x%x >> ", virt);
+       hyper_flush_whole_icache();
+       srmmu_flush_whole_tlb();
+}
 
-       if(trace) printk(" 0x%x :", root);
-       wh = ldw_sun4m_bypass(root);
-       if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
-               if(trace) printk("\n");
-               return 0;
-       }
-       if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
-               wh &= ~SRMMU_PTE_ET_MASK;
-               wh |= 0x3;
-               if(trace) printk("\n");
-               printk("AIEEE context table level pte prom mapping!\n");
-               prom_halt();
-               return 0;
+static void hypersparc_invalidate_mm(struct mm_struct *mm)
+{
+
+}
+
+static void hypersparc_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+
+}
+
+static void hypersparc_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+{
+
+}
+
+static void srmmu_set_pte(pte_t *ptep, pte_t pteval)
+{
+       srmmu_set_entry(ptep, pte_val(pteval));
+}
+
+static void srmmu_quick_kernel_fault(unsigned long address)
+{
+       printk("SRMMU: quick_kernel_fault called for %08lx\n", address);
+       panic("Srmmu bolixed...");
+}
+
+static inline void alloc_context(struct mm_struct *mm)
+{
+       struct ctx_list *ctxp;
+
+       ctxp = ctx_free.next;
+       if(ctxp != &ctx_free) {
+               remove_from_ctx_list(ctxp);
+               add_to_used_ctxlist(ctxp);
+               mm->context = ctxp->ctx_number;
+               ctxp->ctx_mm = mm;
+               return;
        }
-               
-       if(trace) printk(" 0x%x .", wh);
-       wh = ldw_sun4m_bypass(
-                             ((wh & SRMMU_PTD_PTP_MASK) << 4)
-                             + ((virt & SRMMU_IDX1_MASK) >> SRMMU_IDX1_SHIFT)*sizeof(pte_t));
+       ctxp = ctx_used.next;
+       if(ctxp->ctx_mm == current->mm)
+               ctxp = ctxp->next;
+       if(ctxp == &ctx_used)
+               panic("out of mmu contexts");
+       remove_from_ctx_list(ctxp);
+       add_to_used_ctxlist(ctxp);
+       ctxp->ctx_mm->context = NO_CONTEXT;
+       ctxp->ctx_mm = mm;
+       mm->context = ctxp->ctx_number;
+}
 
-       if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
-               if(trace) printk("\n");
-               return 0;
+static void srmmu_switch_to_context(struct task_struct *tsk)
+{
+       /* Kernel threads can execute in any context and so can tasks
+        * sleeping in the middle of exiting. If this task has already
+        * been allocated a piece of the mmu realestate, just jump to
+        * it.
+        */
+       if((tsk->tss.flags & SPARC_FLAG_KTHREAD) ||
+          (tsk->flags & PF_EXITING))
+               return;
+       if(tsk->mm->context == NO_CONTEXT) {
+               alloc_context(tsk->mm);
+               srmmu_ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
        }
-       if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
-               wh &= ~SRMMU_PTE_ET_MASK;
-               if(trace) printk("\n");
-               return wh;
+       srmmu_set_context(tsk->mm->context);
+}
+
+/* Low level IO area allocation on the SRMMU. */
+void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
+{
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+       unsigned long tmp;
+
+       physaddr &= PAGE_MASK;
+       pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
+       pmdp = srmmu_pmd_offset(pgdp, virt_addr);
+       ptep = srmmu_pte_offset(pmdp, virt_addr);
+       tmp = (physaddr >> 4) | SRMMU_ET_PTE;
+
+       /* I need to test whether this is consistant over all
+        * sun4m's.  The bus_type represents the upper 4 bits of
+        * 36-bit physical address on the I/O space lines...
+        */
+       tmp |= (bus_type << 28);
+       if(rdonly)
+               tmp |= SRMMU_PRIV_RDONLY;
+       else
+               tmp |= SRMMU_PRIV;
+       srmmu_set_entry(ptep, tmp);
+       invalidate_all();
+}
+
+static char *srmmu_lockarea(char *vaddr, unsigned long len)
+{
+       return vaddr;
+}
+
+static void srmmu_unlockarea(char *vaddr, unsigned long len)
+{
+}
+
+/* IOMMU things go here. */
+
+#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+static unsigned long first_dvma_page, last_dvma_page;
+
+static inline void srmmu_map_dvma_pages_for_iommu(struct iommu_struct *iommu)
+{
+       unsigned long first = first_dvma_page;
+       unsigned long last = last_dvma_page;
+       iopte_t *iopte;
+
+       iopte = iommu->page_table;
+       iopte += ((DVMA_VADDR - iommu->start) >> PAGE_SHIFT);
+       while(first <= last) {
+               iopte_val(*iopte++) = ((((first - PAGE_OFFSET) >> 4) & IOPTE_PAGE) |
+                                      (IOPTE_WRITE | IOPTE_VALID)) & ~(IOPTE_WAZ);
+               first += PAGE_SIZE;
        }
+}
 
-       if(trace) printk(" 0x%x .", wh);
-       wh = ldw_sun4m_bypass(
-                             ((wh & SRMMU_PTD_PTP_MASK) << 4)
-                             + ((virt & SRMMU_IDX2_MASK) >> SRMMU_IDX2_SHIFT)*sizeof(pte_t));
-       if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
-               if(trace) printk("\n");
-               return 0;
+void srmmu_uncache_iommu_page_table(unsigned long start, int size)
+{
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+       unsigned long end = start + size;
+
+       while(start < end) {
+               pgdp = srmmu_pgd_offset(init_task.mm, start);
+               pmdp = srmmu_pmd_offset(pgdp, start);
+               ptep = srmmu_pte_offset(pmdp, start);
+               pte_val(*ptep) &= ~SRMMU_CACHE;
+               start += PAGE_SIZE;
        }
-       if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
-               wh &= ~SRMMU_PTE_ET_MASK;
-               wh |= 0x1;
-               if(trace) printk("\n");
-               return wh;
+}
+
+unsigned long iommu_init(int iommund, unsigned long memory_start,
+                        unsigned long memory_end, struct linux_sbus *sbus)
+{
+       int impl, vers, ptsize;
+       unsigned long tmp;
+       struct iommu_struct *iommu;
+       struct linux_prom_registers iommu_promregs[PROMREG_MAX];
+
+       memory_start = LONG_ALIGN(memory_start);
+       iommu = (struct iommu_struct *) memory_start;
+       memory_start += sizeof(struct iommu_struct);
+       prom_getproperty(iommund, "reg", (void *) iommu_promregs, sizeof(iommu_promregs));
+       iommu->regs = (struct iommu_regs *)
+               sparc_alloc_io(iommu_promregs[0].phys_addr, 0, (PAGE_SIZE * 3),
+                              "IOMMU registers", iommu_promregs[0].which_io, 0x0);
+       if(!iommu->regs)
+               panic("Cannot map IOMMU registers.");
+       impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28;
+       vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24;
+       tmp = iommu->regs->control;
+       tmp &= ~(IOMMU_CTRL_RNGE);
+       tmp |= (IOMMU_RNGE_64MB | IOMMU_CTRL_ENAB);
+       iommu->regs->control = tmp;
+       iommu_invalidate(iommu->regs);
+       iommu->start = 0xfc000000;
+       iommu->end = 0xffffffff;
+
+       /* Allocate IOMMU page table */
+       ptsize = iommu->end - iommu->start + 1;
+       ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t);
+
+       /* Stupid alignment constraints give me a headache. */
+       memory_start = PAGE_ALIGN(memory_start);
+       memory_start = (((memory_start) + (ptsize - 1)) & ~(ptsize - 1));
+       iommu->page_table = (iopte_t *) memory_start;
+       memory_start += ptsize;
+
+       /* Initialize new table. */
+       memset(iommu->page_table, 0, ptsize);
+       srmmu_map_dvma_pages_for_iommu(iommu);
+       iommu->regs->base = (((unsigned long) iommu->page_table) - PAGE_OFFSET) >> 4;
+       srmmu_uncache_iommu_page_table((unsigned long) iommu->page_table, ptsize);
+       iommu_invalidate(iommu->regs);
+       invalidate_all();
+
+       sbus->iommu = iommu;
+       printk("IOMMU: impl %d vers %d page table at %p of size %d bytes\n",
+              impl, vers, iommu->page_table, ptsize);
+       return memory_start;
+}
+
+
+static char *srmmu_get_scsi_buffer(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+       struct iommu_struct *iommu = sbus->iommu;
+       unsigned long page = (unsigned long) vaddr;
+       unsigned long start, end, offset;
+       iopte_t *iopte;
+
+       if(len > PAGE_SIZE)
+               panic("Can only handle page sized iommu mappings.");
+       offset = page & ~PAGE_MASK;
+       page &= PAGE_MASK;
+
+       start = iommu->start;
+       end = KADB_DEBUGGER_BEGVM; /* Don't step on kadb/prom. */
+       iopte = iommu->page_table;
+       while(start < end) {
+               if(!(iopte_val(*iopte) & IOPTE_VALID))
+                       break;
+               iopte++;
+               start += PAGE_SIZE;
        }
+       if(start == KADB_DEBUGGER_BEGVM)
+               panic("Could not find free iommu entry in get_scsi_buffer.");
+
+       vaddr = (char *) (start | offset);
+       iopte_val(*iopte) = ((((page - PAGE_OFFSET) >> 4) & IOPTE_PAGE) |
+               (IOPTE_WRITE | IOPTE_VALID)) & ~(IOPTE_WAZ);
+       iommu_invalidate(iommu->regs);
+       invalidate_all();
 
-       if(trace) printk(" 0x%x .", wh);
-       wh = ldw_sun4m_bypass(
-                             ((wh & SRMMU_PTD_PTP_MASK) << 4)
-                             + ((virt & SRMMU_IDX3_MASK) >> SRMMU_IDX3_SHIFT)*sizeof(pte_t));
-       if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
-               if(trace) printk("\n");
+       return vaddr;
+}
+
+static void srmmu_release_scsi_buffer(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+       struct iommu_struct *iommu = sbus->iommu;
+       unsigned long page = (unsigned long) vaddr;
+       iopte_t *iopte;
+
+       if(len > PAGE_SIZE)
+               panic("Can only handle page sized IOMMU mappings.");
+       page &= PAGE_MASK;
+       iopte = iommu->page_table + ((page - iommu->start) >> PAGE_SHIFT);
+       iopte_val(*iopte) = 0;
+       iommu_invalidate(iommu->regs);
+       invalidate_all();
+}
+
+/* On the SRMMU we do not have the problems with limited tlb entries
+ * for mapping kernel pages, so we just take things from the free page
+ * pool.  As a side effect we are putting a little too much pressure
+ * on the gfp() subsystem and we don't catch stack overflow like we
+ * did on the sun4c with virtual kstack mappings.  This setup also
+ * makes the logic of the iommu mapping code a lot easier as we can
+ * transparently handle mappings on the kernel stack without any
+ * special code as we did need on the sun4c.
+ */
+struct task_struct *srmmu_alloc_task_struct(void)
+{
+       unsigned long page;
+
+       page = get_free_page(GFP_KERNEL);
+       if(!page)
+               return (struct task_struct *) 0;
+       return (struct task_struct *) page;
+}
+
+unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk)
+{
+       unsigned long pages;
+
+       pages = __get_free_pages(GFP_KERNEL, 1, ~0UL);
+       if(!pages)
                return 0;
-       }
-       if(trace) printk(" 0x%x\n", wh);
-       return wh;
+       memset((void *) pages, 0, (PAGE_SIZE << 1));
+       return pages;
 }
 
+static void srmmu_free_task_struct(struct task_struct *tsk)
+{
+       free_page((unsigned long) tsk);
+}
+
+static void srmmu_free_kernel_stack(unsigned long stack)
+{
+       free_pages(stack, 1);
+}
+
+static unsigned long mempool;
 
 /* Allocate a block of RAM which is aligned to its size.
  * This procedure can be used until the call to mem_init().
- *
- * To get around the elf bootloader nastyness we have a
- * early-on page table pool allocation area starting at
- * C_LABEL(pg0) which is 256k, this should be enough for now.
  */
-static void *
-srmmu_init_alloc(unsigned long *kbrk, unsigned size)
+static void *srmmu_init_alloc(unsigned long *kbrk, unsigned size)
 {
        register unsigned mask = size - 1;
        register unsigned long ret;
 
        if(size==0) return 0x0;
        if(size & mask) {
-               printk("panic: srmmu_init_alloc botch\n");
+               prom_printf("panic: srmmu_init_alloc botch\n");
                prom_halt();
        }
        ret = (*kbrk + mask) & ~mask;
@@ -560,228 +940,166 @@ srmmu_init_alloc(unsigned long *kbrk, unsigned size)
        return (void*) ret;
 }
 
-/* Get fault information on an SRMMU. */
-int
-srmmu_get_fault_info(unsigned long *address, unsigned long *error_code,
-                    unsigned long from_user)
-{
-       /* XXX Foo, write this... XXX */
-       return 0;
-}
-
-/* Paging initialization on the Sparc Reference MMU. */
-
-/* This is all poorly designed, we cannot assume any pages are valid
- * past _end until *after* this routine runs, thus we can't use the
- * start_mem mechanism during initialization...
- */
-static unsigned long mempool;
-
-/* The following is global because trap_init needs it to fire up
- * the other cpu's on multiprocessors.
- */
-pgd_t *lnx_root;      /* Pointer to the new root table */
-
-extern char start[];
-
-unsigned long
-srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
+static inline void srmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end)
 {
-       unsigned long vaddr;  /* Virtual counter */
-       int i;
-
-       pte_t *ptep = 0;
-       pmd_t *pmdp = 0;
-       pgd_t *pgdp = 0;
-
-       mempool = start_mem;
-       lnx_root = srmmu_init_alloc(&mempool, num_contexts*sizeof(pgd_t));
-
-       memset(swapper_pg_dir, 0, PAGE_SIZE);
-
-       /* For every entry in the new Linux context table, put in
-        * an entry which points to swapper_pg_dir .
-        */
-       pmdp = (pmd_t *) swapper_pg_dir;
-       for(i = 0; i < num_contexts; i++)
-               srmmu_pgd_set(&lnx_root[i], pmdp);
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
 
-       /* Make Linux physical page tables. */
-       for(vaddr = KERNBASE; vaddr < end_mem; vaddr+=PAGE_SIZE) {
-               pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
+       while(start < end) {
+               pgdp = srmmu_pgd_offset(init_task.mm, start);
                if(srmmu_pgd_none(*pgdp)) {
-                       pmdp = srmmu_init_alloc(&mempool,
-                                               SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+                       pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE);
                        srmmu_pgd_set(pgdp, pmdp);
                }
-
-               pmdp = srmmu_pmd_offset(pgdp, vaddr);
+               pmdp = srmmu_pmd_offset(pgdp, start);
                if(srmmu_pmd_none(*pmdp)) {
-                       ptep = srmmu_init_alloc(&mempool,
-                                               SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+                       ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE);
                        srmmu_pmd_set(pmdp, ptep);
                }
-
-               ptep = srmmu_pte_offset(pmdp, vaddr);
-               *ptep = srmmu_mk_pte(vaddr, SRMMU_PAGE_KERNEL);
+               start = (start + SRMMU_PMD_SIZE) & SRMMU_PMD_MASK;
        }
+}
 
-       /* Map IO areas. */
-       for(vaddr = IOBASE_VADDR; vaddr < (IOBASE_VADDR+IOBASE_LEN);
-           vaddr += SRMMU_PMD_SIZE) {
-               pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
-               if(srmmu_pgd_none(*pgdp)) {
-                       pmdp = srmmu_init_alloc(&mempool,
-                                               SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
-                       srmmu_pgd_set(pgdp, pmdp);
-               }
-               pmdp = srmmu_pmd_offset(pgdp, vaddr);
-               if(srmmu_pmd_none(*pmdp)) {
-                       ptep = srmmu_init_alloc(&mempool,
-                                               SRMMU_PTRS_PER_PTE*sizeof(pte_t));
-                       srmmu_pmd_set(pmdp, ptep);
+/* This is much cleaner than poking around physical address space
+ * looking at the prom's page table directly which is what most
+ * other OS's do.  Yuck... this is much better.
+ */
+static inline void srmmu_inherit_prom_mappings(void)
+{
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+       unsigned long start, end;
+       unsigned long prompte;
+
+       start = KADB_DEBUGGER_BEGVM;
+       end = LINUX_OPPROM_ENDVM;
+       while(start < end) {
+               /* Something going wrong here on some ss5's... */
+               prompte = srmmu_hwprobe(start);
+
+               if((prompte & SRMMU_ET_MASK) == SRMMU_ET_PTE) {
+                       pgdp = srmmu_pgd_offset(init_task.mm, start);
+                       if(srmmu_pgd_none(*pgdp)) {
+                               pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE);
+                               srmmu_pgd_set(pgdp, pmdp);
+                       }
+                       pmdp = srmmu_pmd_offset(pgdp, start);
+                       if(srmmu_pmd_none(*pmdp)) {
+                               ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE);
+                               srmmu_pmd_set(pmdp, ptep);
+                       }
+                       ptep = srmmu_pte_offset(pmdp, start);
+                       pte_val(*ptep) = prompte;
                }
+               start += PAGE_SIZE;
        }
+}
 
-       /* Map DVMA areas. */
-       for(vaddr = (DVMA_VADDR); vaddr < (DVMA_VADDR + DVMA_LEN);
-           vaddr += PAGE_SIZE) {
-               pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
-               if(srmmu_pgd_none(*pgdp)) {
-                       pmdp = srmmu_init_alloc(&mempool,
-                                               SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
-                       srmmu_pgd_set(pgdp, pmdp);
-               }
-               pmdp = srmmu_pmd_offset(pgdp, vaddr);
-               if(srmmu_pmd_none(*pmdp)) {
-                       ptep = srmmu_init_alloc(&mempool,
-                                               SRMMU_PTRS_PER_PTE*sizeof(pte_t));
-                       srmmu_pmd_set(pmdp, ptep);
-               }
+static inline void srmmu_map_dvma_pages_for_cpu(unsigned long first, unsigned long last)
+{
+       unsigned long start;
+       pgprot_t dvma_prot;
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+
+       start = DVMA_VADDR;
+       dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV);
+       while(first <= last) {
+               pgdp = srmmu_pgd_offset(init_task.mm, start);
+               pmdp = srmmu_pmd_offset(pgdp, start);
+               ptep = srmmu_pte_offset(pmdp, start);
 
-               ptep = srmmu_pte_offset(pmdp, vaddr);
-               *ptep = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE), SRMMU_PAGE_KERNEL);
-               pte_val(*ptep) &= ~(SRMMU_PTE_C_MASK);
+               /* Map with cacheable bit clear. */
+               srmmu_set_entry(ptep, pte_val(srmmu_mk_pte(first, dvma_prot)));
+
+               first += PAGE_SIZE;
+               start += PAGE_SIZE;
        }
-       srmmu_flush_whole_tlb();
-       flush_ei_ctx(0x0);
-
-       /* Map in the PERCPU areas in virtual address space. */
-#if 0
-       prom_printf("PERCPU_VADDR + PERCPU_LEN = %08lx\n",
-                   (PERCPU_VADDR + PERCPU_LEN));
-#endif
-       for(vaddr = PERCPU_VADDR; vaddr < (PERCPU_VADDR + PERCPU_LEN);
-           vaddr += PERCPU_ENTSIZE) {
-               pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
+}
+
+static void srmmu_map_kernel(unsigned long start, unsigned long end)
+{
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+
+       end = (PAGE_ALIGN(end) + PAGE_SIZE);
+       while(start < end) {
+               pgdp = srmmu_pgd_offset(init_task.mm, start);
                if(srmmu_pgd_none(*pgdp)) {
-                       pmdp = srmmu_init_alloc(&mempool,
-                                               SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+                       pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE);
                        srmmu_pgd_set(pgdp, pmdp);
                }
-               pmdp = srmmu_pmd_offset(pgdp, vaddr);
+               pmdp = srmmu_pmd_offset(pgdp, start);
                if(srmmu_pmd_none(*pmdp)) {
-                       ptep = srmmu_init_alloc(&mempool,
-                                               SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+                       ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE);
                        srmmu_pmd_set(pmdp, ptep);
                }
-               ptep = srmmu_pte_offset(pmdp, vaddr);
-               /* Per-cpu trap table page. */
-               *ptep++ = srmmu_mk_pte((unsigned int) start, SRMMU_PAGE_KERNEL);
-               /* Per-cpu kernel stack page. */
-               *ptep++ = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
-                                      SRMMU_PAGE_KERNEL);
-               /* Per-cpu Prom MBox. */
-               *ptep++ = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
-                                      SRMMU_PAGE_KERNEL);
-               /* Per-cpu state variables. */
-               *ptep = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
-                                    SRMMU_PAGE_KERNEL);
-       }
-       percpu_table = (struct sparc_percpu *) PERCPU_VADDR;
-
-       /* Ugh, have to map DVMA that the prom has mapped too or else
-        * you will lose with video cards when we take over the ctx table.
-        * Also, must take into consideration that prom might be using level
-        * two or one PTE's. TODO
-        *
-        * XXX This still isn't right, the cg* graphics cards get their
-        * XXX mapped screens all fucked up when I jump onto Linux's
-        * XXX page tables.  Must investigate...
-        */
-       for(vaddr = KADB_DEBUGGER_BEGVM; vaddr != 0x0;) {
-               unsigned int prom_pte;
-
-               prom_pte = srmmu_init_twalk(vaddr, 0);
-
-               if(prom_pte) {
-                       pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
-                       if((prom_pte&0x3) == 0x0) {
-                               prom_pte &= ~0x3;
-                               prom_pte |= SRMMU_ET_PTE;
-                               pgd_val(*pgdp) = prom_pte;
-                               vaddr = SRMMU_PGDIR_ALIGN(vaddr+1);
-                               continue;
-                       }
-                       if(srmmu_pgd_none(*pgdp)) {
-                               pmdp = srmmu_init_alloc(&mempool,
-                                                       SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
-                               srmmu_pgd_set(pgdp, pmdp);
-                       }
+               ptep = srmmu_pte_offset(pmdp, start);
+               *ptep = srmmu_mk_pte(start, SRMMU_PAGE_KERNEL);
+               start += PAGE_SIZE;
+       }
+}
 
-                       pmdp = srmmu_pmd_offset(pgdp, vaddr);
-                       if((prom_pte&0x3) == 0x1) {
-                               prom_pte &= ~0x3;
-                               prom_pte |= SRMMU_ET_PTE;
-                               pgd_val(*pgdp) = prom_pte;
-                               vaddr = SRMMU_PMD_ALIGN(vaddr+1);
-                               continue;
-                       }
-                       if(srmmu_pmd_none(*pmdp)) {
-                               ptep = srmmu_init_alloc(&mempool,
-                                                       SRMMU_PTRS_PER_PTE*sizeof(pte_t));
-                               srmmu_pmd_set(pmdp, ptep);
-                       }
-                       /* A normal 3rd level PTE, no need to change ET bits. */
-                       ptep = srmmu_pte_offset(pmdp, vaddr);
-                       pte_val(*ptep) = prom_pte;
+/* Paging initialization on the Sparc Reference MMU. */
+extern unsigned long free_area_init(unsigned long, unsigned long);
+extern unsigned long sparc_context_init(unsigned long, int);
 
+unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
+{
+       int i, cpunode;
+       char node_str[128];
+
+       /* Find the number of contexts on the srmmu. */
+       cpunode = prom_getchild(prom_root_node);
+       num_contexts = 0;
+       while((cpunode = prom_getsibling(cpunode)) != 0) {
+               prom_getstring(cpunode, "device_type", node_str, sizeof(node_str));
+               if(!strcmp(node_str, "cpu")) {
+                       num_contexts = prom_getintdefault(cpunode, "mmu-nctx", 0x8);
+                       break;
                }
-               vaddr += PAGE_SIZE;
        }
+       if(!num_contexts) {
+               prom_printf("Something wrong, cant find cpu node in paging_init.\n");
+               prom_halt();
+       }
+               
+       prom_printf("Number of MMU contexts %d\n", num_contexts);
+       mempool = start_mem;
+       memset(swapper_pg_dir, 0, PAGE_SIZE);
+       srmmu_map_kernel(KERNBASE, end_mem);
+       srmmu_allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_END);
+       srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END);
+       mempool = PAGE_ALIGN(mempool);
+       first_dvma_page = mempool;
+       last_dvma_page = (mempool + (DVMA_LEN) - PAGE_SIZE);
+       mempool = last_dvma_page + PAGE_SIZE;
+       srmmu_map_dvma_pages_for_cpu(first_dvma_page, last_dvma_page);
+
+       srmmu_inherit_prom_mappings();
+       srmmu_context_table = srmmu_init_alloc(&mempool, num_contexts*sizeof(ctxd_t));
+       for(i = 0; i < num_contexts; i++)
+               srmmu_ctxd_set(&srmmu_context_table[i], swapper_pg_dir);
 
-       /* I believe I do not need to flush VAC here since my stores  */
-        /* probably already reached the physical RAM.             --P3 */
-
-       /* We probably do, and should do it just to be safe... -Davem */
-
-       /* Take the MMU over from the PROM */
        prom_printf("Taking over MMU from PROM.\n");
-
-       srmmu_set_ctable_ptr(((unsigned)lnx_root) - PAGE_OFFSET);
-
+       srmmu_flush_whole_tlb();
+       srmmu_set_ctable_ptr(((unsigned)srmmu_context_table) - PAGE_OFFSET);
        srmmu_flush_whole_tlb();
 
-       /* Now it is ok to use memory at start_mem. */
        start_mem = PAGE_ALIGN(mempool);
+       start_mem = sparc_context_init(start_mem, num_contexts);
        start_mem = free_area_init(start_mem, end_mem);
-       start_mem = PAGE_ALIGN(start_mem);
-
-#if 0
-       prom_printf("Testing context switches...\n");
-       for(i=0; i<num_contexts; i++)
-               srmmu_set_context(i);
-       prom_printf("done...\n");
-       srmmu_set_context(0);
-#endif
 
        prom_printf("survived...\n");
-       return start_mem;
+       return PAGE_ALIGN(start_mem);
 }
 
 /* Test the WP bit on the Sparc Reference MMU. */
-void
-srmmu_test_wp(void)
+void srmmu_test_wp(void)
 {
        pgd_t *pgdp;
        
@@ -798,50 +1116,350 @@ srmmu_test_wp(void)
 
        pgdp = srmmu_pgd_offset(init_task.mm, 0x0);
        pgd_val(*pgdp) = 0x0;
+}
+
+static char *srmmu_mmu_info(void)
+{
+       return "";
+}
+
+static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
+{
+}
+
+static void srmmu_exit_hook(void)
+{
+       struct ctx_list *ctx_old;
+       struct mm_struct *mm = current->mm;
+
+       if(mm->context != NO_CONTEXT) {
+               srmmu_ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir);
+               ctx_old = ctx_list_pool + mm->context;
+               remove_from_ctx_list(ctx_old);
+               add_to_free_ctxlist(ctx_old);
+               mm->context = NO_CONTEXT;
+       }
+}
+
+static void
+srmmu_flush_hook(void)
+{
+       if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+               alloc_context(current->mm);
+               srmmu_ctxd_set(&srmmu_context_table[current->mm->context], current->mm->pgd);
+               srmmu_set_context(current->mm->context);
+       }
+}
+
+/* Init various srmmu chip types. */
+void srmmu_is_bad(void)
+{
+       prom_printf("Could not determine SRMMU chip type.\n");
+       prom_halt();
+}
+
+void init_hypersparc(void)
+{
+       unsigned long mreg = srmmu_get_mmureg();
+
+       prom_printf("HyperSparc MMU detected.\n");
+       if(mreg & HYPERSPARC_CSIZE)
+               hyper_cache_size = (256 * 1024);
+       else
+               hyper_cache_size = (128 * 1024);
+
+       srmmu_modtype = HyperSparc;
+       hwbug_bitmask |= HWBUG_VACFLUSH_BITROT;
+
+       hyper_flush_whole_icache();
+       hyper_flush_all_combined();
+
+       /* Keep things sane for now, cache in write-through mode. */
+       mreg &= ~(HYPERSPARC_CWENABLE | HYPERSPARC_CMODE | HYPERSPARC_WBENABLE);
+       mreg |= HYPERSPARC_CENABLE;
+       srmmu_set_mmureg(mreg);
+       put_ross_icr(get_ross_icr() | 0x3);
+       invalidate_all = hypersparc_invalidate_all;
+       invalidate_mm = hypersparc_invalidate_mm;
+       invalidate_page = hypersparc_invalidate_page;
+       invalidate_range = hypersparc_invalidate_range;
+}
+
+void init_cypress_common(void)
+{
+       unsigned long mreg = srmmu_get_mmureg();
+
+       mreg &= ~CYPRESS_CMODE;
+       mreg |= CYPRESS_CENABLE;
+       srmmu_set_mmureg(mreg);
+       invalidate_all = cypress_invalidate_all;
+       invalidate_mm = cypress_invalidate_mm;
+       invalidate_page = cypress_invalidate_page;
+       invalidate_range = cypress_invalidate_range;
+}
 
-       return;
+void init_cypress_604(void)
+{
+       prom_printf("Cypress 604(UP) MMU detected.\n");
+       srmmu_modtype = Cypress;
+       init_cypress_common();
 }
 
-void srmmu_update_mmu_cache(struct vm_area_struct * vma,
-                           unsigned long address, pte_t pte)
+void init_cypress_605(unsigned long mrev)
 {
-       printk("WHOOPS, update_mmu_cache called on a SRMMU!\n");
-       panic("SRMMU bolixed...");
+       prom_printf("Cypress 605(MP) MMU detected.\n");
+       if(mrev == 0xe) {
+               srmmu_modtype = Cypress_vE;
+               hwbug_bitmask |= HWBUG_COPYBACK_BROKEN;
+       } else {
+               if(mrev == 0xd) {
+                       srmmu_modtype = Cypress_vD;
+                       hwbug_bitmask |= HWBUG_ASIFLUSH_BROKEN;
+               } else {
+                       srmmu_modtype = Cypress;
+               }
+       }
+       init_cypress_common();
 }
 
-void
-srmmu_fork_hook(void *vtask, unsigned long kthread_usp)
+#define SWIFT_REVISION_ADDR  0x10003000
+void init_swift(void)
 {
-       return; /* XXX */
+       unsigned long swift_rev, addr;
+       unsigned long mreg = srmmu_get_mmureg();
+
+       prom_printf("Swift MMU detected.\n");
+       __asm__ __volatile__("lda [%1] %2, %0\n\t"
+                            "srl %0, 0x18, %0\n\t" :
+                            "=r" (swift_rev) :
+                            "r" (SWIFT_REVISION_ADDR), "i" (0x20));
+       switch(swift_rev) {
+       case 0x11:
+       case 0x20:
+       case 0x23:
+       case 0x30:
+               srmmu_modtype = Swift_lots_o_bugs;
+               hwbug_bitmask |= (HWBUG_KERN_ACCBROKEN | HWBUG_KERN_CBITBROKEN);
+               /* Gee george, I wonder why Sun is so hush hush about
+                * this hardware bug... really braindamage stuff going
+                * on here.  However I think we can find a way to avoid
+                * all of the workaround overhead under Linux.  Basically,
+                * any page fault can cause kernel pages to become user
+                * accessible (the mmu gets confused and clears some of
+                * the ACC bits in kernel ptes).  Aha, sounds pretty
+                * horrible eh?  But wait, after extensive testing it appears
+                * that if you use pgd_t level large kernel pte's (like the
+                * 4MB pages on the Pentium) the bug does not get tripped
+                * at all.  This avoids almost all of the major overhead.
+                * Welcome to a world where your vendor tells you to,
+                * "apply this kernel patch" instead of "sorry for the
+                * broken hardware, send it back and we'll give you
+                * properly functioning parts"
+                */
+               break;
+       case 0x25:
+       case 0x31:
+               srmmu_modtype = Swift_bad_c;
+               hwbug_bitmask |= HWBUG_KERN_CBITBROKEN;
+               /* You see Sun allude to this hardware bug but never
+                * admit things directly, they'll say things like,
+                * "the Swift chip cache problems" or similar.
+                */
+               break;
+       default:
+               srmmu_modtype = Swift_ok;
+               break;
+       };
+       /* Clear any crap from the cache or else... */
+       for(addr = 0; addr < (PAGE_SIZE * 4); addr += 16) {
+               swift_inv_insn_tag(addr); /* whiz- */
+               swift_inv_data_tag(addr); /* bang */
+       }
+       mreg |= (SWIFT_IE | SWIFT_DE); /* I & D caches on */
+
+       /* The Swift branch folding logic is completely broken.  At
+        * trap time, if things are just right, if can mistakedly
+        * thing that a trap is coming from kernel mode when in fact
+        * it is coming from user mode (it misexecutes the branch in
+        * the trap code).  So you see things like crashme completely
+        * hosing your machine which is completely unacceptable.  Turn
+        * this crap off... nice job Fujitsu.
+        */
+       mreg &= ~(SWIFT_BF);
+       srmmu_set_mmureg(mreg);
+
+       invalidate_all = swift_invalidate_all;
+       invalidate_mm = swift_invalidate_mm;
+       invalidate_page = swift_invalidate_page;
+       invalidate_range = swift_invalidate_range;
+
+       /* Are you now convinced that the Swift is one of the
+        * biggest VLSI abortions of all time?  Bravo Fujitsu!
+        */
 }
 
-void
-srmmu_exit_hook(void *vtask)
+void init_tsunami(unsigned long mreg)
 {
-       return; /* XXX */
+       /* Tsunami's pretty sane, Sun and TI actually got it
+        * somewhat right this time.  Fujitsu should have
+        * taken some lessons from them.
+        */
+
+       prom_printf("Tsunami MMU detected.\n");
+       srmmu_modtype = Tsunami;
+       tsunami_invalidate_icache();
+       tsunami_invalidate_dcache();
+       mreg &= ~TSUNAMI_ITD;
+       mreg |= (TSUNAMI_IENAB | TSUNAMI_DENAB);
+       srmmu_set_mmureg(mreg);
+       invalidate_all = tsunami_invalidate_all;
+       invalidate_mm = tsunami_invalidate_mm;
+       invalidate_page = tsunami_invalidate_page;
+       invalidate_range = tsunami_invalidate_range;
 }
 
-void
-srmmu_release_hook(void *vtask)
+void init_viking(unsigned long psr_vers, unsigned long mod_rev)
 {
-       return; /* XXX */
+       unsigned long mreg = srmmu_get_mmureg();
+
+       /* Ahhh, the viking.  SRMMU VLSI abortion number two... */
+
+       prom_printf("Viking MMU detected.\n");
+       if(!psr_vers && ! mod_rev) {
+               srmmu_modtype = Viking_12;
+               hwbug_bitmask |= (HWBUG_MODIFIED_BITROT | HWBUG_PC_BADFAULT_ADDR);
+
+               /* On a fault, the chip gets entirely confused.  It will
+                * do one of two things.  Either it will set the modified
+                * bit for a read-only page (!!!) or it will improperly
+                * report a fault when a dcti/loadstore sequence is the
+                * last two instructions on a page.  Oh baby...
+                */
+       } else {
+               if(psr_vers) {
+                       srmmu_modtype = Viking_2x;
+                       hwbug_bitmask |= HWBUG_PC_BADFAULT_ADDR; /* see above */
+               } else {
+                       if(mod_rev == 1) {
+                               srmmu_modtype = Viking_30;
+                               hwbug_bitmask |= HWBUG_PACINIT_BITROT;
+
+                               /* At boot time the physical cache
+                                * has cherry bombs in it, so you
+                                * have to scrape it by hand before
+                                * enabling it.  Nice CAD tools guys.
+                                */
+                       } else {
+                               if(mod_rev < 8)
+                                       srmmu_modtype = Viking_35;
+                               else
+                                       srmmu_modtype = Viking_new;
+                       }
+               }
+       }
+       /* XXX Dave, play with the MXCC you pinhead XXX */
+       viking_flush_icache();
+       viking_flush_dcache();
+       mreg |= (VIKING_DCENABLE | VIKING_ICENABLE | VIKING_SBENABLE |
+                VIKING_TCENABLE | VIKING_DPENABLE);
+       srmmu_set_mmureg(mreg);
+       invalidate_all = viking_invalidate_all;
+       invalidate_mm = viking_invalidate_mm;
+       invalidate_page = viking_invalidate_page;
+       invalidate_range = viking_invalidate_range;
 }
 
-void
-srmmu_flush_hook(void *vtask)
+/* Probe for the srmmu chip version. */
+static void get_srmmu_type(void)
 {
-       return; /* XXX */
+       unsigned long mreg, psr;
+       unsigned long mod_typ, mod_rev, psr_typ, psr_vers;
+
+       srmmu_modtype = SRMMU_INVAL_MOD;
+       hwbug_bitmask = 0;
+
+       mreg = srmmu_get_mmureg(); psr = get_psr();
+       mod_typ = (mreg & 0xf0000000) >> 28;
+       mod_rev = (mreg & 0x0f000000) >> 24;
+       psr_typ = (psr >> 28) & 0xf;
+       psr_vers = (psr >> 24) & 0xf;
+
+       /* First, check for HyperSparc or Cypress. */
+       if(mod_typ == 1) {
+               switch(mod_rev) {
+               case 7:
+                       /* UP or MP Hypersparc */
+                       init_hypersparc();
+                       break;
+               case 0:
+                       /* Uniprocessor Cypress */
+                       init_cypress_604();
+                       break;
+               case 13:
+               case 14:
+               case 15:
+                       /* MP Cypress mmu/cache-controller */
+                       init_cypress_605(mod_rev);
+                       break;
+               default:
+                       srmmu_is_bad();
+                       break;
+               };
+               return;
+       }
+
+       /* Next check for Fujitsu Swift. */
+       if(psr_typ == 0 && psr_vers == 4) {
+               init_swift();
+               return;
+       }
+
+       /* Now the Viking family of srmmu. */
+       if(psr_typ == 4 &&
+          ((psr_vers == 0) ||
+           ((psr_vers == 1) && (mod_typ == 0) && (mod_rev == 0)))) {
+               init_viking(psr_vers, mod_rev);
+               return;
+       }
+
+       /* Finally the Tsunami. */
+       if(psr_typ == 4 && psr_vers == 1 && (mod_typ || mod_rev)) {
+               init_tsunami(mreg);
+               return;
+       }
+
+       /* Oh well */
+       srmmu_is_bad();
 }
 
-void
-srmmu_task_cacheflush(void *vtask)
+extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme,
+       tsetup_mmu_patchme, rtrap_mmu_patchme;
+
+extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk,
+       tsetup_srmmu_stackchk, srmmu_rett_stackchk;
+
+extern unsigned long srmmu_fault;
+
+#define PATCH_BRANCH(insn, dest) do { \
+               iaddr = &(insn); \
+               daddr = &(dest); \
+               *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \
+        } while(0);
+
+static void patch_window_trap_handlers(void)
 {
-       return; /* XXX */
+       unsigned long *iaddr, *daddr;
+       
+       PATCH_BRANCH(spwin_mmu_patchme, spwin_srmmu_stackchk);
+       PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk);
+       PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk);
+       PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk);
+       PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault);
+       PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault);
 }
 
 /* Load up routines and constants for sun4m mmu */
-void
-ld_mmu_srmmu(void)
+void ld_mmu_srmmu(void)
 {
        prom_printf("Loading srmmu MMU routines\n");
 
@@ -860,12 +1478,11 @@ ld_mmu_srmmu(void)
        page_none = SRMMU_PAGE_NONE;
        page_shared = SRMMU_PAGE_SHARED;
        page_copy = SRMMU_PAGE_COPY;
-       page_readonly = SRMMU_PAGE_READONLY;
+       page_readonly = SRMMU_PAGE_RDONLY;
        page_kernel = SRMMU_PAGE_KERNEL;
-       page_invalid = SRMMU_PAGE_INVALID;
-       
+       pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF;
+           
        /* Functions */
-       invalidate = srmmu_invalidate;
        set_pte = srmmu_set_pte;
        switch_to_context = srmmu_switch_to_context;
        pmd_align = srmmu_pmd_align;
@@ -900,6 +1517,7 @@ ld_mmu_srmmu(void)
 
        mk_pte = srmmu_mk_pte;
        pgd_set = srmmu_pgd_set;
+       mk_pte_io = srmmu_mk_pte_io;
        pte_modify = srmmu_pte_modify;
        pgd_offset = srmmu_pgd_offset;
        pmd_offset = srmmu_pmd_offset;
@@ -915,33 +1533,39 @@ ld_mmu_srmmu(void)
        pgd_free = srmmu_pgd_free;
        pgd_alloc = srmmu_pgd_alloc;
 
-       pte_read = srmmu_pte_read;
        pte_write = srmmu_pte_write;
-       pte_exec = srmmu_pte_exec;
        pte_dirty = srmmu_pte_dirty;
        pte_young = srmmu_pte_young;
-       pte_cow = srmmu_pte_cow;
        pte_wrprotect = srmmu_pte_wrprotect;
-       pte_rdprotect = srmmu_pte_rdprotect;
-       pte_exprotect = srmmu_pte_exprotect;
        pte_mkclean = srmmu_pte_mkclean;
        pte_mkold = srmmu_pte_mkold;
-       pte_uncow = srmmu_pte_uncow;
        pte_mkwrite = srmmu_pte_mkwrite;
-       pte_mkread = srmmu_pte_mkread;
-       pte_mkexec = srmmu_pte_mkexec;
        pte_mkdirty = srmmu_pte_mkdirty;
        pte_mkyoung = srmmu_pte_mkyoung;
-       pte_mkcow = srmmu_pte_mkcow;
-       get_fault_info = srmmu_get_fault_info;
        update_mmu_cache = srmmu_update_mmu_cache;
        mmu_exit_hook = srmmu_exit_hook;
-       mmu_fork_hook = srmmu_fork_hook;
-       mmu_release_hook = srmmu_release_hook;
        mmu_flush_hook = srmmu_flush_hook;
-       mmu_task_cacheflush = srmmu_task_cacheflush;
        mmu_lockarea = srmmu_lockarea;
        mmu_unlockarea = srmmu_unlockarea;
        mmu_get_scsi_buffer = srmmu_get_scsi_buffer;
        mmu_release_scsi_buffer = srmmu_release_scsi_buffer;
+       mmu_info = srmmu_mmu_info;
+
+       /* Task struct and kernel stack allocating/freeing. */
+       alloc_kernel_stack = srmmu_alloc_kernel_stack;
+       alloc_task_struct = srmmu_alloc_task_struct;
+       free_kernel_stack = srmmu_free_kernel_stack;
+       free_task_struct = srmmu_free_task_struct;
+
+       quick_kernel_fault = srmmu_quick_kernel_fault;
+
+       get_srmmu_type();
+       if(!(srmmu_get_mmureg() & 0x800)) {
+               srmmu_read_physical = msparc_read_physical;
+               srmmu_write_physical = msparc_write_physical;
+       } else {
+               srmmu_read_physical = gensrmmu_read_physical;
+               srmmu_write_physical = gensrmmu_write_physical;
+       }
+       patch_window_trap_handlers();
 }
index 747d49232e13a4b98ff89beba4f394fdddc10565..7475c70e4af147b959ccce54b1f10a92e1cd8251 100644 (file)
-/* $Id: sun4c.c,v 1.56 1995/11/25 00:59:39 davem Exp $
- * sun4c.c:  Sun4C specific mm routines.
+/* sun4c.c: Doing in software what should be done in hardware.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-/* The SUN4C has an MMU based upon a Translation Lookaside Buffer scheme
- * where only so many translations can be loaded at once.  As Linus said
- * in Boston, this is a broken way of doing things.
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
+#include <linux/mm.h>
 
-#include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/vac-ops.h>
 #include <asm/vaddrs.h>
-#include <asm/asi.h>
-#include <asm/system.h>
-#include <asm/contregs.h>
-#include <asm/oplib.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
 #include <asm/memreg.h>
-#include <asm/kdebug.h>
+#include <asm/processor.h>
 
-/* Pseg allocation structures. */
-static struct pseg_list s4cpseg_pool[256];
+extern int num_segmaps, num_contexts;
 
-struct pseg_list s4cpseg_free;
-struct pseg_list s4cpseg_used;
-static struct pseg_list s4cpseg_locked;
-static struct pseg_list s4cpseg_per_context[16];
+/* Flushing the cache. */
+struct sun4c_vac_props sun4c_vacinfo;
+static int ctxflushes, segflushes, pageflushes;
 
-static unsigned char pseg_count_per_context[16];
+/* Invalidate every sun4c cache line tag. */
+void sun4c_flush_all(void)
+{
+       unsigned long begin, end;
+
+       if(sun4c_vacinfo.on)
+               panic("SUN4C: AIEEE, trying to invalidate vac while"
+                      " it is on.");
+
+       /* Clear 'valid' bit in all cache line tags */
+       begin = AC_CACHETAGS;
+       end = (AC_CACHETAGS + sun4c_vacinfo.num_bytes);
+       while(begin < end) {
+               __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                                    "r" (begin), "i" (ASI_CONTROL));
+               begin += sun4c_vacinfo.linesize;
+       }
+}
 
-unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
-unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
+/* Blow the entire current context out of the virtual cache. */
+/* static */ inline void sun4c_flush_context(void)
+{
+       unsigned long vaddr;
 
-extern int num_segmaps, num_contexts;
+       ctxflushes++;
+       if(sun4c_vacinfo.do_hwflushes) {
+               for(vaddr=0; vaddr < sun4c_vacinfo.num_bytes; vaddr+=PAGE_SIZE)
+                       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                                            "r" (vaddr), "i" (ASI_HWFLUSHCONTEXT));
+       } else {
+               int incr = sun4c_vacinfo.linesize;
+               for(vaddr=0; vaddr < sun4c_vacinfo.num_bytes; vaddr+=incr)
+                       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                                            "r" (vaddr), "i" (ASI_FLUSHCTX));
+       }
+}
 
-/* First the functions which the mid-level code uses to directly
- * manipulate the software page tables.  Some defines since we are
- * emulating the i386 page directory layout.
+/* Scrape the segment starting at ADDR from the virtual cache. */
+static inline void sun4c_flush_segment(unsigned long addr)
+{
+       unsigned long end;
+
+       segflushes++;
+       addr &= SUN4C_REAL_PGDIR_MASK;
+       end = (addr + sun4c_vacinfo.num_bytes);
+       if(sun4c_vacinfo.do_hwflushes) {
+               for( ; addr < end; addr += PAGE_SIZE)
+                       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                                            "r" (addr), "i" (ASI_HWFLUSHSEG));
+       } else {
+               int incr = sun4c_vacinfo.linesize;
+               for( ; addr < end; addr += incr)
+                       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                                            "r" (addr), "i" (ASI_FLUSHSEG));
+       }
+}
+
+/* Bolix one page from the virtual cache. */
+static inline void sun4c_flush_page(unsigned long addr)
+{
+       addr &= PAGE_MASK;
+
+       pageflushes++;
+       if(sun4c_vacinfo.do_hwflushes) {
+               __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                                    "r" (addr), "i" (ASI_HWFLUSHPAGE));
+       } else {
+               unsigned long end = addr + PAGE_SIZE;
+               int incr = sun4c_vacinfo.linesize;
+
+               for( ; addr < end; addr += incr)
+                       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                                            "r" (addr), "i" (ASI_FLUSHPG));
+       }
+}
+
+/* The sun4c's do have an on chip store buffer.  And the way you
+ * clear them out isn't so obvious.  The only way I can think of
+ * to accomplish this is to read the current context register,
+ * store the same value there, then do a bunch of nops for the
+ * pipeline to clear itself completely.  This is only used for
+ * dealing with memory errors, so it is not that critical.
  */
-#define PGD_PRESENT  0x001
-#define PGD_RW       0x002
-#define PGD_USER     0x004
-#define PGD_ACCESSED 0x020
-#define PGD_DIRTY    0x040
-#define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
+void sun4c_complete_all_stores(void)
+{
+       volatile int _unused;
 
-unsigned long sun4c_vmalloc_start(void)
+       _unused = sun4c_get_context();
+       sun4c_set_context(_unused);
+       nop(); nop(); nop(); nop();
+       nop(); nop(); nop(); nop();
+       /* Is that enough? */
+}
+
+/* Bootup utility functions. */
+static inline void sun4c_init_clean_segmap(unsigned char pseg)
 {
-       return SUN4C_VMALLOC_START;
+       unsigned long vaddr;
+
+       sun4c_put_segmap(0, pseg);
+       for(vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr+=PAGE_SIZE)
+               sun4c_put_pte(vaddr, 0);
+       sun4c_put_segmap(0, invalid_segment);
 }
 
-/* Update the root mmu directory on the sun4c mmu. */
-void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
+static inline void sun4c_init_clean_mmu(unsigned long kernel_end)
 {
-       (tsk)->tss.pgd_ptr = (unsigned long) (pgdir);
+       unsigned long vaddr;
+       unsigned char savectx, ctx;
+
+       savectx = sun4c_get_context();
+       kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
+       for(ctx = 0; ctx < num_contexts; ctx++) {
+               sun4c_set_context(ctx);
+               for(vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
+                       sun4c_put_segmap(vaddr, invalid_segment);
+               for(vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
+                       sun4c_put_segmap(vaddr, invalid_segment);
+               for(vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
+                       sun4c_put_segmap(vaddr, invalid_segment);
+               for(vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
+                       sun4c_put_segmap(vaddr, invalid_segment);
+       }
+       sun4c_set_context(ctx);
 }
 
-int sun4c_pte_none(pte_t pte)          { return !pte_val(pte); }
-int sun4c_pte_present(pte_t pte)       { return pte_val(pte) & _SUN4C_PAGE_VALID; }
-int sun4c_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
-void sun4c_pte_clear(pte_t *ptep)      { pte_val(*ptep) = 0; }
-void sun4c_pte_reuse(pte_t *ptep)
+void sun4c_probe_vac(void)
 {
-       if(!mem_map[MAP_NR(ptep)].reserved)
-               mem_map[MAP_NR(ptep)].count++;
+       int propval;
+
+       sun4c_disable_vac();
+       sun4c_vacinfo.num_bytes = prom_getintdefault(prom_root_node,
+                                                    "vac-size", 65536);
+       sun4c_vacinfo.linesize = prom_getintdefault(prom_root_node,
+                                                   "vac-linesize", 16);
+       sun4c_vacinfo.num_lines =
+               (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
+       switch(sun4c_vacinfo.linesize) {
+       case 16:
+               sun4c_vacinfo.log2lsize = 4;
+               break;
+       case 32:
+               sun4c_vacinfo.log2lsize = 5;
+               break;
+       default:
+               prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",
+                           sun4c_vacinfo.linesize);
+               prom_halt();
+       };
+
+       propval = prom_getintdefault(prom_root_node, "vac_hwflush", -1);
+       sun4c_vacinfo.do_hwflushes = (propval == -1 ?
+                                     prom_getintdefault(prom_root_node,
+                                                        "vac-hwflush", 0) :
+                                     propval);
+
+       if(sun4c_vacinfo.num_bytes != 65536) {
+               prom_printf("WEIRD Sun4C VAC cache size, tell davem");
+               prom_halt();
+       }
+
+       sun4c_flush_all();
+       sun4c_enable_vac();
 }
 
-int sun4c_pmd_none(pmd_t pmd)          { return !pmd_val(pmd); }
-int sun4c_pmd_bad(pmd_t pmd)
+static void sun4c_probe_mmu(void)
 {
-       return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE || pmd_val(pmd) > high_memory;
+       num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
+       num_contexts = prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
 }
 
-int sun4c_pmd_present(pmd_t pmd)       { return pmd_val(pmd) & PGD_PRESENT; }
-int sun4c_pmd_inuse(pmd_t *pmdp)        { return 0; }
-void sun4c_pmd_clear(pmd_t *pmdp)      { pmd_val(*pmdp) = 0; }
-void sun4c_pmd_reuse(pmd_t * pmdp)      { }
+static inline void sun4c_init_ss2_cache_bug(void)
+{
+       extern unsigned long start;
 
-int sun4c_pgd_none(pgd_t pgd)          { return 0; }
-int sun4c_pgd_bad(pgd_t pgd)           { return 0; }
-int sun4c_pgd_present(pgd_t pgd)       { return 1; }
-int sun4c_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)].reserved; }
-void sun4c_pgd_clear(pgd_t * pgdp)     { }
+       if(idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) {
+               /* Whee.. */
+               printk("SS2 cache bug detected, uncaching trap table page\n");
+               sun4c_flush_page((unsigned int) &start);
+               sun4c_put_pte(((unsigned long) &start),
+                       (sun4c_get_pte((unsigned long) &start) | _SUN4C_PAGE_NOCACHE));
+       }
+}
 
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
+static inline unsigned long sun4c_init_alloc_dvma_pages(unsigned long start_mem)
+{
+       unsigned long addr, pte;
+
+       for(addr = DVMA_VADDR; addr < DVMA_END; addr += PAGE_SIZE) {
+               pte = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+               pte |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_NOCACHE);
+               sun4c_put_pte(addr, pte);
+               start_mem += PAGE_SIZE;
+       }
+       return start_mem;
+}
+
+/* TLB management. */
+struct sun4c_mmu_entry {
+       struct sun4c_mmu_entry *next;
+       struct sun4c_mmu_entry *prev;
+       unsigned long vaddr;
+       unsigned char pseg;
+       unsigned char locked;
+};
+static struct sun4c_mmu_entry mmu_entry_pool[256];
+
+static void sun4c_init_mmu_entry_pool(void)
+{
+       int i;
+
+       for(i=0; i < 256; i++) {
+               mmu_entry_pool[i].pseg = i;
+               mmu_entry_pool[i].next = 0;
+               mmu_entry_pool[i].prev = 0;
+               mmu_entry_pool[i].vaddr = 0;
+               mmu_entry_pool[i].locked = 0;
+       }
+       mmu_entry_pool[invalid_segment].locked = 1;
+}
+
+static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
+                                  unsigned long bits_off)
+{
+       unsigned long start, end;
+
+       end = vaddr + SUN4C_REAL_PGDIR_SIZE;
+       for(start = vaddr; start < end; start += PAGE_SIZE)
+               if(sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
+                       sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) &
+                                     ~bits_off);
+}
+
+static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
+{
+       unsigned long vaddr;
+       unsigned char pseg, ctx;
+
+       for(vaddr = KADB_DEBUGGER_BEGVM;
+           vaddr < LINUX_OPPROM_ENDVM;
+           vaddr += SUN4C_REAL_PGDIR_SIZE) {
+               pseg = sun4c_get_segmap(vaddr);
+               if(pseg != invalid_segment) {
+                       mmu_entry_pool[pseg].locked = 1;
+                       for(ctx = 0; ctx < num_contexts; ctx++)
+                               prom_putsegment(ctx, vaddr, pseg);
+                       fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
+               }
+       }
+       for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
+               pseg = sun4c_get_segmap(vaddr);
+               mmu_entry_pool[pseg].locked = 1;
+               for(ctx = 0; ctx < num_contexts; ctx++)
+                       prom_putsegment(ctx, vaddr, pseg);
+               fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE);
+       }
+}
+
+static void sun4c_init_lock_area(unsigned long start, unsigned long end)
+{
+       int i, ctx;
+
+       while(start < end) {
+               for(i=0; i < invalid_segment; i++)
+                       if(!mmu_entry_pool[i].locked)
+                               break;
+               mmu_entry_pool[i].locked = 1;
+               sun4c_init_clean_segmap(i);
+               for(ctx = 0; ctx < num_contexts; ctx++)
+                       prom_putsegment(ctx, start, mmu_entry_pool[i].pseg);
+               start += SUN4C_REAL_PGDIR_SIZE;
+       }
+}
+
+struct sun4c_mmu_ring {
+       struct sun4c_mmu_entry ringhd;
+       int num_entries;
+};
+static struct sun4c_mmu_ring sun4c_context_ring[16]; /* used user entries */
+static struct sun4c_mmu_ring sun4c_ufree_ring;       /* free user entries */
+static struct sun4c_mmu_ring sun4c_kernel_ring;      /* used kernel entries */
+static struct sun4c_mmu_ring sun4c_kfree_ring;       /* free kernel entries */
+
+static inline void sun4c_init_rings(void)
+{
+       int i;
+       for(i=0; i<16; i++) {
+               sun4c_context_ring[i].ringhd.next =
+                       sun4c_context_ring[i].ringhd.prev =
+                       &sun4c_context_ring[i].ringhd;
+               sun4c_context_ring[i].num_entries = 0;
+       }
+       sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
+               &sun4c_ufree_ring.ringhd;
+       sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
+               &sun4c_kernel_ring.ringhd;
+       sun4c_kfree_ring.ringhd.next = sun4c_kfree_ring.ringhd.prev =
+               &sun4c_kfree_ring.ringhd;
+       sun4c_ufree_ring.num_entries = sun4c_kernel_ring.num_entries =
+               sun4c_kfree_ring.num_entries = 0;
+}
+
+static inline void add_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
+{
+       struct sun4c_mmu_entry *head = &ring->ringhd;
+
+       entry->prev = head;
+       (entry->next = head->next)->prev = entry;
+       head->next = entry;
+       ring->num_entries++;
+}
+
+static inline void remove_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
+{
+       struct sun4c_mmu_entry *next = entry->next;
+
+       (next->prev = entry->prev)->next = next;
+       ring->num_entries--;
+}
+
+static inline void recycle_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
+{
+       struct sun4c_mmu_entry *head = &ring->ringhd;
+       struct sun4c_mmu_entry *next = entry->next;
+
+       (next->prev = entry->prev)->next = next;
+       entry->prev = head; (entry->next = head->next)->prev = entry;
+       head->next = entry;
+       /* num_entries stays the same */
+}
+
+static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
+{
+        remove_ring(sun4c_context_ring+ctx, entry);
+        add_ring(&sun4c_ufree_ring, entry);
+}
+
+static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry) 
+{
+        remove_ring(&sun4c_ufree_ring, entry);
+        add_ring(sun4c_context_ring+ctx, entry);
+}
+
+static inline void free_kernel_entry(struct sun4c_mmu_entry *entry, struct sun4c_mmu_ring *ring)
+{
+        remove_ring(ring, entry);
+        add_ring(&sun4c_kfree_ring, entry);
+}
+
+static inline void assign_kernel_entry(struct sun4c_mmu_entry *entry, struct sun4c_mmu_ring *ring) 
+{
+        remove_ring(ring, entry);
+        add_ring(&sun4c_kernel_ring, entry);
+}
+
+static inline void reassign_kernel_entry(struct sun4c_mmu_entry *entry)
+{
+       recycle_ring(&sun4c_kernel_ring, entry);
+}
+
+static void sun4c_init_fill_kernel_ring(int howmany)
+{
+       int i;
+
+       while(howmany) {
+               for(i=0; i < invalid_segment; i++)
+                       if(!mmu_entry_pool[i].locked)
+                               break;
+               mmu_entry_pool[i].locked = 1;
+               sun4c_init_clean_segmap(i);
+               add_ring(&sun4c_kfree_ring, &mmu_entry_pool[i]);
+               howmany--;
+       }
+}
+
+static void sun4c_init_fill_user_ring(void)
+{
+       int i;
+
+       for(i=0; i < invalid_segment; i++) {
+               if(mmu_entry_pool[i].locked)
+                       continue;
+               sun4c_init_clean_segmap(i);
+               add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]);
+       }
+}
+
+static inline void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
+{
+       int savectx, ctx;
+
+       savectx = sun4c_get_context();
+       flush_user_windows();
+       sun4c_flush_segment(kentry->vaddr);
+       for(ctx = 0; ctx < num_contexts; ctx++) {
+               sun4c_set_context(ctx);
+               sun4c_put_segmap(kentry->vaddr, invalid_segment);
+       }
+       sun4c_set_context(savectx);
+}
+
+static inline void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
+{
+       int savectx, ctx;
+
+       savectx = sun4c_get_context();
+       flush_user_windows();
+       for(ctx = 0; ctx < num_contexts; ctx++) {
+               sun4c_set_context(ctx);
+               sun4c_put_segmap(kentry->vaddr, kentry->pseg);
+       }
+       sun4c_set_context(savectx);
+}
+
+static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry)
+{
+       sun4c_flush_segment(uentry->vaddr);
+       sun4c_put_segmap(uentry->vaddr, invalid_segment);
+}
+
+static inline void sun4c_user_map(struct sun4c_mmu_entry *uentry)
+{
+       unsigned long start = uentry->vaddr;
+       unsigned long end = start + SUN4C_REAL_PGDIR_SIZE;
+
+       sun4c_put_segmap(uentry->vaddr, uentry->pseg);
+       while(start < end) {
+               sun4c_put_pte(start, 0);
+               start += PAGE_SIZE;
+       }
+}
+
+static inline void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx)
+{
+       struct sun4c_mmu_entry *this_entry, *next_entry;
+       int savectx = sun4c_get_context();
+
+       this_entry = crp->ringhd.next;
+       flush_user_windows();
+       sun4c_set_context(ctx);
+       while(crp->num_entries) {
+               next_entry = this_entry->next;
+               sun4c_user_unmap(this_entry);
+               free_user_entry(ctx, this_entry);
+               this_entry = next_entry;
+       }
+       sun4c_set_context(savectx);
+}
+
+static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx)
+{
+       struct sun4c_mmu_entry *entry = crp->ringhd.next;
+       int savectx = sun4c_get_context();
+
+       flush_user_windows();
+       sun4c_set_context(ctx);
+       sun4c_user_unmap(entry);
+       free_user_entry(ctx, entry);
+       sun4c_set_context(savectx);
+}
+
+/* Using this method to free up mmu entries eliminates a lot of
+ * potention races since we have a kernel that incurs tlb
+ * replacement faults.  There may be performance penalties.
  */
-int sun4c_pte_read(pte_t pte)          { return !(pte_val(pte) & _SUN4C_PAGE_PRIV); }
-int sun4c_pte_write(pte_t pte)         { return pte_val(pte) & _SUN4C_PAGE_WRITE; }
-int sun4c_pte_exec(pte_t pte)          { return !(pte_val(pte) & _SUN4C_PAGE_PRIV); }
-int sun4c_pte_dirty(pte_t pte)         { return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
-int sun4c_pte_young(pte_t pte)         { return pte_val(pte) & _SUN4C_PAGE_REF; }
-int sun4c_pte_cow(pte_t pte)           { return pte_val(pte) & _SUN4C_PAGE_COW; }
-
-pte_t sun4c_pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
-pte_t sun4c_pte_rdprotect(pte_t pte)   { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
-pte_t sun4c_pte_exprotect(pte_t pte)   { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
-pte_t sun4c_pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
-pte_t sun4c_pte_mkold(pte_t pte)       { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
-pte_t sun4c_pte_uncow(pte_t pte)       { pte_val(pte) &= ~_SUN4C_PAGE_COW; return pte; }
-pte_t sun4c_pte_mkwrite(pte_t pte)     { pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
-pte_t sun4c_pte_mkread(pte_t pte)      { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
-pte_t sun4c_pte_mkexec(pte_t pte)      { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
-pte_t sun4c_pte_mkdirty(pte_t pte)     { pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
-pte_t sun4c_pte_mkyoung(pte_t pte)     { pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
-pte_t sun4c_pte_mkcow(pte_t pte)       { pte_val(pte) |= _SUN4C_PAGE_COW; return pte; }
+static inline struct sun4c_mmu_entry *sun4c_user_strategy(void)
+{
+       struct sun4c_mmu_ring *rp = 0;
+       unsigned char mmuhog, i, ctx = 0;
+
+       /* If some are free, return first one. */
+       if(sun4c_ufree_ring.num_entries)
+               return sun4c_ufree_ring.ringhd.next;
+
+       /* Else free one up. */
+       mmuhog = 0;
+       for(i=0; i < num_contexts; i++) {
+               if(sun4c_context_ring[i].num_entries > mmuhog) {
+                       rp = &sun4c_context_ring[i];
+                       mmuhog = rp->num_entries;
+                       ctx = i;
+               }
+       }
+       sun4c_demap_one(rp, ctx);
+       return sun4c_ufree_ring.ringhd.next;
+}
+
+static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
+{
+       struct sun4c_mmu_entry *this_entry;
+
+       /* If some are free, return first one. */
+       if(sun4c_kfree_ring.num_entries)
+               return sun4c_kfree_ring.ringhd.next;
+
+       /* Else free one up. */
+       this_entry = sun4c_kernel_ring.ringhd.prev;
+       sun4c_kernel_unmap(this_entry);
+       free_kernel_entry(this_entry, &sun4c_kernel_ring);
+       return sun4c_kfree_ring.ringhd.next;
+}
+
+static inline void alloc_user_segment(unsigned long address, unsigned char ctx)
+{
+       struct sun4c_mmu_entry *entry;
+
+       address &= SUN4C_REAL_PGDIR_MASK;
+       entry = sun4c_user_strategy();
+       assign_user_entry(ctx, entry);
+       entry->vaddr = address;
+       sun4c_user_map(entry);
+}
+
+static inline void alloc_kernel_segment(unsigned long address)
+{
+       struct sun4c_mmu_entry *entry;
+
+       address &= SUN4C_REAL_PGDIR_MASK;
+       entry = sun4c_kernel_strategy();
+
+       assign_kernel_entry(entry, &sun4c_kfree_ring);
+       entry->vaddr = address;
+       sun4c_kernel_map(entry);
+}
+
+/* XXX Just like kernel tlb replacement we'd like to have a low level
+ * XXX equivalent for user faults which need not go through the mm
+ * XXX subsystem just to load a mmu entry.  But this might not be as
+ * XXX feasible since we need to go through the kernel page tables
+ * XXX for this process, which we currently don't lock into the mmu
+ * XXX so we would fault with traps off... must think about this...
+ */
+static void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       address &= PAGE_MASK;
+       if(sun4c_get_segmap(address) == invalid_segment)
+               alloc_user_segment(address, sun4c_get_context());
+       sun4c_put_pte(address, pte_val(pte));
+       restore_flags(flags);
+}
+
+/* READ THIS:  If you put any diagnostic printing code in any of the kernel
+ *             fault handling code you will lose badly.  This is the most
+ *             delicate piece of code in the entire kernel, atomicity of
+ *             kernel tlb replacement must be guarenteed.  This is why we
+ *             have seperate user and kernel allocation rings to alleviate
+ *             as many bad interactions as possible.
+ *
+ * XXX Someday make this into a fast in-window trap handler to avoid
+ * XXX any and all races.  *High* priority, also for performance.
+ */
+static void sun4c_quick_kernel_fault(unsigned long address)
+{
+       unsigned long end, flags;
+
+       save_flags(flags); cli();
+       address &= SUN4C_REAL_PGDIR_MASK;
+       end = address + SUN4C_REAL_PGDIR_SIZE;
+       if(sun4c_get_segmap(address) == invalid_segment)
+               alloc_kernel_segment(address);
+
+       if(address < SUN4C_VMALLOC_START) {
+               unsigned long pte;
+               pte = (address - PAGE_OFFSET) >> PAGE_SHIFT;
+               pte |= pgprot_val(SUN4C_PAGE_KERNEL);
+               /* Stupid pte tricks... */
+               while(address < end) {
+                       sun4c_put_pte(address, pte++);
+                       address += PAGE_SIZE;
+               }
+       } else {
+               pte_t *ptep;
+
+               ptep = (pte_t *) (PAGE_MASK & pgd_val(swapper_pg_dir[address>>SUN4C_PGDIR_SHIFT]));
+               ptep = (ptep + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1)));
+               while(address < end) {
+                       sun4c_put_pte(address, pte_val(*ptep++));
+                       address += PAGE_SIZE;
+               }
+       }
+       restore_flags(flags);
+}
 
 /*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
+ * 4 page buckets for task struct and kernel stack allocation.
+ *
+ * TASK_STACK_BEGIN
+ * bucket[0]
+ * bucket[1]
+ *   [ ... ]
+ * bucket[NR_TASKS-1]
+ * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASKS)
+ *
+ * Each slot looks like:
+ *
+ *  page 1   --  task struct
+ *  page 2   --  unmapped, for stack redzone (maybe use for pgd)
+ *  page 3/4 --  kernel stack
  */
-pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
+
+struct task_bucket {
+       struct task_struct task;
+       char _unused1[PAGE_SIZE - sizeof(struct task_struct)];
+       char _unused2[PAGE_SIZE];
+       char kstack[(PAGE_SIZE<<1)];
+};
+
+struct task_bucket *sun4c_bucket[NR_TASKS];
+
+#define BUCKET_EMPTY     ((struct task_bucket *) 0)
+#define BUCKET_SIZE      (PAGE_SIZE << 2)
+#define BUCKET_SHIFT     14        /* log2(sizeof(struct task_bucket)) */
+#define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT))
+#define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR)
+#define BUCKET_PTE(page)       \
+        ((((page) - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL))
+#define BUCKET_PTE_PAGE(pte)   \
+        (PAGE_OFFSET + (((pte) & 0xffff) << PAGE_SHIFT))
+
+static inline void get_task_segment(unsigned long addr)
 {
-       return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
+       struct sun4c_mmu_entry *stolen;
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       addr &= SUN4C_REAL_PGDIR_MASK;
+       stolen = sun4c_user_strategy();
+       remove_ring(&sun4c_ufree_ring, stolen);
+       stolen->vaddr = addr;
+       sun4c_kernel_map(stolen);
+       restore_flags(flags);
 }
 
-pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
+static inline void free_task_segment(unsigned long addr)
 {
-       return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot));
+       struct sun4c_mmu_entry *entry;
+       unsigned long flags;
+       unsigned char pseg;
+
+       save_flags(flags); cli();
+       addr &= SUN4C_REAL_PGDIR_MASK;
+       pseg = sun4c_get_segmap(addr);
+       entry = &mmu_entry_pool[pseg];
+       sun4c_flush_segment(addr);
+       sun4c_kernel_unmap(entry);
+       add_ring(&sun4c_ufree_ring, entry);
+       restore_flags(flags);
 }
 
-unsigned long sun4c_pte_page(pte_t pte)
+static inline void garbage_collect(int entry)
 {
-       return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT)));
+       int start, end;
+
+       /* 16 buckets per segment... */
+       entry &= ~15;
+       start = entry;
+       for(end = (start + 16); start < end; start++)
+               if(sun4c_bucket[start] != BUCKET_EMPTY)
+                       return;
+       /* Entire segment empty, release it. */
+       free_task_segment(BUCKET_ADDR(entry));
 }
 
-unsigned long sun4c_pmd_page(pmd_t pmd)
+static struct task_struct *sun4c_alloc_task_struct(void)
 {
-       return (pmd_val(pmd) & PAGE_MASK);
+       unsigned long addr, page;
+       int entry;
+
+       page = get_free_page(GFP_KERNEL);
+       if(!page)
+               return (struct task_struct *) 0;
+       /* XXX Bahh, linear search too slow, use hash
+        * XXX table in final implementation.  Or
+        * XXX keep track of first free when we free
+        * XXX a bucket... anything but this.
+        */
+       for(entry = 0; entry < NR_TASKS; entry++)
+               if(sun4c_bucket[entry] == BUCKET_EMPTY)
+                       break;
+       if(entry == NR_TASKS) {
+               free_page(page);
+               return (struct task_struct *) 0;
+       }
+       addr = BUCKET_ADDR(entry);
+       sun4c_bucket[entry] = (struct task_bucket *) addr;
+       if(sun4c_get_segmap(addr) == invalid_segment)
+               get_task_segment(addr);
+       sun4c_put_pte(addr, BUCKET_PTE(page));
+       return (struct task_struct *) addr;
 }
 
-/* to find an entry in a page-table-directory */
-pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
+static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk)
 {
-       return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
+       unsigned long saddr = (unsigned long) tsk;
+       unsigned long page[2];
+
+       if(!saddr)
+               return 0;
+       page[0] = get_free_page(GFP_KERNEL);
+       if(!page[0])
+               return 0;
+       page[1] = get_free_page(GFP_KERNEL);
+       if(!page[1]) {
+               free_page(page[0]);
+               return 0;
+       }
+       saddr += (PAGE_SIZE << 1);
+       sun4c_put_pte(saddr - PAGE_SIZE, 0);
+       sun4c_put_pte(saddr, BUCKET_PTE(page[0]));
+       sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1]));
+       return saddr;
 }
 
-/* Find an entry in the second-level page table.. */
-pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address)
+static void sun4c_free_kernel_stack(unsigned long stack)
 {
-       return (pmd_t *) dir;
+       unsigned long page[2];
+
+       page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
+       page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
+       sun4c_flush_segment(stack & SUN4C_REAL_PGDIR_MASK);
+       sun4c_put_pte(stack, 0);
+       sun4c_put_pte(stack + PAGE_SIZE, 0);
+       free_page(page[0]);
+       free_page(page[1]);
 }
 
-/* Find an entry in the third-level page table.. */ 
-pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
+static void sun4c_free_task_struct(struct task_struct *tsk)
 {
-       return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
+       unsigned long tsaddr = (unsigned long) tsk;
+       unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+       int entry = BUCKET_NUM(tsaddr);
+
+       sun4c_flush_segment(tsaddr & SUN4C_REAL_PGDIR_MASK);
+       sun4c_put_pte(tsaddr, 0);
+       sun4c_bucket[entry] = BUCKET_EMPTY;
+       free_page(page);
+       garbage_collect(entry);
+}
+
+static void sun4c_init_buckets(void)
+{
+       int entry;
+
+       if(sizeof(struct task_bucket) != (PAGE_SIZE << 2)) {
+               prom_printf("task bucket not 4 pages!\n");
+               prom_halt();
+       }
+       for(entry = 0; entry < NR_TASKS; entry++)
+               sun4c_bucket[entry] = BUCKET_EMPTY;
+}
+
+static unsigned long sun4c_iobuffer_start;
+static unsigned long sun4c_iobuffer_end;
+static unsigned long *sun4c_iobuffer_map;
+static int iobuffer_map_size;
+
+static char *sun4c_lockpage(char *vaddr, unsigned long _unused)
+{
+       unsigned long vpage, voffset, search, pte;
+       unsigned long npage;
+
+       vpage = ((unsigned long) vaddr) & PAGE_MASK;
+       voffset = ((unsigned long) vaddr) & ~PAGE_MASK;
+       pte = ((vpage-PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL);
+       pte |= _SUN4C_PAGE_NOCACHE;
+       search = find_first_zero_bit(sun4c_iobuffer_map, iobuffer_map_size);
+       set_bit(search, sun4c_iobuffer_map);
+       npage = (search << PAGE_SHIFT) + sun4c_iobuffer_start;
+       sun4c_flush_page(vpage);
+       sun4c_put_pte(npage, pte);
+       return (char *) (npage + voffset);
+}
+
+static void sun4c_unlockpage(char *vaddr, unsigned long _unused)
+{
+       unsigned long vpage, nr;
+
+       vpage = (unsigned long) vaddr;
+       vpage &= PAGE_MASK;
+       nr = (vpage - sun4c_iobuffer_start) >> PAGE_SHIFT;
+       sun4c_put_pte(vpage, 0);
+       clear_bit(nr, sun4c_iobuffer_map);
+}
+
+/* Note the scsi code at init time passes to here buffers
+ * which sit on the kernel stack, those are already locked
+ * by implication and fool the page locking code above
+ * if passed to by mistake.
+ */
+static char *sun4c_get_scsi_buffer(char *bufptr, unsigned long len, struct linux_sbus *sbus)
+{
+       unsigned long page1, page2;
+
+       page1 = ((unsigned long) bufptr) & PAGE_MASK;
+       page2 = (((unsigned long) bufptr) + len - 1) & PAGE_MASK;
+       if(page1 != page2) {
+               printk("Problem, trying to lock multipage scsi buffer.\n");
+               printk("page1<%08lx> page2<%08lx>\n", page1, page2);
+               panic("Scsi buffer too big.");
+       }
+       if(page1 > high_memory)
+               return bufptr; /* already locked */
+       return sun4c_lockpage(bufptr, PAGE_SIZE);
+}
+
+static void sun4c_release_scsi_buffer(char *bufptr, unsigned long len, struct linux_sbus *sbus)
+{
+       unsigned long page = (unsigned long) bufptr;
+
+       if(page < sun4c_iobuffer_start)
+               return; /* On kernel stack or similar, see above */
+       sun4c_unlockpage(bufptr, PAGE_SIZE);
+}
+
+#define TASK_ENTRY_SIZE    (3 * PAGE_SIZE)
+#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+
+struct vm_area_struct sun4c_kstack_vma;
+
+static unsigned long sun4c_init_lock_areas(unsigned long start_mem)
+{
+       unsigned long sun4c_taskstack_start;
+       unsigned long sun4c_taskstack_end;
+       int bitmap_size;
+
+       sun4c_init_buckets();
+       sun4c_taskstack_start = SUN4C_LOCK_VADDR;
+       sun4c_taskstack_end = (sun4c_taskstack_start +
+                              (TASK_ENTRY_SIZE * NR_TASKS));
+       if(sun4c_taskstack_end >= SUN4C_LOCK_END) {
+               prom_printf("Too many tasks, decrease NR_TASKS please.\n");
+               prom_halt();
+       }
+
+       sun4c_iobuffer_start = SUN4C_REAL_PGDIR_ALIGN(sun4c_taskstack_end);
+       sun4c_iobuffer_end = sun4c_iobuffer_start + SUN4C_REAL_PGDIR_SIZE;
+       bitmap_size = (sun4c_iobuffer_end - sun4c_iobuffer_start) >> PAGE_SHIFT;
+       bitmap_size = (bitmap_size + 7) >> 3;
+       bitmap_size = LONG_ALIGN(bitmap_size);
+       iobuffer_map_size = bitmap_size << 3;
+       sun4c_iobuffer_map = (unsigned long *) start_mem;
+       memset((void *) start_mem, 0, bitmap_size);
+       start_mem += bitmap_size;
+
+       /* Now get us some mmu entries for I/O maps. */
+       sun4c_init_lock_area(sun4c_iobuffer_start, sun4c_iobuffer_end);
+       sun4c_kstack_vma.vm_mm = init_task.mm;
+       sun4c_kstack_vma.vm_start = sun4c_taskstack_start;
+       sun4c_kstack_vma.vm_end = sun4c_taskstack_end;
+       sun4c_kstack_vma.vm_page_prot = PAGE_SHARED;
+       sun4c_kstack_vma.vm_flags = VM_READ | VM_WRITE | VM_EXEC;
+       insert_vm_struct(&init_task, &sun4c_kstack_vma);
+       return start_mem;
+}
+
+static void sun4c_invalidate_all(void)
+{
+       struct sun4c_mmu_entry *this_entry, *next_entry;
+
+       this_entry = sun4c_kernel_ring.ringhd.next;
+       while(sun4c_kernel_ring.num_entries) {
+               next_entry = this_entry->next;
+               sun4c_kernel_unmap(this_entry);
+               free_kernel_entry(this_entry, &sun4c_kernel_ring);
+               this_entry = next_entry;
+       }
+}
+
+static void sun4c_invalidate_mm(struct mm_struct *mm)
+{
+       if(mm->context == NO_CONTEXT)
+               return;
+       sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
+}
+
+static void sun4c_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+       struct sun4c_mmu_entry *this_entry;
+       unsigned char pseg, savectx;
+
+       if(mm->context == NO_CONTEXT)
+               return;
+       flush_user_windows();
+       savectx = sun4c_get_context();
+       sun4c_set_context(mm->context);
+       start &= SUN4C_REAL_PGDIR_MASK;
+       while(start < end) {
+               pseg = sun4c_get_segmap(start);
+               if(pseg == invalid_segment)
+                       goto next_one;
+               this_entry = &mmu_entry_pool[pseg];
+               sun4c_user_unmap(this_entry);
+               free_user_entry(mm->context, this_entry);
+       next_one:
+               start += SUN4C_REAL_PGDIR_SIZE;
+       }
+       sun4c_set_context(savectx);
 }
 
-/* Here comes the sun4c mmu-tlb management engine.  It is here because
- * some of the mid-level mm support needs to be able to lock down
- * critical areas of kernel memory into the tlb.
+static void sun4c_invalidate_page(struct vm_area_struct *vma, unsigned long page)
+{
+       struct mm_struct *mm = vma->vm_mm;
+       unsigned char savectx;
+
+       if(mm->context == NO_CONTEXT)
+               return;
+       flush_user_windows();
+       savectx = sun4c_get_context();
+       sun4c_set_context(mm->context);
+       page &= PAGE_MASK;
+       if(sun4c_get_pte(page) & _SUN4C_PAGE_VALID) {
+               sun4c_flush_page(page);
+               sun4c_put_pte(page, 0);
+       }
+       sun4c_set_context(savectx);
+}
+
+/* Sun4c mmu hardware doesn't update the dirty bit in the pte's
+ * for us, so we do it in software.
  */
-static inline void add_pseg_list(struct pseg_list *head, struct pseg_list *entry)
+static void sun4c_set_pte(pte_t *ptep, pte_t pte)
+{
+
+       if((pte_val(pte) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_DIRTY)) ==
+          _SUN4C_PAGE_WRITE)
+               pte_val(pte) |= _SUN4C_PAGE_DIRTY;
+
+       *ptep = pte;
+}
+
+/* static */ void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+                    int bus_type, int rdonly)
+{
+       unsigned long page_entry;
+
+       page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
+       page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE |
+                      _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO);
+       if(rdonly)
+               page_entry &= (~_SUN4C_PAGE_WRITE);
+       sun4c_flush_page(virt_addr);
+       sun4c_put_pte(virt_addr, page_entry);
+}
+
+static inline void sun4c_alloc_context(struct mm_struct *mm)
+{
+       struct ctx_list *ctxp;
+
+       ctxp = ctx_free.next;
+       if(ctxp != &ctx_free) {
+               remove_from_ctx_list(ctxp);
+               add_to_used_ctxlist(ctxp);
+               mm->context = ctxp->ctx_number;
+               ctxp->ctx_mm = mm;
+               return;
+       }
+       ctxp = ctx_used.next;
+       if(ctxp->ctx_mm == current->mm)
+               ctxp = ctxp->next;
+       if(ctxp == &ctx_used)
+               panic("out of mmu contexts");
+       remove_from_ctx_list(ctxp);
+       add_to_used_ctxlist(ctxp);
+       ctxp->ctx_mm->context = NO_CONTEXT;
+       ctxp->ctx_mm = mm;
+       mm->context = ctxp->ctx_number;
+       sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number], ctxp->ctx_number);
+}
+
+#if some_day_soon /* We need some tweaking to start using this */
+extern void force_user_fault(unsigned long, int);
+
+void sun4c_switch_heuristic(struct pt_regs *regs)
 {
-       entry->next = head;
-       (entry->prev = head->prev)->next = entry;
-       head->prev = entry;
+       unsigned long sp = regs->u_regs[UREG_FP];
+       unsigned long sp2 = sp + REGWIN_SZ - 0x8;
+
+       force_user_fault(regs->pc, 0);
+       force_user_fault(sp, 0);
+       if((sp&PAGE_MASK) != (sp2&PAGE_MASK))
+               force_user_fault(sp2, 0);
 }
-#define add_to_used_pseg_list(entry) add_pseg_list(&s4cpseg_used, entry)
-#define add_to_free_pseg_list(entry) add_pseg_list(&s4cpseg_free, entry)
-#define add_to_locked_pseg_list(entry) add_pseg_list(&s4cpseg_locked, entry)
+#endif
 
-static inline void remove_pseg_list(struct pseg_list *entry)
+static void sun4c_switch_to_context(struct task_struct *tsk)
 {
-       entry->next->prev = entry->prev;
-       entry->prev->next = entry->next;
+       /* Kernel threads can execute in any context and so can tasks
+        * sleeping in the middle of exiting. If this task has already
+        * been allocated a piece of the mmu realestate, just jump to
+        * it.
+        */
+       if((tsk->tss.flags & SPARC_FLAG_KTHREAD) ||
+          (tsk->flags & PF_EXITING))
+               return;
+       if(tsk->mm->context == NO_CONTEXT)
+               sun4c_alloc_context(tsk->mm);
+
+       sun4c_set_context(tsk->mm->context);
 }
 
-static inline void add_pseg_ctxlist(struct pseg_list *entry, int ctx)
+static void sun4c_flush_hook(void)
 {
-       struct pseg_list *head = &s4cpseg_per_context[ctx];
+       if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+               sun4c_alloc_context(current->mm);
+               sun4c_set_context(current->mm->context);
+       }
+}
 
-       entry->ctx_next = head;
-       (entry->ctx_prev = head->ctx_prev)->ctx_next = entry;
-       head->ctx_prev = entry;
-       pseg_count_per_context[ctx]++;
+static void sun4c_exit_hook(void)
+{
+       struct ctx_list *ctx_old;
+       struct mm_struct *mm = current->mm;
+
+       if(mm->context != NO_CONTEXT) {
+               sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
+               ctx_old = ctx_list_pool + mm->context;
+               remove_from_ctx_list(ctx_old);
+               add_to_free_ctxlist(ctx_old);
+               mm->context = NO_CONTEXT;
+       }
 }
 
-static inline void remove_pseg_ctxlist(struct pseg_list *entry, int ctx)
+void sun4c_test_wp(void)
+{
+       wp_works_ok = -1;
+
+       /* Let it rip... */
+       sun4c_put_pte((unsigned long) 0x0, (_SUN4C_PAGE_VALID | _SUN4C_PAGE_PRIV));
+       __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
+       sun4c_put_pte((unsigned long) 0x0, 0x0);
+       if (wp_works_ok < 0)
+               wp_works_ok = 0;
+}
+
+static char s4cinfo[512];
+
+static char *sun4c_mmu_info(void)
+{
+       int used_user_entries, i;
+
+       used_user_entries = 0;
+       for(i=0; i < num_contexts; i++)
+               used_user_entries += sun4c_context_ring[i].num_entries;
+
+       sprintf(s4cinfo, "vacsize: %d bytes\n"
+               "vachwflush\t: %s\n"
+               "vaclinesize\t: %d bytes\n"
+               "mmuctxs\t\t: %d\n"
+               "mmupsegs\t: %d\n"
+               "usedpsegs\t: %d\n"
+               "ufreepsegs\t: %d\n"
+               "context\t\t: %d flushes\n"
+               "segment\t\t: %d flushes\n"
+               "page\t\t: %d flushes\n",
+               sun4c_vacinfo.num_bytes,
+               (sun4c_vacinfo.do_hwflushes ? "yes" : "no"),
+               sun4c_vacinfo.linesize,
+               num_contexts,
+               (invalid_segment + 1),
+               used_user_entries,
+               sun4c_ufree_ring.num_entries,
+               ctxflushes, segflushes, pageflushes);
+
+       return s4cinfo;
+}
+
+/* Nothing below here should touch the mmu hardware nor the mmu_entry
+ * data structures.
+ */
+
+static unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
+static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
+
+/* First the functions which the mid-level code uses to directly
+ * manipulate the software page tables.  Some defines since we are
+ * emulating the i386 page directory layout.
+ */
+#define PGD_PRESENT  0x001
+#define PGD_RW       0x002
+#define PGD_USER     0x004
+#define PGD_ACCESSED 0x020
+#define PGD_DIRTY    0x040
+#define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
+
+static unsigned long sun4c_vmalloc_start(void)
 {
-       entry->ctx_next->ctx_prev = entry->ctx_prev;
-       entry->ctx_prev->ctx_next = entry->ctx_next;
-       pseg_count_per_context[ctx]--;
+       return SUN4C_VMALLOC_START;
 }
 
-static inline void sun4c_init_pseg_lists(void)
+static int sun4c_pte_none(pte_t pte)           { return !pte_val(pte); }
+static int sun4c_pte_present(pte_t pte)                { return pte_val(pte) & _SUN4C_PAGE_VALID; }
+static int sun4c_pte_inuse(pte_t *ptep)         { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
+static void sun4c_pte_clear(pte_t *ptep)       { pte_val(*ptep) = 0; }
+static void sun4c_pte_reuse(pte_t *ptep)
 {
-       int i;
-
-       s4cpseg_free.prev = s4cpseg_free.next = &s4cpseg_free;
-       s4cpseg_used.prev = s4cpseg_used.next = &s4cpseg_used;
-       s4cpseg_locked.prev = s4cpseg_locked.next = &s4cpseg_locked;
-       for(i = 0; i < num_contexts; i++) {
-               s4cpseg_per_context[i].ctx_prev = s4cpseg_per_context[i].ctx_next =
-                       &s4cpseg_per_context[i];
-       }
-       for(i = 0; i <= invalid_segment; i++) {
-               s4cpseg_pool[i].vaddr = 0;
-               s4cpseg_pool[i].context = 0;
-               s4cpseg_pool[i].ref_cnt = 0;
-               s4cpseg_pool[i].hardlock = 0;
-               s4cpseg_pool[i].pseg = i;
-       }
-       s4cpseg_pool[invalid_segment].hardlock = 1;
+       if(!mem_map[MAP_NR(ptep)].reserved)
+               mem_map[MAP_NR(ptep)].count++;
 }
 
-static inline void sun4c_distribute_kernel_mapping(unsigned long address,
-                                                  unsigned char pseg)
+static int sun4c_pmd_none(pmd_t pmd)           { return !pmd_val(pmd); }
+static int sun4c_pmd_bad(pmd_t pmd)
 {
-       unsigned int flags;
-       int ctx, save_ctx;
-
-       save_flags(flags); cli();
-       save_ctx = get_context();
-       flush_user_windows();
-       for(ctx = 0; ctx < num_contexts; ctx++) {
-               set_context(ctx);
-               put_segmap(address, pseg);
-       }
-       set_context(save_ctx);
-       restore_flags(flags);
+       return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE || pmd_val(pmd) > high_memory;
 }
 
-static inline void sun4c_delete_kernel_mapping(unsigned long address)
-{
-       unsigned int flags;
-       int ctx, save_ctx;
+static int sun4c_pmd_present(pmd_t pmd)                { return pmd_val(pmd) & PGD_PRESENT; }
+static int sun4c_pmd_inuse(pmd_t *pmdp)         { return 0; }
+static void sun4c_pmd_clear(pmd_t *pmdp)       { pmd_val(*pmdp) = 0; }
+static void sun4c_pmd_reuse(pmd_t * pmdp)       { }
 
-       save_flags(flags); cli();
-       save_ctx = get_context();
-       flush_user_windows();
+static int sun4c_pgd_none(pgd_t pgd)           { return 0; }
+static int sun4c_pgd_bad(pgd_t pgd)            { return 0; }
+static int sun4c_pgd_present(pgd_t pgd)                { return 1; }
+static int sun4c_pgd_inuse(pgd_t *pgdp)         { return mem_map[MAP_NR(pgdp)].reserved; }
+static void sun4c_pgd_clear(pgd_t * pgdp)      { }
 
-       /* Flush only needed in one context for kernel mappings. */
-       sun4c_flush_segment(address);
-       for(ctx = 0; ctx < num_contexts; ctx++) {
-               set_context(ctx);
-               put_segmap(address, invalid_segment);
-       }
-       set_context(save_ctx);
-       restore_flags(flags);
-}
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static int sun4c_pte_write(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_WRITE; }
+static int sun4c_pte_dirty(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
+static int sun4c_pte_young(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_REF; }
 
-/* NOTE: You can only lock kernel tlb entries, attempts to lock
- *       pages in user vm will bolix the entire system.
+static pte_t sun4c_pte_wrprotect(pte_t pte)    { pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
+static pte_t sun4c_pte_mkclean(pte_t pte)      { pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
+static pte_t sun4c_pte_mkold(pte_t pte)                { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
+static pte_t sun4c_pte_mkwrite(pte_t pte)      { pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
+static pte_t sun4c_pte_mkdirty(pte_t pte)      { pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
+static pte_t sun4c_pte_mkyoung(pte_t pte)      { pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
  */
-static inline void sun4c_lock_tlb_entry(unsigned long address)
+static pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
 {
-       unsigned long flags;
-       unsigned char pseg;
-
-       save_flags(flags); cli();
-       /* Fault it in. */
-       __asm__ __volatile__("ldub [%0], %%g0\n\t" : : "r" (address));
-       address &= SUN4C_REAL_PGDIR_MASK;
-       pseg = get_segmap(address);
-       if(address < KERNBASE)
-               panic("locking user address space into tlb!");
-       if(pseg == invalid_segment)
-               panic("cannot lock kernel tlb entry...");
-       if(!s4cpseg_pool[pseg].ref_cnt++ && !s4cpseg_pool[pseg].hardlock) {
-               /* Move from used to locked list. */
-               remove_pseg_list(&s4cpseg_pool[pseg]);
-               add_to_locked_pseg_list(&s4cpseg_pool[pseg]);
-       }
-       restore_flags(flags);
+       return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
 }
 
-static inline void sun4c_unlock_tlb_entry(unsigned long address)
+static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot)
 {
-       unsigned long flags;
-       struct pseg_list *psegp;
-       unsigned char pseg;
+       return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
+}
 
-       save_flags(flags); cli();
-       address &= SUN4C_REAL_PGDIR_MASK;
-       pseg = get_segmap(address);
-       if(address < KERNBASE)
-               panic("unlocking user tlb entry!");
-       if(pseg == invalid_segment)
-               panic("unlocking non-locked kernel tlb entry...");
-       psegp = &s4cpseg_pool[pseg];
-       if(!--psegp->ref_cnt && !psegp->hardlock) {
-               /* Move from locked list to used list. */
-               remove_pseg_list(psegp);
-               add_to_used_pseg_list(psegp);
-       }
-       restore_flags(flags);
+static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
+{
+       return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot));
 }
 
-/* Anyone who calls this must turn _all_ interrupts off and flush
- * any necessary user windows beforehand.
- */
-static inline void sun4c_unload_context_from_tlb(unsigned char ctx)
-{
-       struct pseg_list *psegp, *pnextp;
-
-       if(pseg_count_per_context[ctx]) {
-               sun4c_flush_context(); /* Most efficient */
-               psegp = s4cpseg_per_context[ctx].ctx_next;
-               while(psegp != &s4cpseg_per_context[ctx]) {
-                       pnextp = psegp->ctx_next;
-                       if(psegp->vaddr >= KERNBASE)
-                               panic("Unloading kernel from tlb, not good.");
-                       put_segmap(psegp->vaddr, invalid_segment);
-                       remove_pseg_ctxlist(psegp, ctx);
-                       remove_pseg_list(psegp);
-                       add_to_free_pseg_list(psegp);
-                       psegp = pnextp;
-               }
-               if(pseg_count_per_context[ctx])
-                       panic("pseg_count_per_context inconsistant after "
-                             "invalidate.");
-       }
+static unsigned long sun4c_pte_page(pte_t pte)
+{
+       return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT)));
 }
 
-/* This page must be a page in user vma... again all IRQ's gotta be off. */
-static inline void sun4c_unload_page_from_tlb(unsigned long addr,
-                                             struct task_struct *tsk)
+static unsigned long sun4c_pmd_page(pmd_t pmd)
 {
-       unsigned char save_ctx;
+       return (pmd_val(pmd) & PAGE_MASK);
+}
 
-       if(tsk->tss.context != -1) {
-               save_ctx = get_context();
-               flush_user_windows();
-               set_context(tsk->tss.context);
-               sun4c_flush_page(addr);
-               put_pte(addr, 0);
-               set_context(save_ctx);
-       }
+/* to find an entry in a page-table-directory */
+static pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
+{
+       return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
 }
 
-/* NOTE: When we have finer grained invalidate()'s (RSN) this
- *       whole scheme will be much more efficient and need to
- *       be re-written.  Also note that this routine only
- *       unloads user page translations, this may need to
- *       be changed at some point.
- */
-void sun4c_invalidate(void)
+/* Find an entry in the second-level page table.. */
+static pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address)
 {
-       int orig_ctx, cur_ctx, flags;
+       return (pmd_t *) dir;
+}
 
-       save_flags(flags); cli();
-       flush_user_windows();
-       orig_ctx = get_context();
-       for(cur_ctx = 0; cur_ctx < num_contexts; cur_ctx++) {
-               set_context(cur_ctx);
-               sun4c_unload_context_from_tlb(cur_ctx);
-       }
-       set_context(orig_ctx);
-       restore_flags(flags);
+/* Find an entry in the third-level page table.. */ 
+static pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
+{
+       return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
 }
 
-/* We're only updating software tables on the sun4c. */
-void sun4c_set_pte(pte_t *ptep, pte_t pteval)
+/* Update the root mmu directory. */
+static void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
 {
-       *ptep = pteval;
 }
 
-/* Now back to the mid-level interface code:
- *
- * Allocate and free page tables. The xxx_kernel() versions are
+/* Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
  * if any, and marks the page tables reserved.
  */
-void sun4c_pte_free_kernel(pte_t *pte)
+static void sun4c_pte_free_kernel(pte_t *pte)
 {
        mem_map[MAP_NR(pte)].reserved = 0;
        free_page((unsigned long) pte);
 }
 
-pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
        address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
        if (sun4c_pmd_none(*pmd)) {
@@ -406,22 +1244,22 @@ pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-void sun4c_pmd_free_kernel(pmd_t *pmd)
+static void sun4c_pmd_free_kernel(pmd_t *pmd)
 {
        pmd_val(*pmd) = 0;
 }
 
-pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+static pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
 {
        return (pmd_t *) pgd;
 }
 
-void sun4c_pte_free(pte_t *pte)
+static void sun4c_pte_free(pte_t *pte)
 {
        free_page((unsigned long) pte);
 }
 
-pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
+static pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
 {
        address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
        if (sun4c_pmd_none(*pmd)) {
@@ -448,606 +1286,70 @@ pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-void sun4c_pmd_free(pmd_t * pmd)
+static void sun4c_pmd_free(pmd_t * pmd)
 {
        pmd_val(*pmd) = 0;
 }
 
-pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
+static pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
 {
        return (pmd_t *) pgd;
 }
 
-void sun4c_pgd_free(pgd_t *pgd)
+static void sun4c_pgd_free(pgd_t *pgd)
 {
        free_page((unsigned long) pgd);
 }
 
-pgd_t *sun4c_pgd_alloc(void)
-{
-       unsigned long new_pgd = get_free_page(GFP_KERNEL);
-       return (pgd_t *) new_pgd;
-}
-
-/* Jumping to and fro different contexts, the modifying of the pseg lists
- * must be atomic during the switch, or else...
- */
-void sun4c_switch_to_context(void *new_task)
-{
-       struct task_struct *tsk = (struct task_struct *) new_task;
-       struct task_struct *old_tsk;
-       struct ctx_list *ctxp;
-       unsigned long flags;
-       int ctx = tsk->tss.context;
-
-       /* Swapper can execute in any context, or this task
-        * has already been allocated a piece of the mmu real-
-        * estate.
-        */
-       if(tsk->pid == 0 || ctx != -1)
-               return;
-       ctxp = ctx_free.next;
-       if(ctxp != &ctx_free) {
-               save_flags(flags); cli();
-               ctx = ctxp->ctx_number;
-               remove_from_ctx_list(ctxp);
-               add_to_used_ctxlist(ctxp);
-               tsk->tss.context = ctx;
-               ctxp->ctx_task = tsk;
-               restore_flags(flags);
-               return;
-       }
-       save_flags(flags); cli();
-       ctxp = ctx_used.prev;
-       /* Don't steal from current, thank you. */
-       if(ctxp->ctx_task == current)
-               ctxp = ctxp->prev;
-       if(ctxp == &ctx_used)
-               panic("out of contexts");
-       remove_from_ctx_list(ctxp);
-       old_tsk = ctxp->ctx_task;
-       old_tsk->tss.context = -1;
-       ctxp->ctx_task = tsk;
-       tsk->tss.context = ctxp->ctx_number;
-       add_to_used_ctxlist(ctxp);
-       /* User windows flushed already by switch_to(p) macro. */
-       set_context(ctxp->ctx_number);
-       sun4c_unload_context_from_tlb(ctxp->ctx_number);
-       restore_flags(flags);
-}
-
-/* Low level IO area allocation on the Sun4c MMU.  This function is called
- * for each page of IO area you need.  Kernel code should not call this
- * routine directly, use sparc_alloc_io() instead.
- */
-void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
-                    int bus_type, int rdonly)
-{
-       unsigned long page_entry;
-
-       page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
-       page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE |
-                      _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO);
-       if(rdonly)
-               page_entry &= (~_SUN4C_PAGE_WRITE);
-       sun4c_flush_page(virt_addr);
-       put_pte(virt_addr, page_entry);
-}
-
-/* These routines are used to lock down and unlock data transfer
- * areas in the sun4c tlb.  If the pages need to be uncached the
- * caller must do that himself.
- */
-inline char *sun4c_lockarea(char *vaddr, unsigned long size)
-{
-       unsigned long flags;
-       unsigned long orig_addr = (unsigned long) vaddr;
-       unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK);
-       unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK);
-
-       save_flags(flags); cli();
-       for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE)
-               sun4c_lock_tlb_entry(first_seg);
-
-       restore_flags(flags);
-       return vaddr;
-}
-
-/* Note that when calling unlockarea you pass as 'vaddr' the address that
- * was returned to you by lockarea for this pool above.
- */
-inline void sun4c_unlockarea(char *vaddr, unsigned long size)
-{
-       unsigned long flags;
-       unsigned long orig_addr = (unsigned long) vaddr;
-       unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK);
-       unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK);
-
-       save_flags(flags); cli();
-       for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE)
-               sun4c_unlock_tlb_entry(first_seg);
-
-       restore_flags(flags);
-}
-
-/* Getting and Releasing scsi dvma buffers. */
-char *sun4c_get_scsi_buffer(char *bufptr, unsigned long len)
-{
-       unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK;
-       unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK;
-
-       /* First lock down the area. */
-       bufptr = sun4c_lockarea(bufptr, len);
-
-       /* Uncache and flush all the pages. */
-       for(; first_page <= last_page; first_page += PAGE_SIZE) {
-               sun4c_flush_page(first_page);
-               put_pte(first_page, get_pte(first_page) | PTE_NC);
-       }
-       return bufptr;
-}
-
-void sun4c_release_scsi_buffer(char *bufptr, unsigned long len)
-{
-       unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK;
-       unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK;
-
-
-       /* Recache all the pages. */
-       for(; first_page <= last_page; first_page += PAGE_SIZE)
-               put_pte(first_page, get_pte(first_page) & ~PTE_NC);
-
-       sun4c_unlockarea(bufptr, len);
-}
-
-/* Code to fill the sun4c tlb during a fault.  Plus fault helper routine. */
-int sun4c_get_fault_info(unsigned long *address, unsigned long *error_code,
-                        unsigned long from_user)
-{
-       unsigned long faddr, fstatus, new_code;
-
-       faddr = sun4c_get_synchronous_address();
-       *address = faddr;
-       if(faddr >= 0x20000000 && faddr < 0xe0000000) {
-               printk("SUN4C: Fault in vm hole at %08lx\n", faddr);
-               *error_code = from_user;
-               return 1;
-       }
-       fstatus = sun4c_get_synchronous_error();
-       if(fstatus & SUN4C_SYNC_BOLIXED)
-               panic("SUN4C: Unrecoverable fault type.");
-       new_code = 0;
-       if(fstatus & SUN4C_SYNC_PROT)
-               new_code |= FAULT_CODE_PROT;
-       if(fstatus & SUN4C_SYNC_BADWRITE)
-               new_code |= FAULT_CODE_WRITE;
-       *error_code = (new_code | from_user);
-       return 0;
-}
-
-static inline void sun4c_alloc_pseg(unsigned long address)
-{
-       struct pseg_list *psegp;
-       unsigned char cur_ctx = get_context();
-       int kernel_address = (address >= KERNBASE);
-       int user_address = !kernel_address;
-
-       psegp = s4cpseg_free.next;
-       if(psegp != &s4cpseg_free) {
-               remove_pseg_list(psegp);
-               add_to_used_pseg_list(psegp);
-               if(user_address)
-                       add_pseg_ctxlist(psegp, cur_ctx);
-               psegp->vaddr = address;
-               psegp->context = cur_ctx;
-               /* No cache flush needed */
-               if(kernel_address)
-                       sun4c_distribute_kernel_mapping(address, psegp->pseg);
-               else
-                       put_segmap(address, psegp->pseg);
-               return;
-       }
-       psegp = s4cpseg_used.prev; /* Take last used list entry. */
-       if(psegp == &s4cpseg_used)
-               panic("Sun4c psegs have disappeared...");
-       if(psegp->vaddr >= KERNBASE) {
-               sun4c_delete_kernel_mapping(psegp->vaddr);
-       } else {
-               flush_user_windows();
-               set_context(psegp->context);
-               sun4c_flush_segment(psegp->vaddr);
-               put_segmap(psegp->vaddr, invalid_segment);
-               set_context(cur_ctx);
-       }
-       remove_pseg_list(psegp);
-       if(psegp->vaddr < KERNBASE)
-               remove_pseg_ctxlist(psegp, psegp->context);
-       psegp->vaddr = address;
-       psegp->context = cur_ctx;
-       if(kernel_address)
-               sun4c_distribute_kernel_mapping(address, psegp->pseg);
-       else
-               put_segmap(address, psegp->pseg);
-       add_to_used_pseg_list(psegp);
-       if(user_address)
-               add_pseg_ctxlist(psegp, cur_ctx);
-}
-
-/*
- * handle_mm_fault() gets here so that we can update our 'view'
- * of a new address translation.  A lot of the time, mappings
- * don't change and we are just 'working the tlb cache'.
- */
-void sun4c_update_mmu_cache(struct vm_area_struct * vma,
-                           unsigned long address, pte_t pte)
-{
-       unsigned long flags, segmap, segaddr, clean;
-
-       save_flags(flags); cli();
-       address &= PAGE_MASK;
-       segaddr = address & SUN4C_REAL_PGDIR_MASK;
-       segmap = get_segmap(segaddr);
-       if(segmap == invalid_segment) {
-               sun4c_alloc_pseg(segaddr);
-               /* XXX make segmap freeing routines do this. XXX */
-               for(clean = segaddr; clean < (segaddr + SUN4C_REAL_PGDIR_SIZE);
-                   clean += PAGE_SIZE)
-                       put_pte(clean, 0);
-       }
-
-       /* If this is a user fault, only load the one pte so that
-        * the kernel's ref/mod bits accurately reflect what is
-        * in the tlb.  handle_pte_fault() causes this to work.
-        */
-       if(address < TASK_SIZE)
-               put_pte(address, pte_val(pte));
-       else {
-               /* We have a kernel fault here, load entire segment. */
-               pgd_t *pgdp;
-               pte_t *ptable;
-               int pnum = 64;
-
-               pgdp = sun4c_pgd_offset(&init_mm, segaddr);
-               ptable = sun4c_pte_offset((pmd_t *)pgdp, segaddr);
-               while(pnum--) {
-                       put_pte(segaddr, pte_val(*ptable++));
-                       segaddr += PAGE_SIZE;
-               };
-       }
-       restore_flags(flags);
-}
-
-/* Paging initialization on the Sun4c. */
-static inline void sun4c_free_all_nonlocked_psegs(void)
-{
-       struct pseg_list *plp;
-       int i;
-
-       for(i=0; i < invalid_segment; i++)
-               if(!s4cpseg_pool[i].hardlock)
-                       add_to_free_pseg_list(&s4cpseg_pool[i]);
-       /* Now for every free pseg, make all the ptes invalid. */
-       plp = s4cpseg_free.next;
-       while(plp != &s4cpseg_free) {
-               put_segmap(0x0, plp->pseg);
-               for(i=0; i<64; i++)
-                       put_pte((i * PAGE_SIZE), 0x0);
-               plp = plp->next;
-       }
-       put_segmap(0x0, invalid_segment);
-}
-
-static inline struct pseg_list *sun4c_alloc_pseg_from_free_list(void)
-{
-       struct pseg_list *psegp;
-
-       psegp = s4cpseg_free.next;
-       if(psegp != &s4cpseg_free) {
-               remove_pseg_list(psegp);
-               return psegp;
-       }
-       return 0;
-}
-
-static inline void sun4c_init_lock_area(unsigned long start_addr,
-                                       unsigned long end_addr)
-{
-       struct pseg_list *psegp;
-       unsigned long a;
-       int ctx;
-
-       for(a = start_addr; a < end_addr; a += SUN4C_REAL_PGDIR_SIZE) {
-               psegp = sun4c_alloc_pseg_from_free_list();
-               if(!psegp) {
-                       prom_printf("whoops...");
-                       prom_halt();
-               }
-               for(ctx=0;ctx<num_contexts;ctx++)
-                       prom_putsegment(ctx,a,psegp->pseg);
-               add_to_locked_pseg_list(psegp);
-               psegp->hardlock = 1;
-       }
-}
-
-static inline void sun4c_check_for_ss2_cache_bug(void)
+static pgd_t *sun4c_pgd_alloc(void)
 {
-       extern unsigned long start;
-
-       /* Well we've now got a problem, on the SS2 a cache bug
-        * causes line entries to get severely corrupted if the
-        * trap table is able to be cached.  A sane and simple
-        * workaround, at least for now, is to mark the trap
-        * table page as uncacheable.
-        *
-        * XXX Investigate other possible workarounds and see
-        * XXX if they help performance enough to warrant using
-        * XXX them.                      -- 8/6/95 davem
-        */
-       if(idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) {
-               /* Whee.. */
-               printk("SS2 cache bug detected, uncaching trap table page\n");
-               sun4c_flush_page((unsigned int) &start);
-               put_pte(((unsigned long) &start),
-                       (get_pte((unsigned long) &start) | PTE_NC));
-       }
+       return (pgd_t *) get_free_page(GFP_KERNEL);
 }
 
+#define SUN4C_KERNEL_BUCKETS   16
 extern unsigned long free_area_init(unsigned long, unsigned long);
-
-/* Whee, this is now *ultra* clean and more managable */
+extern unsigned long sparc_context_init(unsigned long, int);
 extern unsigned long end;
-extern void probe_mmu(void);
 
 unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
 {
-       unsigned long addr, vaddr, kern_begin, kern_end;
-       unsigned long prom_begin, prom_end, kadb_begin;
-       pgd_t *pgdp;
-       pte_t *pg_table;
-       int phys_seg, i, ctx;
-
-       start_mem = PAGE_ALIGN(start_mem);
+       int i, cnt;
+       unsigned long kernel_end;
 
-       probe_mmu();
+       kernel_end = (unsigned long) &end;
+       kernel_end += (SUN4C_REAL_PGDIR_SIZE * 3);
+       kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
+       sun4c_probe_mmu();
        invalid_segment = (num_segmaps - 1);
-       sun4c_init_pseg_lists();
-       for(kern_begin = KERNBASE;
-           kern_begin < (unsigned long) &end;
-           kern_begin += SUN4C_REAL_PGDIR_SIZE) {
-               unsigned char pseg = get_segmap(kern_begin);
-
-               s4cpseg_pool[pseg].hardlock=1;
-               for(ctx=0; ctx<num_contexts;ctx++)
-                       prom_putsegment(ctx,kern_begin,pseg);
-       }
-       for(kern_begin = SUN4C_REAL_PGDIR_ALIGN((unsigned long) &end);
-           kern_begin < KADB_DEBUGGER_BEGVM;
-           kern_begin += SUN4C_REAL_PGDIR_SIZE)
-               for(ctx=0; ctx<num_contexts;ctx++)
-                       prom_putsegment(ctx, kern_begin, invalid_segment);
-       for(prom_begin = KADB_DEBUGGER_BEGVM;
-           prom_begin < LINUX_OPPROM_ENDVM;
-           prom_begin += SUN4C_REAL_PGDIR_SIZE) {
-               unsigned long pseg = get_segmap(prom_begin);
-
-               if(pseg != invalid_segment) {
-                       s4cpseg_pool[pseg].hardlock=1;
-                       for(ctx=0; ctx<num_contexts; ctx++)
-                               prom_putsegment(ctx,prom_begin,pseg);
-               }
-       }
-       /* Clean the MMU of excess garbage... */
-       for(ctx=0; ctx<num_contexts;ctx++) {
-               set_context(ctx);
-               for(vaddr = 0; vaddr < 0x20000000;
-                   vaddr += SUN4C_REAL_PGDIR_SIZE)
-                       put_segmap(vaddr,invalid_segment);
-               for(vaddr = 0xe0000000; vaddr < KERNBASE;
-                   vaddr += SUN4C_REAL_PGDIR_SIZE)
-                       put_segmap(vaddr,invalid_segment);
-               for(vaddr = LINUX_OPPROM_ENDVM; vaddr != 0;
-                   vaddr += SUN4C_REAL_PGDIR_SIZE)
-                       put_segmap(vaddr,invalid_segment);
-       }
-       set_context(0);
-       sun4c_free_all_nonlocked_psegs();
-       /* Lock I/O and DVMA areas for the system. */
+       sun4c_init_mmu_entry_pool();
+       sun4c_init_rings();
+       sun4c_init_map_kernelprom(kernel_end);
+       sun4c_init_clean_mmu(kernel_end);
+       sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS);
        sun4c_init_lock_area(IOBASE_VADDR, IOBASE_END);
        sun4c_init_lock_area(DVMA_VADDR, DVMA_END);
-       /* Zero out swapper_pg_dir and pg0 */
+       start_mem = sun4c_init_lock_areas(start_mem);
+       sun4c_init_fill_user_ring();
+
+       sun4c_set_context(0);
        memset(swapper_pg_dir, 0, PAGE_SIZE);
        memset(pg0, 0, PAGE_SIZE);
-       /* This makes us Solaris boot-loader 'safe' */
-       pgd_val(swapper_pg_dir[KERNBASE>>SUN4C_PGDIR_SHIFT]) =
+       /* Save work later. */
+       pgd_val(swapper_pg_dir[SUN4C_VMALLOC_START>>SUN4C_PGDIR_SHIFT]) =
                PGD_TABLE | (unsigned long) pg0;
-
-       /* Initialize swapper_pg_dir to map the kernel
-        * addresses in high memory.  Note that as soon as we get past
-        * the 4MB lower mapping and start using dynamic memory from
-        * start_mem we can start faulting and this is ok since our
-        * pseg free list and the lower 4MB of the kernel is mapped
-        * properly in the software page tables.
-        */
-       pgdp = swapper_pg_dir;
-       kern_end = PAGE_ALIGN(end_mem);
-       kern_begin = KERNBASE;
-       while(kern_begin < kern_end) {
-               unsigned long pte, tmp;
-
-               /* We only need _one_ mapping, the high address one. */
-               pg_table = (pte_t *) (PAGE_MASK & pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT]));
-               if(!pg_table) {
-                       pg_table = (pte_t *) start_mem;
-                       start_mem += PAGE_SIZE;
-               }
-               pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT]) =
-                       PGD_TABLE | (unsigned long) pg_table;
-               pgdp++;
-               for(tmp = 0; tmp < SUN4C_PTRS_PER_PTE; tmp++, pg_table++) {
-                       if(kern_begin < kern_end)
-                               sun4c_set_pte(pg_table,
-                                             mk_pte(kern_begin,
-                                                    SUN4C_PAGE_SHARED));
-                       else
-                               sun4c_pte_clear(pg_table);
-                       pte = get_pte(kern_begin);
-                       if(pte & _SUN4C_PAGE_VALID) {
-                               pte &= ~(_SUN4C_PAGE_NOCACHE);
-                               pte |= (_SUN4C_PAGE_PRIV | _SUN4C_PAGE_WRITE |
-                                       _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY);
-                               put_pte(kern_begin, pte);
-                       }
-                       kern_begin += PAGE_SIZE;
-               }
-       }
-       sun4c_check_for_ss2_cache_bug();
-       /* Fix kadb/prom permissions. */
-       kadb_begin = KADB_DEBUGGER_BEGVM;
-       prom_end = LINUX_OPPROM_ENDVM;
-       for(; kadb_begin < prom_end; kadb_begin += PAGE_SIZE) {
-               unsigned long pte = get_pte(kadb_begin);
-               if(pte & _SUN4C_PAGE_VALID)
-                       put_pte(kadb_begin, (pte | _SUN4C_PAGE_PRIV));
-       }
-       /* Allocate the DVMA pages */
-       addr = DVMA_VADDR;
-       start_mem = PAGE_ALIGN(start_mem);
-       while(addr < DVMA_END) {
-               unsigned long dvmapte = start_mem - PAGE_OFFSET;
-
-               start_mem += PAGE_SIZE;
-               dvmapte = ((dvmapte>>PAGE_SHIFT) & 0xffff);
-               dvmapte |= (_SUN4C_PAGE_VALID |
-                           _SUN4C_PAGE_WRITE |
-                           _SUN4C_PAGE_NOCACHE);
-               put_pte(addr, dvmapte);
-               addr += PAGE_SIZE;
-       }
-       /* Tell the user our allocations */
-       for(phys_seg=0, i=0; i<=invalid_segment; i++)
-               if(s4cpseg_pool[i].hardlock)
-                       phys_seg++;
-       printk("SUN4C: Hard locked %d boot-up psegs\n", phys_seg);
-       /* Init the context pool and lists */
-       ctx_list_pool = (struct ctx_list *) start_mem;
-       start_mem += (num_contexts * sizeof(struct ctx_list));
-       for(ctx = 0; ctx < num_contexts; ctx++) {
-               struct ctx_list *clist;
-
-               clist = (ctx_list_pool + ctx);
-               clist->ctx_number = ctx;
-               clist->ctx_task = 0;
-       }
-       ctx_free.next = ctx_free.prev = &ctx_free;
-       ctx_used.next = ctx_used.prev = &ctx_used;
-       for(ctx = 0; ctx < num_contexts; ctx++)
-               add_to_free_ctxlist(ctx_list_pool + ctx);
+       sun4c_init_ss2_cache_bug();
        start_mem = PAGE_ALIGN(start_mem);
+       start_mem = sun4c_init_alloc_dvma_pages(start_mem);
+       start_mem = sparc_context_init(start_mem, num_contexts);
        start_mem = free_area_init(start_mem, end_mem);
-       start_mem = PAGE_ALIGN(start_mem);
+       cnt = 0;
+       for(i = 0; i < num_segmaps; i++)
+               if(mmu_entry_pool[i].locked)
+                       cnt++;
+       printk("SUN4C: %d mmu entries for the kernel\n", cnt);
        return start_mem;
 }
 
-/* Test the WP bit on the sun4c. */
-void sun4c_test_wp(void)
-{
-       wp_works_ok = -1;
-
-       /* Let it rip... */
-       put_pte((unsigned long) 0x0, (PTE_V | PTE_P));
-       __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
-       put_pte((unsigned long) 0x0, 0x0);
-       if (wp_works_ok < 0)
-               wp_works_ok = 0;
-}
-
-void sun4c_lock_entire_kernel(unsigned long start_mem)
-{
-       unsigned long addr = (unsigned long) &end;
-
-       addr = (addr & SUN4C_REAL_PGDIR_MASK);
-       start_mem = SUN4C_REAL_PGDIR_ALIGN(start_mem);
-       while(addr < start_mem) {
-               int pseg;
-
-               sun4c_lock_tlb_entry(addr);
-               pseg = get_segmap(addr);
-               if(!s4cpseg_pool[pseg].hardlock) {
-                       s4cpseg_pool[pseg].hardlock = 1;
-                       remove_pseg_list(&s4cpseg_pool[pseg]);
-               }
-               addr += SUN4C_REAL_PGDIR_SIZE;
-       }
-}
-
-static void sun4c_fork_hook(void *vtask, unsigned long kthread_usp)
-{
-       struct task_struct *new_task = vtask;
-
-       /* These pages must not cause a fault when traps
-        * are off (such as in a window spill/fill) so
-        * lock them down for the life of the task.
-        */
-       sun4c_lock_tlb_entry((unsigned long) new_task);
-       sun4c_lock_tlb_entry(new_task->kernel_stack_page);
-       if(kthread_usp)
-               sun4c_lock_tlb_entry(kthread_usp);
-}
-
-static void sun4c_release_hook(void *vtask)
-{
-       struct task_struct *old_task = vtask;
-       struct ctx_list *ctx_old;
-       struct pt_regs *regs;
-       unsigned char this_ctx = get_context();
-       unsigned long flags;
-
-       save_flags(flags); cli();
-       if(old_task == &init_task)
-               panic("AIEEE releasing swapper");
-       if(old_task->tss.context != -1) {
-
-               /* Clear from the mmu, all notions of this dead task. */
-               flush_user_windows();
-               set_context(old_task->tss.context);
-               sun4c_unload_context_from_tlb(old_task->tss.context);
-               set_context(this_ctx);
-
-               ctx_old = ctx_list_pool + old_task->tss.context;
-               remove_from_ctx_list(ctx_old);
-               add_to_free_ctxlist(ctx_old);
-               old_task->tss.context = -1;
-       }
-       regs = (struct pt_regs *) 
-               (((old_task->tss.ksp & ~0xfff)) + (0x1000 - TRACEREG_SZ));
-       if(regs->u_regs[UREG_FP] > KERNBASE)
-               sun4c_unlock_tlb_entry(regs->u_regs[UREG_FP] & PAGE_MASK);
-       sun4c_unlock_tlb_entry(old_task->kernel_stack_page);
-       sun4c_unlock_tlb_entry((unsigned long) old_task);
-       restore_flags(flags);
-       /* bye bye... */
-}
-
-static void sun4c_flush_hook(void *vtask)
-{
-       struct task_struct *dead_task = vtask;
-
-       if(dead_task->tss.context != -1)
-               sun4c_flush_context();
-}
-
-static void sun4c_task_cacheflush(void *vtask)
-{
-       struct task_struct *flush_task = vtask;
-
-       if(flush_task->tss.context != -1)
-               sun4c_flush_context();
-}
-
-static void sun4c_exit_hook(void *vtask)
-{
-}
-
 /* Load up routines and constants for sun4c mmu */
 void ld_mmu_sun4c(void)
 {
@@ -1070,10 +1372,14 @@ void ld_mmu_sun4c(void)
        page_copy = SUN4C_PAGE_COPY;
        page_readonly = SUN4C_PAGE_READONLY;
        page_kernel = SUN4C_PAGE_KERNEL;
-       page_invalid = SUN4C_PAGE_INVALID;
+       pg_iobits = _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO | _SUN4C_PAGE_VALID
+           | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_DIRTY;
        
        /* Functions */
-       invalidate = sun4c_invalidate;
+       invalidate_all = sun4c_invalidate_all;
+       invalidate_mm = sun4c_invalidate_mm;
+       invalidate_range = sun4c_invalidate_range;
+       invalidate_page = sun4c_invalidate_page;
        set_pte = sun4c_set_pte;
        switch_to_context = sun4c_switch_to_context;
        pmd_align = sun4c_pmd_align;
@@ -1105,6 +1411,7 @@ void ld_mmu_sun4c(void)
        pgd_clear = sun4c_pgd_clear;
 
        mk_pte = sun4c_mk_pte;
+       mk_pte_io = sun4c_mk_pte_io;
        pte_modify = sun4c_pte_modify;
        pgd_offset = sun4c_pgd_offset;
        pmd_offset = sun4c_pmd_offset;
@@ -1120,35 +1427,31 @@ void ld_mmu_sun4c(void)
        pgd_free = sun4c_pgd_free;
        pgd_alloc = sun4c_pgd_alloc;
 
-       pte_read = sun4c_pte_read;
        pte_write = sun4c_pte_write;
-       pte_exec = sun4c_pte_exec;
        pte_dirty = sun4c_pte_dirty;
        pte_young = sun4c_pte_young;
-       pte_cow = sun4c_pte_cow;
        pte_wrprotect = sun4c_pte_wrprotect;
-       pte_rdprotect = sun4c_pte_rdprotect;
-       pte_exprotect = sun4c_pte_exprotect;
        pte_mkclean = sun4c_pte_mkclean;
        pte_mkold = sun4c_pte_mkold;
-       pte_uncow = sun4c_pte_uncow;
        pte_mkwrite = sun4c_pte_mkwrite;
-       pte_mkread = sun4c_pte_mkread;
-       pte_mkexec = sun4c_pte_mkexec;
        pte_mkdirty = sun4c_pte_mkdirty;
        pte_mkyoung = sun4c_pte_mkyoung;
-       pte_mkcow = sun4c_pte_mkcow;
-       get_fault_info = sun4c_get_fault_info;
        update_mmu_cache = sun4c_update_mmu_cache;
        mmu_exit_hook = sun4c_exit_hook;
-       mmu_fork_hook = sun4c_fork_hook;
-       mmu_release_hook = sun4c_release_hook;
        mmu_flush_hook = sun4c_flush_hook;
-       mmu_task_cacheflush = sun4c_task_cacheflush;
-       mmu_lockarea = sun4c_lockarea;
-       mmu_unlockarea = sun4c_unlockarea;
+       mmu_lockarea = sun4c_lockpage;
+       mmu_unlockarea = sun4c_unlockpage;
        mmu_get_scsi_buffer = sun4c_get_scsi_buffer;
        mmu_release_scsi_buffer = sun4c_release_scsi_buffer;
+       
+       /* Task struct and kernel stack allocating/freeing. */
+       alloc_kernel_stack = sun4c_alloc_kernel_stack;
+       alloc_task_struct = sun4c_alloc_task_struct;
+       free_kernel_stack = sun4c_free_kernel_stack;
+       free_task_struct = sun4c_free_task_struct;
+
+       quick_kernel_fault = sun4c_quick_kernel_fault;
+       mmu_info = sun4c_mmu_info;
 
        /* These should _never_ get called with two level tables. */
        pgd_set = 0;
diff --git a/arch/sparc/mm/sun4c_vac.c b/arch/sparc/mm/sun4c_vac.c
deleted file mode 100644 (file)
index 75e2498..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* $Id: sun4c_vac.c,v 1.5 1995/11/25 00:59:43 davem Exp $
- * vac.c:   Routines for flushing various amount of the Sparc VAC
- *          (virtual address cache) on the sun4c.
- *
- * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <asm/vac-ops.h>
-#include <asm/page.h>
-
-struct sun4c_vac_props sun4c_vacinfo;
-
-/* Invalidate the entire sun4c VAC, it must be off at this point */
-void
-sun4c_flush_all(void)
-{
-       unsigned long begin, end;
-
-       if(sun4c_vacinfo.on)
-               panic("SUN4C: AIEEE, trying to invalidate vac while"
-                      " it is on.");
-
-       /* Clear 'valid' bit in all cache line tags */
-       begin = AC_CACHETAGS;
-       end = (AC_CACHETAGS + sun4c_vacinfo.num_bytes);
-       while(begin < end) {
-               __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
-                                    "r" (begin), "i" (ASI_CONTROL));
-               begin += sun4c_vacinfo.linesize;
-       }
-       return;
-}
-
index e58bf168e4f23f42fec33e168467c4b03b770b45..bcaa389bc1d59e9545e0abc23df12c8d9a9cf0f2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bootstr.c,v 1.3 1995/11/25 00:59:51 davem Exp $
+/* $Id: bootstr.c,v 1.4 1996/02/08 07:06:43 zaitcev Exp $
  * bootstr.c:  Boot string/argument acquisition from the PROM.
  *
  * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -6,7 +6,7 @@
 
 #include <asm/oplib.h>
 
-static char barg_buf[128];
+static char barg_buf[256];
 
 char *
 prom_getbootargs(void)
index f7ff344fb56b0ef49652a3f76317ef9282621708..16a83e42fdc72cb917e143004bfec0ff6ee2139a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.5 1995/11/25 00:59:54 davem Exp $
+/* $Id: console.c,v 1.6 1996/01/01 02:46:27 davem Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
@@ -77,11 +77,38 @@ prom_putchar(char c)
 enum prom_input_device
 prom_query_input_device()
 {
-       switch(*romvec->pv_stdin) {
-       case PROMDEV_KBD:       return PROMDEV_IKBD;
-       case PROMDEV_TTYA:      return PROMDEV_ITTYA;
-       case PROMDEV_TTYB:      return PROMDEV_ITTYB;
+       int st_p;
+       char propb[64];
+       char *p;
+
+       switch(prom_vers) {
+       case PROM_V0:
+       case PROM_V2:
        default:
+               switch(*romvec->pv_stdin) {
+               case PROMDEV_KBD:       return PROMDEV_IKBD;
+               case PROMDEV_TTYA:      return PROMDEV_ITTYA;
+               case PROMDEV_TTYB:      return PROMDEV_ITTYB;
+               default:
+                       return PROMDEV_I_UNK;
+               };
+       case PROM_V3:
+       case PROM_P1275:
+               st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
+               if(prom_node_has_property(st_p, "keyboard"))
+                       return PROMDEV_IKBD;
+               prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+               if(strncmp(propb, "serial", sizeof("serial")))
+                       return PROMDEV_I_UNK;
+               prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
+               p = propb;
+               while(*p) p++; p -= 2;
+               if(p[0] == ':') {
+                       if(p[1] == 'a')
+                               return PROMDEV_ITTYA;
+                       else if(p[1] == 'b')
+                               return PROMDEV_ITTYB;
+               }
                return PROMDEV_I_UNK;
        };
 }
@@ -92,7 +119,8 @@ enum prom_output_device
 prom_query_output_device()
 {
        int st_p;
-       char propb[ sizeof("display") ];
+       char propb[64];
+       char *p;
        int propl;
 
        switch(prom_vers) {
@@ -113,12 +141,26 @@ prom_query_output_device()
                {
                        return PROMDEV_OSCREEN;
                }
-               /* This works on SS-2 (an early OpenFirmware) still. */
-               /* XXX fix for serial cases at SS-5.                 */
-               switch(*romvec->pv_stdin) {
-               case PROMDEV_TTYA:      return PROMDEV_OTTYA;
-               case PROMDEV_TTYB:      return PROMDEV_OTTYB;
-               };
+               if(prom_vers == PROM_V3) {
+                       if(strncmp("serial", propb, sizeof("serial")))
+                               return PROMDEV_O_UNK;
+                       prom_getproperty(prom_root_node, "stdout-path", propb, sizeof(propb));
+                       p = propb;
+                       while(*p) p++; p -= 2;
+                       if(p[0]==':') {
+                               if(p[1] == 'a')
+                                       return PROMDEV_OTTYA;
+                               else if(p[1] == 'b')
+                                       return PROMDEV_OTTYB;
+                       }
+                       return PROMDEV_O_UNK;
+               } else {
+                       /* This works on SS-2 (an early OpenFirmware) still. */
+                       switch(*romvec->pv_stdin) {
+                       case PROMDEV_TTYA:      return PROMDEV_OTTYA;
+                       case PROMDEV_TTYB:      return PROMDEV_OTTYB;
+                       };
+               }
                break;
        };
        return PROMDEV_O_UNK;
diff --git a/arch/sparc/prom/devtree.c b/arch/sparc/prom/devtree.c
new file mode 100644 (file)
index 0000000..65af43e
--- /dev/null
@@ -0,0 +1,114 @@
+/* devtree.c: Build a copy of the prom device tree in kernel
+ *            memory for easier access and cleaner interface.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Add more as appropriate. */
+enum bus_t {
+       OBIO_BUS,
+       SBUS_BUS,
+       PCI_BUS,
+       PMEM_BUS,
+       CPU_BUS,
+};
+
+struct sdevmapping {
+       unsigned long physpage;
+       int mapsz;
+       enum bus_t where;
+};
+
+/* limitation of sparc arch. */
+#define NUM_SPARC_IRQS    15
+
+struct sdev_irqs {
+       int level;
+       int vector; /* For vme/sbus irq sharing methinks. */
+};
+
+struct sparcdev {
+       struct sparcdev *next;
+       struct sparcdev *prev;
+       int node;
+       char *name;
+       int num_mappings;
+       struct sdevmapping *maps;
+       int num_irqs;
+       struct sdev_irqs irqinfo[NUM_SPARC_IRQS];
+};
+
+struct sparcbus {
+       struct sparcbus *next;
+       enum bus_t type;
+       struct sparcdev *device_list;
+};
+
+/* Add more as appropriate. */
+struct sparcbus obiobus_info = { 0, OBIO_BUS, { 0, 0}, };
+struct sparcbus sbusbus_info = { 0, SBUS_BUS, { 0, 0}, };
+struct sparcbus pcibus_info = { 0, PCI_BUS, { 0, 0}, };
+struct sparcbus pmembus_info = { 0, PMEM_BUS, { 0, 0}, };
+struct sparcbus cpubus_info = { 0, CPU_BUS, { 0, 0}, };
+
+struct sparcbus *sparcbus_list = 0;
+
+/* This is called at boot time to build the prom device tree. */
+int prom_build_devtree(unsigned long start_mem, unsigned long end_mem)
+{
+}
+
+/* Search the bus device list for a device which matches one of the
+ * names in NAME_VECTOR which is an array or NUM_NAMES strings, given
+ * the passed BUSTYPE.  Return ptr to the matching sparcdev structure
+ * or NULL if no matches found.
+ */
+struct sparcdev *prom_find_dev_on_bus(bus_t bustype, char **name_vector, int num_names)
+{
+       struct sparcdev *sdp;
+       struct sparcbus *thebus;
+       int niter;
+
+       if(!num_names)
+               return 0;
+
+       if(!sparcbus_list) {
+               prom_printf("prom_find_dev_on_bus: Device list not initted yet!\n");
+               prom_halt();
+       }
+
+       while(thebus = sparcbus_list; thebus; thebus = thebus->next)
+               if(thebus->type == bustype)
+                       break;
+       if(!thebus || !thebus->device_list)
+               return 0;
+
+       for(sdp = thebus->device_list; sdp; sdp = sdp->next) {
+               for(niter = 0; niter < num_names; niter++)
+                       if(!strcmp(sdp->name, name_vector[niter]))
+                               break;
+       }
+       return sdp;
+}
+
+/* Continue searching on a device list, starting at START_DEV for the next
+ * instance whose name matches one of the elements of NAME_VECTOR which is
+ * of length NUM_NAMES.
+ */
+struct sparcdev *prom_find_next_dev(struct sparcdev *start_dev, char **name_vector, int num_names)
+{
+       struct sparcdev *sdp;
+       int niter;
+
+       if(!start_dev->next || !num_names)
+               return 0;
+       for(sdp = start_dev->next; sdp; sdp = sdp->next) {
+               for(niter = 0; niter < num_names; niter++)
+                       if(!strcmp(sdp->name, name_vector[niter]))
+                               break;
+       }
+       return sdp;
+}
index b2d2223d1aafe66f5e3eab6499d00ee4fe70526d..efdfdb0ba83532c0fa8ab7013fe4e39ed90ab060 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.3 1995/11/25 01:00:04 davem Exp $
+/* $Id: misc.c,v 1.5 1996/02/02 03:37:44 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -29,13 +29,19 @@ prom_feval(char *fstring)
        return;
 }
 
+/* We want to do this more nicely some day. */
+extern void console_restore_palette(void);
+extern void set_palette(void);
+
 /* Drop into the prom, with the chance to continue with the 'go'
  * prom command.
  */
 void
 prom_halt(void)
 {
+        console_restore_palette ();
        (*(romvec->pv_abort))();
+       set_palette ();
        return;
 }
 
index 9e013f33b295962d01e12193e5a4f63dfa4064c3..a0665519fe4aa81d88ff299b24488ca259f0a0e5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.6 1995/11/25 01:00:16 davem Exp $
+/* $Id: tree.c,v 1.7 1996/01/01 02:46:24 davem Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
@@ -174,6 +174,19 @@ prom_nextprop(int node, char *oprop)
        return prom_nodeops->no_nextprop(node, oprop);
 }
 
+int
+prom_node_has_property(int node, char *prop)
+{
+       char *current_property = "";
+
+       do {
+               current_property = prom_nextprop(node, current_property);
+               if(!strcmp(current_property, prop))
+                  return 1;
+       } while (*current_property);
+       return 0;
+}
+
 /* Set property 'pname' at node 'node' to value 'value' which has a length
  * of 'size' bytes.  Return the number of bytes the prom accepted.
  */
index 4a14fff01127ae3605f6ac82ce2aa4f852ffcdce..aa68ef83fd0a002efda8367ccc38428395dcd97f 100644 (file)
@@ -4021,7 +4021,7 @@ extern char *get_options(char *str, int *ints);
 
 static void mod_setup(char *pattern, void (*setup)(char *, int *))
 {
-       int i;
+       unsigned long i;
        char c;
        int j;
        int match;
index 53078fa7fafb927d4370c62e919bfab03101bc74..946b59ec9c3e187ba3f7448b211bf327fc20399f 100644 (file)
@@ -357,8 +357,10 @@ static void make_request(int major,int rw, struct buffer_head * bh)
             || major == IDE3_MAJOR)
            && (req = blk_dev[major].current_request))
        {
-               if (major != SCSI_DISK_MAJOR && major != SCSI_CDROM_MAJOR)
-                       req = req->next;
+               if (major != SCSI_DISK_MAJOR &&
+                   major != SCSI_CDROM_MAJOR &&
+                   major != MD_MAJOR)
+                       req = req->next;
 
                while (req) {
                        if (req->rq_dev == bh->b_dev &&
index fdec8f5979c16ab071e20489e1f9a74f3f1656d9..59bddb4d8d54ec34e3774e86e98b65bdb9900e13 100644 (file)
 
 #include <linux/module.h>
 
-#include <linux/mm.h>
-#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
 #include <linux/errno.h>
-#include <asm/segment.h>
-#include "loop.h"
+#include <linux/major.h>
 
 #ifdef DES_AVAILABLE
 #include "des.h"
 #endif
+#include <linux/loop.h>                /* must follow des.h */
 
-#define DEFAULT_MAJOR_NR 10
-int loop_major = DEFAULT_MAJOR_NR;
-#define MAJOR_NR loop_major    /* not necessarily constant */
+#define MAJOR_NR LOOP_MAJOR
 
 #define DEVICE_NAME "loop"
 #define DEVICE_REQUEST do_lo_request
@@ -219,6 +213,7 @@ repeat:
                size = blksize - offset;
                if (size > len)
                        size = len;
+                          
                if ((lo->transfer)(lo, CURRENT->cmd, bh->b_data + offset,
                                   dest_addr, size)) {
                        printk("loop: transfer error block %d\n", block);
@@ -260,10 +255,12 @@ static int loop_set_fd(struct loop_device *lo, unsigned int arg)
                        lo->lo_device = inode->i_rdev;
                else
                        return -EINVAL;
+       invalidate_inode_pages (inode);
        lo->lo_inode = inode;
        lo->lo_inode->i_count++;
        lo->transfer = NULL;
        figure_loop_size(lo);
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -283,6 +280,7 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
        memset(lo->lo_name, 0, LO_NAME_SIZE);
        loop_sizes[lo->lo_number] = 0;
        invalidate_buffers(dev);
+       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -362,8 +360,8 @@ static int lo_ioctl(struct inode * inode, struct file * file,
 
        if (!inode)
                return -EINVAL;
-       if (MAJOR(inode->i_rdev) != loop_major) {
-               printk("lo_ioctl: pseudo-major != %d\n", loop_major);
+       if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+               printk("lo_ioctl: pseudo-major != %d\n", MAJOR_NR);
                return -ENODEV;
        }
        dev = MINOR(inode->i_rdev);
@@ -401,8 +399,8 @@ static int lo_open(struct inode *inode, struct file *file)
 
        if (!inode)
                return -EINVAL;
-       if (MAJOR(inode->i_rdev) != loop_major) {
-               printk("lo_open: pseudo-major != %d\n", loop_major);
+       if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+               printk("lo_open: pseudo-major != %d\n", MAJOR_NR);
                return -ENODEV;
        }
        dev = MINOR(inode->i_rdev);
@@ -421,14 +419,14 @@ static void lo_release(struct inode *inode, struct file *file)
 
        if (!inode)
                return;
-       if (MAJOR(inode->i_rdev) != loop_major) {
-               printk("lo_release: pseudo-major != %d\n", loop_major);
+       if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+               printk("lo_release: pseudo-major != %d\n", MAJOR_NR);
                return;
        }
        dev = MINOR(inode->i_rdev);
        if (dev >= MAX_LOOP)
                return;
-       sync_dev(inode->i_rdev);
+       fsync_dev(inode->i_rdev);
        lo = &loop_dev[dev];
        if (lo->lo_refcnt <= 0)
                printk("lo_release: refcount(%d) <= 0\n", lo->lo_refcnt);
@@ -461,26 +459,24 @@ static struct file_operations lo_fops = {
 
 int
 loop_init( void ) {
-       int     i = (loop_major ? loop_major : DEFAULT_MAJOR_NR);
+       int     i;
 
-       if (register_blkdev(i, "loop", &lo_fops) &&
-           (i = register_blkdev(0, "loop", &lo_fops)) <= 0) {
-               printk("Unable to get major number for loop device\n");
+       if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
+               printk("Unable to get major number %d for loop device\n",
+                      MAJOR_NR);
                return -EIO;
        }
-       loop_major = i;
-#ifdef MODULE
-       if (i != DEFAULT_MAJOR_NR)
+#ifndef MODULE
+       printk("loop: registered device at major %d\n", MAJOR_NR);
 #endif
-         printk("loop: registered device at major %d\n",loop_major);
 
-       blk_dev[loop_major].request_fn = DEVICE_REQUEST;
+       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
        for (i=0; i < MAX_LOOP; i++) {
                memset(&loop_dev[i], 0, sizeof(struct loop_device));
                loop_dev[i].lo_number = i;
        }
        memset(&loop_sizes, 0, sizeof(loop_sizes));
-       blk_size[loop_major] = loop_sizes;
+       blk_size[MAJOR_NR] = loop_sizes;
 
        return 0;
 }
@@ -488,7 +484,7 @@ loop_init( void ) {
 #ifdef MODULE
 void
 cleanup_module( void ) {
-  if (unregister_blkdev(loop_major, "loop") != 0)
+  if (unregister_blkdev(MAJOR_NR, "loop") != 0)
     printk("loop: cleanup_module failed\n");
 }
 #endif
diff --git a/drivers/block/loop.h b/drivers/block/loop.h
deleted file mode 100644 (file)
index 3724bb0..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef _LINUX_LOOP_H
-#define _LINUX_LOOP_H
-
-/*
- * include/linux/loop.h
- *
- * Written by Theodore Ts'o, 3/29/93.
- *
- * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
- * permitted under the GNU Public License.
- */
-
-#define LO_NAME_SIZE   64
-#define LO_KEY_SIZE    32
-       
-struct loop_device {
-       int             lo_number;
-       struct inode    *lo_inode;
-       int             lo_refcnt;
-       kdev_t          lo_device;
-       int             lo_offset;
-       int             lo_encrypt_type;
-       int             lo_encrypt_key_size;
-       int             lo_flags;
-       int             (*transfer)(struct loop_device *, int cmd,
-                                   char *raw_buf, char *loop_buf, int size);
-       char            lo_name[LO_NAME_SIZE];
-       char            lo_encrypt_key[LO_KEY_SIZE];
-#ifdef DES_AVAILABLE
-       des_key_schedule lo_des_key;
-       unsigned long   lo_des_init[2];
-#endif
-};
-
-typedef        int (* transfer_proc_t)(struct loop_device *, int cmd,
-                               char *raw_buf, char *loop_buf, int size);
-
-/*
- * Loop flags
- */
-#define LO_FLAGS_DO_BMAP       0x00000001
-
-struct loop_info {
-       int             lo_number;      /* ioctl r/o */
-       dev_t           lo_device;      /* ioctl r/o */
-       unsigned long   lo_inode;       /* ioctl r/o */
-       dev_t           lo_rdevice;     /* ioctl r/o */
-       int             lo_offset;
-       int             lo_encrypt_type;
-       int             lo_encrypt_key_size;    /* ioctl w/o */
-       int             lo_flags;       /* ioctl r/o */
-       char            lo_name[LO_NAME_SIZE];
-       unsigned char   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
-       unsigned long   lo_init[2];
-       char            reserved[4];
-};
-
-/*
- * Loop encryption types --- LO_CRYPT_IDEA isn't supported yet
- */
-
-#define LO_CRYPT_NONE  0
-#define LO_CRYPT_XOR   1
-#define LO_CRYPT_DES   2
-#define LO_CRYPT_IDEA  3
-#define MAX_LO_CRYPT   4
-
-/*
- * IOCTL commands --- we will commandeer 0x4C ('L')
- */
-
-#define LOOP_SET_FD    0x4C00
-#define LOOP_CLR_FD    0x4C01
-#define LOOP_SET_STATUS        0x4C02
-#define LOOP_GET_STATUS        0x4C03
-
-#endif
index 1285ffa3a3bd369e418a026d506eaccc89f3709d..78931f15b2b812ffba15342a505a7380ba541b0e 100644 (file)
@@ -175,7 +175,7 @@ static int md_ioctl (struct inode *inode, struct file *file,
        paging). This is NOT done by fdisk when partitionning,
        but that's a DOS thing anyway... */
     
-    devices[minor][index].size=gen_real->sizes[MINOR(dev)] & (PAGE_MASK>>10);
+    devices[minor][index].size=gen_real->sizes[MINOR(dev)] & ~((PAGE_SIZE >> 10)-1);
     devices[minor][index].offset=index ?
       (devices[minor][index-1].offset + devices[minor][index-1].size) : 0;
 
@@ -461,10 +461,12 @@ void make_md_request (struct request *pending, int n)
         || major == IDE3_MAJOR)
        && (req = blk_dev[major].current_request))
     {
-#ifdef CONFIG_BLK_DEV_HD
-      if (major == HD_MAJOR)
+      /*
+       * Thanx to Gadi Oxman <gadio@netvision.net.il>
+       * (He reads my own code better than I do... ;-)
+       */
+      if (major != SCSI_DISK_MAJOR)
        req = req->next;
-#endif CONFIG_BLK_DEV_HD
 
       while (req && !found)
       {
index 8f4c1e5d9afb5f8c0aba30bb4c482ece0f27b16c..6561f9722c95f90c1d0e3274ce8f66aea9eb8e30 100644 (file)
@@ -479,7 +479,7 @@ int read_sector(int start)
    4 c_stop waits for receive_buffer_full: 0xff
 */
 
-void cm206_bh(void * unused)
+void cm206_bh(void)
 {
   debug(("bh: %d\n", cd->background));
   switch (cd->background) {
@@ -1169,8 +1169,7 @@ int cm206_init(void)
   }
   blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
   read_ahead[MAJOR_NR] = 16;   /* reads ahead what? */
-  bh_base[CM206_BH].routine = cm206_bh;
-  enable_bh(CM206_BH);
+  init_bh(CM206_BH, cm206_bh);
 
   memset(cd, 0, sizeof(*cd));  /* give'm some reasonable value */
   cd->sector_last = -1;                /* flag no data buffered */
index c829640e4223dc231d61ea27a7aafae65ceae870..bcef41431231317ad39c48b377ba24c9d25f475e 100644 (file)
@@ -90,6 +90,7 @@
 #if 0
 static int mcd_sizes[] = { 0 };
 #endif
+static int mcd_blocksizes[1] = { 0, };
 
 /* I know putting defines in this file is probably stupid, but it should be */
 /* the only place that they are really needed... I HOPE! :) */
@@ -1184,7 +1185,8 @@ int mcd_init(void)
                 mcd_port);
           return -EIO;
        }
-         
+
+       blksize_size[MAJOR_NR] = mcd_blocksizes;
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
        read_ahead[MAJOR_NR] = 4;
 
@@ -1253,7 +1255,7 @@ int mcd_init(void)
 
        mcd_invalidate_buffers();
        mcdPresent = 1;
-        return 0;
+       return 0;
 }
 
 
index 6c6726490eb9e69cf78648962dfd30387d6ba1fc..d4a5d2bfb8f8b1370bc0be10d902f02575fbdb9f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * The Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.5a
+ * VERSION: 1.7
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
  *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
+ *  Andreas Kies (testing the mysterious hang up's)
  *  ... somebody forgotten?
  *  
  */
 
 #if RCS
 static const char *mcdx_c_version
-               = "mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp";
+               = "mcdx.c,v 1.31 1996/03/02 00:21:18 heiko Exp";
 #endif
 
 #include <linux/version.h>
 #include <linux/module.h>
 
 #include <linux/errno.h>
-#include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/fs.h>
@@ -77,14 +77,13 @@ enum drivemodes { TOC, DATA, RAW, COOKED };
 enum datamodes { MODE0, MODE1, MODE2 };
 enum resetmodes { SOFT, HARD };
 
-const int SINGLE = 0x01;
-const int DOUBLE = 0x02;
-const int DOOR   = 0x04;
-const int MULTI  = 0x08;
-const int READY  = 0x70;
+const int SINGLE = 0x01;               /* single speed drive (FX001S, LU) */
+const int DOUBLE = 0x02;               /* double speed drive (FX001D, ..? */
+const int DOOR   = 0x04;               /* door locking capability */
+const int MULTI  = 0x08;               /* multi session capability */
 
-const unsigned char READSSPEED = 0xc0;
-const unsigned char READDSPEED = 0xc1;
+const unsigned char READ1X = 0xc0;
+const unsigned char READ2X = 0xc1;
 
 
 /* DECLARATIONS ****************************************************/ 
@@ -161,14 +160,15 @@ struct s_drive_stuff {
     int irq;                   /* irq used by this drive */
     int minor;                 /* minor number of this drive */
     int present;           /* drive present and its capabilities */
-    char readcmd;              /* read cmd depends on single/double speed */
-    char playcmd;       /* play should always be single speed */
-    unsigned long changed;     /* last jiff the media was changed */
-    unsigned long xxx;      /* last jiff it was asked for media change */
+    unsigned char readcmd;     /* read cmd depends on single/double speed */
+    unsigned char playcmd;  /* play should always be single speed */
+    unsigned int xxx;      /* set if changed, reset while open */
+    unsigned int yyy;      /* set if changed, reset by media_changed */
     unsigned long ejected;  /* time we called the eject function */
     int users;                         /* keeps track of open/close */
     int lastsector;                    /* last block accessible */
-    int errno;                         /* last operation's error */
+    int status;                                /* last operation's error / status */
+       int readerrs;                   /* # of blocks read w/o error */
 };
 
 
@@ -211,6 +211,7 @@ static char *port(int*);
 static int irq(int*);
 static void mcdx_delay(struct s_drive_stuff*, long jifs);
 static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
+static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
 
 static int mcdx_config(struct s_drive_stuff*, int);
 static int mcdx_closedoor(struct s_drive_stuff*, int);
@@ -238,6 +239,7 @@ static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int
 
 /* static variables ************************************************/
 
+static int mcdx_blocksizes[MCDX_NDRIVES];
 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
 static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
 static struct s_drive_stuff* mcdx_irq_map[16] =
@@ -468,7 +470,7 @@ mcdx_ioctl(
                                ms.addr.lba = msf2log(&stuffp->multi.msf_last);
                        else
                                return -EINVAL;
-                       ms.xa_flag = stuffp->xa;
+                       ms.xa_flag = !!stuffp->multi.multi;
 
                        if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg,
                                        sizeof(struct cdrom_multisession))))
@@ -571,7 +573,7 @@ void do_mcdx_request()
          break;
 
       case READ:
-         stuffp->errno = 0;
+         stuffp->status = 0;
          while (CURRENT->nr_sectors) {
              int i;
 
@@ -580,12 +582,13 @@ void do_mcdx_request()
                                      CURRENT->buffer,
                                      CURRENT->sector,
                                      CURRENT->nr_sectors))) {
-              WARN(("do_request() read error\n"));
-              if (stuffp->errno == MCDX_EOM) {
+              INFO(("do_request() read error\n"));
+              if (stuffp->status & MCDX_ST_EOM) {
                   CURRENT->sector += CURRENT->nr_sectors;
                   CURRENT->nr_sectors = 0;
-              }
+              } 
               end_request(0);
+                         /* return; */
               goto again;
              }
              CURRENT->sector += i;
@@ -627,38 +630,36 @@ mcdx_open(struct inode *ip, struct file *fp)
        if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
         if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) return -EIO;
         if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
-        else return -EIO;
+               else return -EIO;
     }
 
        /* if the media changed we will have to do a little more */
-       if (stuffp->xxx < stuffp->changed) {
+       if (stuffp->xxx) {
 
                TRACE((OPENCLOSE, "open() media changed\n"));
         /* but wait - the time of media change will be set at the 
-        very last of this block - it seems, some of the following
-        talk() will detect a media change ... (I think, config()
-        is the reason. */
+           very last of this block - it seems, some of the following
+           talk() will detect a media change ... (I think, config()
+           is the reason. */
 
         stuffp->audiostatus = CDROM_AUDIO_INVALID;
 
                /* get the multisession information */
-               {
-            int ans;
-
-                       TRACE((OPENCLOSE, "open() Request multisession info\n"));
-            ans = mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6);
-            if (ans == -1) {
-                stuffp->autoclose = 0;
-                mcdx_eject(stuffp, 1);
-                return -EIO;
-            }
-
-            /* we succeeded, so on next open(2) we could try auto close
-            again */
-            stuffp->autoclose = 1;
+               TRACE((OPENCLOSE, "open() Request multisession info\n"));
+               if (-1 == mcdx_requestmultidiskinfo(
+                               stuffp, &stuffp->multi, 6)) {
+                       INFO(("No multidiskinfo\n"));
+                       stuffp->autoclose = 0;
+               } else {
+                       /* we succeeded, so on next open(2) we could try auto close
+                       again */
+                       stuffp->autoclose = 1;
                
+#if !MCDX_QUIET
                        if (stuffp->multi.multi > 2)
-                               WARN(("open() unknown multisession value (%d)\n", stuffp->multi.multi));
+                               INFO(("open() unknown multisession value (%d)\n", 
+                                               stuffp->multi.multi));
+#endif
 
                        /* multisession ? */
                        if (!stuffp->multi.multi)
@@ -669,38 +670,54 @@ mcdx_open(struct inode *ip, struct file *fp)
                                        stuffp->multi.msf_last.minute,
                                        stuffp->multi.msf_last.second,
                                        stuffp->multi.msf_last.frame));
+
                } /* got multisession information */
 
                /* request the disks table of contents (aka diskinfo) */
-               if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) return -EIO;
-
-               stuffp->lastsector = (CD_FRAMESIZE / 512) 
-                * msf2log(&stuffp->di.msf_leadout) - 1;
-
-               TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
-                               stuffp->di.n_first,
-                               stuffp->di.msf_first.minute,
-                               stuffp->di.msf_first.second,
-                               stuffp->di.msf_first.frame,
-                               msf2log(&stuffp->di.msf_first)));
-               TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
-                               stuffp->di.n_last,
-                               stuffp->di.msf_leadout.minute,
-                               stuffp->di.msf_leadout.second,
-                               stuffp->di.msf_leadout.frame,
-                               msf2log(&stuffp->di.msf_leadout)));
+               if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
+
+                       stuffp->lastsector = -1;
+
+               } else {
+
+                       stuffp->lastsector = (CD_FRAMESIZE / 512) 
+                                       * msf2log(&stuffp->di.msf_leadout) - 1;
+
+                       TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
+                                       stuffp->di.n_first,
+                                       stuffp->di.msf_first.minute,
+                                       stuffp->di.msf_first.second,
+                                       stuffp->di.msf_first.frame,
+                                       msf2log(&stuffp->di.msf_first)));
+                       TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
+                                       stuffp->di.n_last,
+                                       stuffp->di.msf_leadout.minute,
+                                       stuffp->di.msf_leadout.second,
+                                       stuffp->di.msf_leadout.frame,
+                                       msf2log(&stuffp->di.msf_leadout)));
+               }
 
                if (stuffp->toc) {
-                       TRACE((MALLOC, "open() free toc @ %p\n", stuffp->toc));
+                       TRACE((MALLOC, "open() free old toc @ %p\n", stuffp->toc));
                        kfree(stuffp->toc);
+               
+                       stuffp->toc = NULL;
                }
-               stuffp->toc = NULL;
 
                TRACE((OPENCLOSE, "open() init irq generation\n"));
                if (-1 == mcdx_config(stuffp, 1)) return -EIO;
 
-               /* try to get the first sector ... */
-               {
+#if FALLBACK
+               /* Set the read speed */
+               WARN(("AAA %x AAA\n", stuffp->readcmd));
+               if (stuffp->readerrs) stuffp->readcmd = READ1X;
+               else stuffp->readcmd = 
+                               stuffp->present | SINGLE ? READ1X : READ2X;
+               WARN(("XXX %x XXX\n", stuffp->readcmd));
+#endif
+
+               /* try to get the first sector, iff any ... */
+               if (stuffp->lastsector >= 0) {
                        char buf[512];
                        int ans;
                        int tries;
@@ -709,13 +726,19 @@ mcdx_open(struct inode *ip, struct file *fp)
                        stuffp->audio = 0;
 
                        for (tries = 6; tries; tries--) {
+
+                               stuffp->introk = 1;
+
                                TRACE((OPENCLOSE, "open() try as %s\n",
                                        stuffp->xa ? "XA" : "normal"));
 
                                /* set data mode */
                                if (-1 == (ans = mcdx_setdatamode(stuffp, 
-                                               stuffp->xa ? MODE2 : MODE1, 1)))
-                                       return -EIO;
+                                               stuffp->xa ? MODE2 : MODE1, 1))) {
+                                       /* return -EIO; */
+                                       stuffp->xa = 0;
+                                       break;
+                               }
 
                                if ((stuffp->audio = e_audio(ans))) break; 
 
@@ -725,7 +748,7 @@ mcdx_open(struct inode *ip, struct file *fp)
                                if (ans == 1) break;
                                stuffp->xa = !stuffp->xa; 
                        }
-                       if (!tries) return -EIO;
+                       /* if (!tries) return -EIO; */
                }
 
                /* xa disks will be read in raw mode, others not */
@@ -735,13 +758,13 @@ mcdx_open(struct inode *ip, struct file *fp)
 
                if (stuffp->audio) {
                        INFO(("open() audio disk found\n"));
-               } else {
+               } else if (stuffp->lastsector >= 0) {
                        INFO(("open() %s%s disk found\n",
                                        stuffp->xa ? "XA / " : "",
                                        stuffp->multi.multi ? "Multi Session" : "Single Session"));
-               }
+               } 
 
-        stuffp->xxx = jiffies;
+        stuffp->xxx = 0;
        }
 
     /* lock the door if not already done */
@@ -768,9 +791,12 @@ mcdx_close(struct inode *ip, struct file *fp)
                /* invalidate_inodes(ip->i_rdev); */
                invalidate_buffers(ip->i_rdev);
 
+
 #if !MCDX_QUIET
                if (-1 == mcdx_lockdoor(stuffp, 0, 3))
                                INFO(("close() Cannot unlock the door\n"));
+#else
+               mcdx_lockdoor(stuffp, 0, 3);
 #endif
 
         /* eject if wished */
@@ -783,15 +809,25 @@ mcdx_close(struct inode *ip, struct file *fp)
 }
 
 int check_mcdx_media_change(kdev_t full_dev)
-/*     Return: 1 if media changed since last call to 
-                         this function
-                       0 else
-       Setting flag to 0 resets the changed state. */
-
+/*     Return: 1 if media changed since last call to this function
+                       0 otherwise */
 {
+    struct s_drive_stuff *stuffp; 
+
     INFO(("check_mcdx_media_change called for device %s\n",
          kdevname(full_dev)));
-    return 0;
+
+       stuffp = mcdx_stuffp[MINOR(full_dev)];
+       mcdx_getstatus(stuffp, 1);
+
+       if (stuffp->yyy == 0) {
+               INFO((" ... not changed\n"));
+               return 0;
+       }
+
+       INFO((" ... changed\n"));
+       stuffp->yyy = 0;
+       return 1;
 }
 
 void mcdx_setup(char *str, int *pi)
@@ -803,22 +839,15 @@ void mcdx_setup(char *str, int *pi)
 /* DIRTY PART ******************************************************/ 
 
 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
-/*     This routine is used for sleeping while initialisation - it seems that
-       there are no other means available. May be we could use a simple count
-       loop w/ jumps to itself, but I wanna make this independend of cpu
-       speed. [1 jiffie is 1/HZ sec */
+/*     This routine is used for sleeping.
+       May be we could use a simple count loop w/ jumps to itself, but 
+       I wanna make this independend of cpu speed. [1 jiffie is 1/HZ] sec */
 {
     unsigned long tout = jiffies + jifs;
 
-    TRACE((INIT, "mcdx_delay %d\n", jifs));
-    if (jifs < 0) return;
+    /* TRACE((INIT, "mcdx_delay %d\n", jifs)); */
+    if (jifs <= 0) return;
 
-#if 1
-    while (jiffies < tout) {
-        current->timeout = jiffies;
-        schedule();
-    }
-#else
     if (current->pid == 0) {        /* no sleep allowed */
                while (jiffies < tout) {
             current->timeout = jiffies;
@@ -826,37 +855,50 @@ static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
         }
     } else {                        /* sleeping is allowed */
         current->timeout = tout;
-        current->state = TASK_INTERRUPTIBLE;
+        /* current->state = TASK_INTERRUPTIBLE; */
+               /* And perhaps we should remove the while() { ... } */
         while (current->timeout) {
             interruptible_sleep_on(&stuff->sleepq);
+                       TRACE((SLEEP, "delay: to is %d\n", current->timeout));
         }
     }
-#endif
 }
 
 static void 
 mcdx_intr(int irq, void *dev_id, struct pt_regs* regs)
 {
     struct s_drive_stuff *stuffp;
-       unsigned char x;
+       unsigned char b;
 
     stuffp = mcdx_irq_map[irq];
 
-    if (stuffp == NULL || !stuffp->busy) {
-               TRACE((IRQ, "intr() unexpected interrupt @ irq %d\n", irq));
+    if (stuffp == NULL ) {
+               WARN(("mcdx: no device for intr %d\n", irq));
                return;
     }
 
-       /* if not ok read the next byte as the drives status */
-       if (0 == (stuffp->introk = 
-                       (~(x = inb((unsigned int) stuffp->rreg_status)) & MCDX_RBIT_DTEN))) 
-               TRACE((IRQ, "intr() irq %d failed, status %02x %02x\n",
-                               irq, x, inb((unsigned int) stuffp->rreg_data)));
-       else
-         {
-           TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, x));
+       /* get the interrupt status */
+       b = inb((unsigned int) stuffp->rreg_status);
+       stuffp->introk = ~b & MCDX_RBIT_DTEN;
+
+       /* NOTE: We only should get interrupts if data were requested.
+          But the drive seems to generate ``asynchronous'' interrupts
+          on several error conditions too.  (Despite the err int enable
+          setting during initialisation) */
+
+       /* if not ok, read the next byte as the drives status */
+       if (!stuffp->introk) {
+               TRACE((IRQ, "intr() irq %d hw status 0x%02x\n", irq, b));
+               if (~b & MCDX_RBIT_STEN) {
+                       INFO((  "intr() irq %d    status 0x%02x\n", 
+                                       irq, inb((unsigned int) stuffp->rreg_data)));
+               } else {
+                       INFO((  "intr() irq %d ambigous hw status\n", irq));
+               }
+       } else {
+               TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, b));
+    }
 
-         }
     stuffp->busy = 0;
     wake_up_interruptible(&stuffp->busyq);
 }
@@ -881,13 +923,11 @@ mcdx_talk (
 
     if ((disgard = (buffer == NULL))) buffer = &c;
 
-    while (stuffp->lock)
-               interruptible_sleep_on(&stuffp->lockq);
-
-    if (current->signal && ~current->blocked) {
-        WARN(("talk() got signal %d\n", current->signal));
-        return -1;
-    }
+    while (stuffp->lock) {
+               interruptible_sleep_on(&stuffp->lockq); 
+               TRACE((SLEEP, "talk: lock = %d\n",
+                               stuffp->lock));
+       }
 
     stuffp->lock = 1;
     stuffp->valid = 0; 
@@ -906,8 +946,8 @@ mcdx_talk (
      *  st != -1 (good) */
        for (st = -1; st == -1 && tries; tries--) {
 
-        size_t sz = size;
-        char* bp = buffer;
+               char *bp = (char*) buffer;
+               size_t sz = size;
 
                outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
         TRACE((TALK, "talk() command sent\n"));
@@ -930,7 +970,7 @@ mcdx_talk (
                     cmd[0], cmdlen > 1 ? "..." : ""));
             st = -1;
             continue;
-        }
+               }
 
         /* audio status? */
         if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
@@ -943,7 +983,7 @@ mcdx_talk (
         /* media change? */
         if (e_changed(st)) {
             INFO(("talk() media changed\n"));
-            stuffp->changed = jiffies;
+            stuffp->xxx = stuffp->yyy = 1;
         }
 
         /* now actually get the data */
@@ -958,7 +998,9 @@ mcdx_talk (
         }
     }
 
-    if (!tries && st == -1) WARN(("talk() giving up\n"));
+#if !MCDX_QUIET
+    if (!tries && st == -1) INFO(("talk() giving up\n"));
+#endif
 
     stuffp->lock = 0;
     wake_up_interruptible(&stuffp->lockq);
@@ -995,7 +1037,7 @@ void cleanup_module(void)
 {
     int i;
 
-       WARN(("cleanup_module called\n"));
+       INFO(("cleanup_module called\n"));
        
     for (i = 0; i < MCDX_NDRIVES; i++) {
                struct s_drive_stuff *stuffp;
@@ -1012,9 +1054,12 @@ void cleanup_module(void)
                kfree(stuffp);
     }
 
-    if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) 
+    if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) {
         WARN(("cleanup() unregister_blkdev() failed\n"));
-    else INFO(("cleanup() succeeded\n"));
+    } 
+#if !MCDX_QUIET
+       else INFO(("cleanup() succeeded\n"));
+#endif
 }
 
 #endif MODULE
@@ -1046,15 +1091,12 @@ void warn(const char* fmt, ...)
        va_end(args);
 }
 
-
 int mcdx_init(void)
 {
        int drive;
 
-       WARN(("Version 1.5a "
-                       "mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n"));
-       INFO((": Version 1.5a "
-                       "mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n"));
+       WARN(("Version 1.7 for %s\n", kernel_version));
+       WARN(("mcdx.c,v 1.31 1996/03/02 00:21:18 heiko Exp\n"));
 
        /* zero the pointer array */
        for (drive = 0; drive < MCDX_NDRIVES; drive++)
@@ -1066,6 +1108,8 @@ int mcdx_init(void)
                struct s_drive_stuff* stuffp;
         int size;
 
+               mcdx_blocksizes[drive] = 0;
+
         size = sizeof(*stuffp);
                
                TRACE((INIT, "init() try drive %d\n", drive));
@@ -1085,7 +1129,6 @@ int mcdx_init(void)
 
                stuffp->present = 0;            /* this should be 0 already */
                stuffp->toc = NULL;                     /* this should be NULL already */
-               stuffp->changed = jiffies;
 
                /* setup our irq and i/o addresses */
                stuffp->irq = irq(mcdx_drive_map[drive]);
@@ -1096,9 +1139,8 @@ int mcdx_init(void)
 
                /* check if i/o addresses are available */
                if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
-            WARN(("%s=0x%3p,%d: "
-                    "Init failed. I/O ports (0x%3p..0x3p) already in use.\n"
-                    MCDX, 
+            WARN(("0x%3p,%d: "
+                    "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n",
                     stuffp->wreg_data, stuffp->irq,
                     stuffp->wreg_data, 
                     stuffp->wreg_data + MCDX_IO_SIZE - 1));
@@ -1127,22 +1169,22 @@ int mcdx_init(void)
 
                switch (version.code) {
                case 'D': 
-                stuffp->readcmd = READDSPEED
+                stuffp->readcmd = READ2X
                 stuffp->present = DOUBLE | DOOR | MULTI; 
                 break;
                case 'F': 
-                stuffp->readcmd = READSSPEED
+                stuffp->readcmd = READ1X
                 stuffp->present = SINGLE | DOOR | MULTI;
                 break;
                case 'M': 
-                stuffp->readcmd = READSSPEED;
+                stuffp->readcmd = READ1X;
                 stuffp->present = SINGLE;
                 break;
                default: 
                 stuffp->present = 0; break;
                }
 
-        stuffp->playcmd = READSSPEED;
+        stuffp->playcmd = READ1X;
 
 
                if (!stuffp->present) {
@@ -1164,9 +1206,7 @@ int mcdx_init(void)
                blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
                read_ahead[MAJOR_NR] = READ_AHEAD;
 
-#if WE_KNOW_WHY
-                blksize_size[MAJOR_NR] = BLKSIZES;
-#endif
+               blksize_size[MAJOR_NR] = mcdx_blocksizes;
 
                TRACE((INIT, "init() subscribe irq and i/o\n"));
                mcdx_irq_map[stuffp->irq] = stuffp;
@@ -1210,8 +1250,38 @@ int mcdx_init(void)
        return 0;
 }
 
+static int 
+mcdx_transfer(struct s_drive_stuff *stuffp,
+               char *p, int sector, int nr_sectors)
+/*     This seems to do the actually transfer.  But it does more.  It
+       keeps track of errors ocurred and will (if possible) fall back
+       to single speed on error. 
+       Return: -1 on timeout or other error
+                       else status byte (as in stuff->st) */
+{
+       int ans;
+
+       ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
+       return ans;
+#if FALLBACK
+       if (-1 == ans) stuffp->readerrs++;
+       else return ans;
 
-static int mcdx_transfer(struct s_drive_stuff *stuffp,
+       if (stuffp->readerrs && stuffp->readcmd == READ1X) {
+               WARN(("XXX Alrady reading 1x -- no chance\n"));
+               return -1;
+       }
+
+       WARN(("XXX Fallback to 1x\n"));
+
+       stuffp->readcmd = READ1X;
+       return mcdx_transfer(stuffp, p, sector, nr_sectors);
+#endif
+       
+}
+
+
+static int mcdx_xfer(struct s_drive_stuff *stuffp,
                char *p, int sector, int nr_sectors)
 /*     This does actually the transfer from the drive.
        Return: -1 on timeout or other error
@@ -1228,11 +1298,11 @@ static int mcdx_transfer(struct s_drive_stuff *stuffp,
                return -1;
        }
 
-    while (stuffp->lock)
+    while (stuffp->lock) {
                interruptible_sleep_on(&stuffp->lockq);
-    if (current->signal && ~current->blocked) {
-        WARN(("talk() got signal %d\n", current->signal));
-    }
+               TRACE((SLEEP, "xfer: lock = %d\n",
+                       stuffp->lock));
+       }
 
     if (stuffp->valid
                        && (sector >= stuffp->pending)
@@ -1245,29 +1315,32 @@ static int mcdx_transfer(struct s_drive_stuff *stuffp,
        stuffp->lock = current->pid;
 
        do {
-           /* int sig = 0; */
-           int to = 0;
+               /* wait for the drive become idle, but first
+                  check for possible occured errors --- the drive
+                  seems to report them asynchronously */
 
-               /* wait for the drive become idle */
-           current->timeout = jiffies + 5*HZ;
-           while (stuffp->busy) {
+           current->timeout = jiffies + 5 * HZ;
+           while (stuffp->introk && stuffp->busy && current->timeout) {
                        interruptible_sleep_on(&stuffp->busyq);
+                       TRACE((SLEEP, "request: busy = %d, timeout = %d\n",
+                               stuffp->busy, current->timeout));
                }
 
-           current->timeout = 0;
-
                /* test for possible errors */
-           if (((stuffp->busy == 0) && !stuffp->introk)
-                               || to) {
-                       if ((stuffp->busy == 0) && !stuffp->introk)
-                WARN(("mcdx_transfer() failure in data request\n"));
-                       else if (to)
-                WARN(("mcdx_transfer(): timeout\n"));
+               if (current->timeout == 0 || !stuffp->introk) {
+                       if (current->timeout == 0)  {
+                               WARN(("mcdx_transfer() timeout\n"));
+                       } else if (!stuffp->introk) { 
+                               WARN(("mcdx_transfer() error via irq reported\n"));
+                       } else {
+                               WARN(("mcdx_transfer() unknown failure in data request\n"));
+                       }
+
                        stuffp->lock = 0;
                        stuffp->busy = 0;
+                       stuffp->valid = 0;
+
                        wake_up_interruptible(&stuffp->lockq);
-                       wake_up_interruptible(&stuffp->busyq);
-                       stuffp->errno = MCDX_E;
                        TRACE((TRANSFER, "transfer() done (-1)\n"));
                        return -1;
            }
@@ -1301,8 +1374,7 @@ static int mcdx_transfer(struct s_drive_stuff *stuffp,
                        done++;
                        sector++;
            }
-       }
-       while (++(stuffp->pending) < off);
+       } while (++(stuffp->pending) < off);
 
        stuffp->lock = 0;
        wake_up_interruptible(&stuffp->lockq);
@@ -1325,7 +1397,8 @@ static int mcdx_transfer(struct s_drive_stuff *stuffp,
                if (stuffp->pending > stuffp->lastsector) {
                        WARN(("transfer() sector %d from nirvana requested.\n",
                                stuffp->pending));
-                       stuffp->errno = MCDX_EOM;
+                       stuffp->status = MCDX_ST_EOM;
+                       stuffp->valid = 0;
                        TRACE((TRANSFER, "transfer() done (-1)\n"));
                        return -1;
                }
@@ -1507,7 +1580,7 @@ mcdx_playmsf(struct s_drive_stuff* stuffp, const struct cdrom_msf* msf)
 
     outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
 
-    if (-1 == mcdx_getval(stuffp, 3*HZ, 0, NULL)) {
+    if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
         WARN(("playmsf() timeout\n")); 
         return -1;
     }
@@ -1550,25 +1623,25 @@ static int
 mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
 {
        if (stuffp->present & DOOR)
-               return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5*HZ, tries);
+               return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, tries);
        else
                return 0;
 }
 
 static int 
 mcdx_stop(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2*HZ, tries); }
+{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); }
 
 static int
 mcdx_hold(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2*HZ, tries); }
+{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); }
 
 static int
 mcdx_eject(struct s_drive_stuff *stuffp, int tries)
 {
        if (stuffp->present & DOOR) {
         stuffp->ejected = jiffies;
-               return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5*HZ, tries);
+               return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, tries);
     } else return 0;
 }
 
@@ -1582,7 +1655,7 @@ mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
 
        if (-1 == (ans = mcdx_talk(
             stuffp, "\x20", 1, buf, sizeof(buf),
-            2*HZ, tries))) 
+            2 * HZ, tries))) 
         return -1;
        sub->control = buf[1];
        sub->tno = buf[2];
@@ -1604,8 +1677,8 @@ mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, i
        int ans;
 
     if (stuffp->present & MULTI) {
-        ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2*HZ, tries);
-        multi->multi = buf[1];
+               ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 1 * HZ, tries);
+               multi->multi = buf[1];
         multi->msf_last.minute = buf[2];
         multi->msf_last.second = buf[3];
         multi->msf_last.frame = buf[4];
@@ -1621,15 +1694,20 @@ mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int t
 {
        char buf[9];
        int ans;
-       ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2*HZ, tries);
-       info->n_first = bcd2uint(buf[1]);
-       info->n_last = bcd2uint(buf[2]);
-       info->msf_leadout.minute = buf[3];
-       info->msf_leadout.second = buf[4];
-       info->msf_leadout.frame = buf[5];
-       info->msf_first.minute = buf[6];
-       info->msf_first.second = buf[7];
-       info->msf_first.frame = buf[8];
+       ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 1 * HZ, tries);
+       if (ans == -1) {
+               info->n_first = 0;
+               info->n_last = 0;
+       } else {
+               info->n_first = bcd2uint(buf[1]);
+               info->n_last = bcd2uint(buf[2]);
+               info->msf_leadout.minute = buf[3];
+               info->msf_leadout.second = buf[4];
+               info->msf_leadout.frame = buf[5];
+               info->msf_first.minute = buf[6];
+               info->msf_first.second = buf[7];
+               info->msf_first.frame = buf[8];
+       }
        return ans;
 }
 
@@ -1641,7 +1719,7 @@ mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
 
        TRACE((HW, "setdrivemode() %d\n", mode));
 
-       if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5*HZ, tries)))
+       if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
                return -1;
 
        switch (mode) {
@@ -1652,10 +1730,9 @@ mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
          default: break;
        }
        cmd[0] = 0x50;
-       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
+       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
 }
 
-
 static int
 mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
 {
@@ -1667,7 +1744,7 @@ mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
          case MODE2: cmd[1] = 0x02; break;
          default: return -EINVAL;
        }
-       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
+       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
 }
 
 static int
@@ -1682,13 +1759,13 @@ mcdx_config(struct s_drive_stuff *stuffp, int tries)
        cmd[1] = 0x10;          /* irq enable */
        cmd[2] = 0x05;          /* pre, err irq enable */
 
-       if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries))
+       if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
                return -1;
 
        cmd[1] = 0x02;          /* dma select */
        cmd[2] = 0x00;          /* no dma */
 
-       return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries);
+       return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
 }
 
 static int
@@ -1697,7 +1774,8 @@ mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tri
        char buf[3];
        int ans;
 
-       if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 1, buf, sizeof(buf), 2*HZ, tries)))
+       if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 
+                       1, buf, sizeof(buf), 1 * HZ, tries)))
                return ans;
 
        ver->code = buf[1];
@@ -1713,7 +1791,7 @@ mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
                outb(0, (unsigned int) stuffp->wreg_chn);               /* no dma, no irq -> hardware */
                outb(0, (unsigned int) stuffp->wreg_reset);             /* hw reset */
                return 0;
-       } else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5*HZ, tries);
+       } else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
 }
 
 static int
@@ -1722,14 +1800,13 @@ mcdx_lockdoor(struct s_drive_stuff *stuffp, int lock, int tries)
        char cmd[2] = { 0xfe };
     if (stuffp->present & DOOR) {
         cmd[1] = lock ? 0x01 : 0x00;
-        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5*HZ, tries);
-    } else 
-        return 0;
+        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, tries);
+    } else return 0;
 }
 
 static int
 mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5*HZ, tries); }
+{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }
 
 static int
 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
@@ -1765,3 +1842,4 @@ mcdx_setattentuator(
     return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
 }
 
+/* ex:set ts=4 sw=4: */
index 2d6890d859a9ba8e03a0df73bb7f8ecf98a63e23..c238566f1bd0f9c9e8bae614e52ebd6a24c88d94 100644 (file)
@@ -742,6 +742,9 @@ void apm_do_busy(void)
 #ifndef ALWAYS_CALL_BUSY
        if (!clock_slowed)
                return;
+#else
+       if (!apm_enabled)
+               return;
 #endif
 
        APM_SET_CPU_BUSY(error);
index 10e74050ac6849838bfb767dd4df955ad975dd7f..ee5b1a004c820f957d75fba88a44b29dac70ada1 100644 (file)
@@ -1958,7 +1958,7 @@ static void con_setsize(unsigned long rows, unsigned long cols)
  * us the option to easily disable it to avoid races when we
  * need to write to the console.
  */
-static void console_bh(void * unused)
+static void console_bh(void)
 {
        if (want_console >= 0) {
                if (want_console != fg_console) {
@@ -2101,9 +2101,7 @@ unsigned long con_init(unsigned long kmem_start)
        if (video_type != VIDEO_TYPE_TGAC)
                register_console(console_print);
 
-       bh_base[CONSOLE_BH].routine = console_bh;
-       enable_bh(CONSOLE_BH);
-
+       init_bh(CONSOLE_BH, console_bh);
        return kmem_start;
 }
 
index 89fa7c31d417b63a85095a0002e532da92ad0ed4..4d05ffad9a7a13e85d8a198ea9939e2ff8f925b9 100644 (file)
@@ -989,7 +989,7 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  * had to poll every port to see if that port needed servicing.
  */
 static void
-do_cyclades_bh(void *unused)
+do_cyclades_bh(void)
 {
     run_task_queue(&tq_cyclades);
 } /* do_cyclades_bh */
@@ -2816,8 +2816,7 @@ cy_init(void)
     if (tty_register_driver(&cy_callout_driver))
            panic("Couldn't register Cyclom callout driver\n");
 
-    bh_base[CYCLADES_BH].routine = do_cyclades_bh;
-    enable_bh(CYCLADES_BH);
+    init_bh(CYCLADES_BH, do_cyclades_bh);
 
     for (i = 0; i < 16; i++) {
            IRQ_cards[i] = 0;
index 61bcce0e3e46388fbb694467668eaf4f97535f69..6afe5c281fa1cd018166b164ce606d722bad2c39 100644 (file)
@@ -1153,7 +1153,7 @@ static inline unsigned char getleds(void){
  * used, but this allows for easy and efficient race-condition
  * prevention later on.
  */
-static void kbd_bh(void * unused)
+static void kbd_bh(void)
 {
        unsigned char leds = getleds();
 
@@ -1182,14 +1182,13 @@ int kbd_init(void)
 
        ttytab = console_driver.table;
 
-       bh_base[KEYBOARD_BH].routine = kbd_bh;
        request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
        request_region(0x60,16,"kbd");
 #ifdef INIT_KBD
        initialize_kbd();
 #endif
+       init_bh(KEYBOARD_BH, kbd_bh);
        mark_bh(KEYBOARD_BH);
-       enable_bh(KEYBOARD_BH);
        return 0;
 }
 
index 4dc9598d18113a7ec28bd595ce97f3ba19d6f98e..e2aab9fd6bc107cbf608f697dee6d40ef0d6ba4f 100644 (file)
@@ -86,10 +86,10 @@ extern unsigned long video_mem_term;
  */
 static inline void scr_writew(unsigned short val, unsigned short * addr)
 {
-        /*
-        * always deposit the char/attr, then see if it was to "screen" mem.
+       /*
+        * always deposit the char/attr, then see if it was to "screen" mem.
         * if so, then render the char/attr onto the real screen.
-        */
+        */
         *addr = val;
         if ((unsigned long)addr < video_mem_term &&
            (unsigned long)addr >= video_mem_base) {
index c98d4396b7976dd91ebdec40474387f7baff480f..76151be84b74536adab7eadacdf041a1da285628 100644 (file)
@@ -723,7 +723,7 @@ static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
  * interrupt driver proper are done; the interrupt driver schedules
  * them using rs_sched_event(), and they get done here.
  */
-static void do_serial_bh(void *unused)
+static void do_serial_bh(void)
 {
        run_task_queue(&tq_serial);
 }
@@ -2665,8 +2665,7 @@ int rs_init(void)
        int i;
        struct async_struct * info;
        
-       bh_base[SERIAL_BH].routine = do_serial_bh;
-       enable_bh(SERIAL_BH);
+       init_bh(SERIAL_BH, do_serial_bh);
        timer_table[RS_TIMER].fn = rs_timer;
        timer_table[RS_TIMER].expires = 0;
 #ifdef CONFIG_AUTO_IRQ
index a8b4c2ead8403695b75b2f926e856253f1d5062d..98346b87dd617f43afb7403b5916e1b8c47edb96 100644 (file)
@@ -668,7 +668,7 @@ isac_new_ph(struct IsdnCardState *sp)
 }
 
 static void
-teles_interrupt(int intno, struct pt_regs *regs)
+teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
        byte                 val, val2, r;
        struct IsdnCardState *sp;
@@ -1530,7 +1530,7 @@ get_irq(int cardnr)
        save_flags(flags);
        cli();
        if (request_irq(card->interrupt, &teles_interrupt,
-                       SA_INTERRUPT, "teles")) {
+                       SA_INTERRUPT, "teles", NULL)) {
                printk(KERN_WARNING "Teles couldn't get interrupt %d\n",
                        card->interrupt);
                restore_flags(flags);
@@ -1547,7 +1547,7 @@ release_irq(int cardnr)
        struct IsdnCard *card = cards + cardnr;
 
        irq2dev_map[card->interrupt] = NULL;
-       free_irq(card->interrupt);
+       free_irq(card->interrupt, NULL);
 }
 
 void
index c917de75c7665798b716c480141f40edee8bf97d..ea861b7cd57f33b28809d4b3379f25ed23c254a9 100644 (file)
@@ -45,6 +45,7 @@ static const char *version =
 
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/byteorder.h>
 
 #include "8390.h"
 #include "3c503.h"
@@ -435,7 +436,7 @@ el2_block_output(struct device *dev, int count,
 {
     unsigned short int *wrd;
     int boguscount;            /* timeout counter */
-    unsigned shor tmp_rev;     /* temporary for reversed values */
+    unsigned short tmp_rev;    /* temporary for reversed values */
 
     if (ei_status.word16)      /* Tx packets go into bank 0 on EL2/16 card */
        outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR);
index 367c0c902c4e9b3191f74ef1d3fb19a846e50ab3..03dcf48e2c7afd6fefb1bddadd4408ba89e416fa 100644 (file)
@@ -82,4 +82,8 @@ bool 'Token Ring driver support' CONFIG_TR
 if [ "$CONFIG_TR" = "y" ]; then
   tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR
 fi
-tristate 'Arcnet support' CONFIG_ARCNET
+tristate 'ARCnet support' CONFIG_ARCNET
+if [ "$CONFIG_ARCNET" != "n" ]; then
+  bool '  Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH
+  bool '  Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051
+fi
index 45ddc0c476031526fd70f6da5010e5e1fd23dfa7..29aa514a9fe12b96138d739f935b05fd33ae67ed 100644 (file)
          
        **********************
        
-       This is ONLY A SUMMARY.  The complete ChangeLog is available in
-       the full Linux-ARCnet package.
-       
+       v2.51 (96/02/29)
+         - Inserted a rather important missing "volatile" in autoprobe.
+         - arc0e and arc0s are now options in drivers/net/Config.in.
+       
+       v2.50 (96/02/24)
+         - Increased IRQ autoprobe delay.  Thanks to Andrew J. Kroll for
+           noticing the problem, which seems to only affect certain cards.
+         - Errors reserving ports and IRQ's now clean up after themselves.
+         - We now replace the TESTvalue byte from unused shmem addresses.
+         - You can now use "irq=" as well as "irqnum=" to set the IRQ
+           during module autoprobe.  This doesn't seem to crash insmod
+           anymore. (?)
+         - You can now define the name of the ARCnet device more easily
+           when loading the module: insmod arcnet.o device=test1
+           A new option, CONFIG_ARCNET_ETHNAME, allows the kernel to
+           choose one of the standard eth?-style device names
+           automatically.  This currently only works as a module.
+         - printk's now try to make some use of the KERN_xxx priority level
+           macros (though they may not be perfect yet).
+         - Packet and skb dump loops are now separate functions.
+         - Removed D_INIT from default debug level, because I am (finally)
+           pretty confident that autoprobe shouldn't toast anyone's
+           computer.
+         - This version is no longer ALPHA.
+
        v2.41 ALPHA (96/02/10)
          - Incorporated changes someone made to arcnet_setup in 1.3.60.
          - Increased reset timeout to 3/10 of a second because some cards
            still a horrible mess and will be cleaned up further as time
            passes.
            
+       The following has been SUMMARIZED.  The complete ChangeLog is
+       available in the full Linux-ARCnet package.
+       
        v2.22 (95/12/08)
          - Major cleanups, speedups, and better code-sharing.
          - Eliminated/changed many useless/meaningless/scary debug messages
            (and, in most cases, the bugs that caused them).
          - Better IPX support.
          - lp->stats updated properly.
-         - RECON checking now by default only bugs you if there are an
-           excessive number (ie. your cable is probably broken).
+         - RECON checking now by default only prints a message if there are
+           excessive errors (ie. your cable is probably broken).
          - New RFC1051-compliant "arc0s" virtual device by Tomasz
            Motylewski.
-         - Excess debug messages can be compiled out for maximum
-           efficiency.
+         - Excess debug messages can be compiled out to reduce code size.
 
        v2.00 (95/09/06)
-         - ARCnet RECON messages are now detected and logged.  These occur
-           when a new computer is powered up on the network, or in a
-           constant stream when the network cable is broken.  Thanks to
-           Tomasz Motylewski for this.  You must have D_EXTRA enabled
-           if you want these messages sent to syslog, otherwise they will
-           only show up in the network statistics (/proc/net/dev).
-         - The TX Acknowledge flag is now checked, and a log message is sent
-           if a completed transmit is not ACK'd.  (I have yet to have this
-           happen to me.)
+         - ARCnet RECON messages are now detected and logged as "carrier"
+           errors.
+         - The TXACK flag is now checked, and errors are logged.
          - Debug levels are now completely different.  See the README.
-         - Many code cleanups, with several no-longer-necessary and some
+         - Massive code cleanups, with several no-longer-necessary and some
            completely useless options removed.
          - Multiprotocol support.  You can now use the "arc0e" device to
            send "Ethernet-Encapsulation" packets, which are compatible with
            Windows for Workgroups and LAN Manager, and possibly other
            software.  See the README for more information.
-         - Documentation updates and improvements.
          
        v1.02 (95/06/21)
           - A fix to make "exception" packets sent from Linux receivable
          - Initial non-alpha release.
        
          
-       TO DO: (it it just me, or does this list only get longer?)
-       
-        - Make sure autoprobe puts TESTvalue back into shmem locations
-          that it determines aren't ARCnet cards.
-        - Probe for multiple devices in one shot (there's supposed to
-          be a way to do that now, but I can't remember what it is!)
-         - Support printk's priority levels.
-         - Have people test the new autoprobe a bit more - then remove
-           D_INIT from the default debug level.
-         - Move the SKB and memory dump code into separate functions.
+       TO DO: (semi-prioritized)
+       
+         - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
+           packet into ARCnet memory.
+        - Probe for multiple devices in one shot (trying to decide whether
+          to do it the "ugly" way or not).
+         - Add support for the new 1.3.x IP header cache features.
         - Debug level should be changed with a system call, not a hack to
           the "metric" flag.
          - What about cards with shared memory that can be "turned off?"
          - Try to implement promiscuous (receive-all-packets) mode available
            on some newer cards with COM20020 and similar chips.  I don't have
            one, but SMC sent me the specs.
-         - Add support for the new 1.3.x IP header cache features.
-         - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
-           packet into ARCnet memory.
          - ATA protocol support?? 
          - VINES TCP/IP encapsulation?? (info needed)
 
 */
 
 static const char *version =
- "arcnet.c: v2.41 ALPHA 96/02/10 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.51 96/02/29 Avery Pennarun <apenwarr@foxnet.net>\n";
 
  
 
@@ -199,19 +210,12 @@ static const char *version =
 
 /**************************************************************************/
 
-/* This driver supports three different "virtual ARCnet devices" running
- * on the same adapter, in order to communicate with various different
- * TCP/IP-over-ARCnet implementations.  They are:
- *     arc0    - RFC1201 Internet-standard protocol
- *     arc0e   - Ethernet-encapsulation protocol (as used by Windows)
- *     arc0s   - "Simpler" (but outdated) RFC1051 internet standard.
- *
- * arc0e and arc0s are created when arc0 is ifconfig'ed up.  You can disable
- * either or both of them by undefining CONFIG_ARCNET_ETH and/or
- * CONFIG_ARCNET_1051.
+/* Normally, the ARCnet device needs to be assigned a name (default arc0). 
+ * Ethernet devices have a fucntion to automatically try eth0, eth1, etc
+ * until a free name is found.  To name the ARCnet device using an "eth?"
+ * device name, define this option.
  */
-#define CONFIG_ARCNET_ETH
-#define CONFIG_ARCNET_1051
+#undef CONFIG_ARCNET_ETHNAME
 
 /* On a fast computer, the buffer copy from memory to the ARCnet card during
  * a transmit can hog the bus just a little too long.  SLOW_XMIT_COPY
@@ -270,9 +274,10 @@ static const char *version =
  * shmem are left in the list at Stage 5, they must correspond to each
  * other.
  *
- * This is undefined by default because it might not always be true.  Speed
- * demons can turn it on - I think it should be fine if you only have one
- * ARCnet card installed.
+ * This is undefined by default because it might not always be true, and the
+ * extra check makes the autoprobe even more careful.  Speed demons can turn
+ * it on - I think it should be fine if you only have one ARCnet card
+ * installed.
  *
  * If no ARCnet cards are installed, this delay never happens anyway and thus
  * the option has no effect.
@@ -321,21 +326,22 @@ static const char *version =
 #define D_SKB          128     /* show skb's                           */
 
 #ifndef ARCNET_DEBUG_MAX
-#define ARCNET_DEBUG_MAX (~0)          /* enable ALL debug messages */
-/*#define ARCNET_DEBUG_MAX (D_NORMAL|D_EXTRA|D_INIT|D_INIT_REASONS) */
-/*#define ARCNET_DEBUG_MAX 0   */      /* enable NO debug messages */
+#define ARCNET_DEBUG_MAX (~0)          /* enable ALL debug messages     */
+/*#define ARCNET_DEBUG_MAX (D_NORMAL|D_EXTRA|D_INIT|D_INIT_REASONS)     */
+/*#define ARCNET_DEBUG_MAX 0   */      /* enable NO messages (bad idea) */
 #endif
 
 #ifndef ARCNET_DEBUG
-#define ARCNET_DEBUG (D_NORMAL|D_EXTRA|D_INIT)
-/*#define ARCNET_DEBUG (D_NORMAL)*/
+#define ARCNET_DEBUG (D_NORMAL|D_EXTRA)
 #endif
 int arcnet_debug = ARCNET_DEBUG;
 
 /* macros to simplify debug checking */
 #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
-#define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg , ## args)
-#define BUGMSG(x,msg,args...) BUGMSG2(x,"%6s: " msg, dev->name , ## args)
+#define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg, ## args)
+#define BUGMSG(x,msg,args...) BUGMSG2(x,"%s%6s: " msg, \
+       x==D_NORMAL ? "" : x<=D_INIT_REASONS ? KERN_INFO : KERN_DEBUG , \
+       dev->name , ## args)
 
 /* Some useful multiprotocol macros.  The idea here is that GCC will
  * optimize away multiple tests or assignments to lp->adev.  Relying on this
@@ -575,6 +581,21 @@ struct arcnet_local {
 
 
 /* Index to functions, as function prototypes. */
+
+#if ARCNET_DEBUG_MAX & D_SKB
+static void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
+       char *desc);
+#else
+#      define arcnet_dump_skb(dev,skb,desc) ;
+#endif
+
+#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
+static void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
+       char *desc);
+#else
+#      define arcnet_dump_packet(dev,buffer,ext,desc) ;
+#endif
+
 extern int arcnet_probe(struct device *dev);
 static int arcnet_found(struct device *dev,int port,int airq,u_long shmem);
 
@@ -634,7 +655,59 @@ void cleanup_module(void);
 #define tx_done(dev) 1
 
 #define JIFFER(time) for (delayval=jiffies+time; jiffies<delayval;) ;
-               
+
+
+/****************************************************************************
+ *                                                                          *
+ * Packet dumps for debugging                                               *
+ *                                                                          *
+ ****************************************************************************/
+
+/* Dump the contents of an sk_buff
+ */ 
+#if ARCNET_DEBUG_MAX & D_SKB
+void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,char *desc)
+{
+       int i;
+       long flags;
+       
+       save_flags(flags);
+       cli();
+       printk(KERN_DEBUG "%6s: skb dump (%s) follows:",dev->name,desc);
+        for(i=0; i<skb->len; i++)
+        {
+               if (i%16==0)
+                       printk("\n" KERN_DEBUG "[%04X] ",i);
+               else
+                               printk("%02X ",((u_char *)skb->data)[i]);
+       }
+        printk("\n");
+        restore_flags(flags);
+}
+#endif
+
+/* Dump the contents of an ARCnet buffer
+ */
+#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
+void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,char *desc)
+{
+       int i;
+       long flags;
+       
+       save_flags(flags);
+       cli();
+       printk(KERN_DEBUG "%6s: packet dump (%s) follows:",dev->name,desc);
+       for (i=0; i<256+(ext!=0)*256; i++)
+       {
+               if (i%16==0)
+                       printk("\n" KERN_DEBUG "[%04X] ",i);
+               else
+                       printk("%02X ",buffer[i]);
+       }
+       printk("\n");
+       restore_flags(flags);
+}
+#endif 
 
 /****************************************************************************
  *                                                                          *
@@ -660,7 +733,8 @@ int arcnet_probe(struct device *dev)
        static int numports=sizeof(ports)/sizeof(ports[0]),
                   numshmems=sizeof(shmems)/sizeof(shmems[0]);
 
-       int count,status,delayval,ioaddr,numprint,airq;
+       int count,status,delayval,ioaddr,numprint,airq,retval=-ENODEV,
+               openparen=0;
        unsigned long airqmask;
        int *port;
        u_long *shmem;
@@ -682,7 +756,7 @@ int arcnet_probe(struct device *dev)
                sizeof(ports)+sizeof(shmems));
 
        
-#if 1
+#if 0
        BUGLVL(D_EXTRA)
        {
                printk("arcnet: ***\n");
@@ -795,7 +869,7 @@ int arcnet_probe(struct device *dev)
        numprint=0;
        for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
        {
-               u_char *cptr;
+               volatile u_char *cptr;
        
                numprint++;
                if (numprint>8)
@@ -810,7 +884,7 @@ int arcnet_probe(struct device *dev)
                
                if (*cptr != TESTvalue)
                {
-                       BUGMSG2(D_INIT_REASONS,"(mem=%Xh, not %Xh)\n",
+                       BUGMSG2(D_INIT_REASONS,"(mem=%02Xh, not %02Xh)\n",
                                *cptr,TESTvalue);
                        BUGMSG(D_INIT_REASONS,"Stage 3: ");
                        BUGLVL(D_INIT_REASONS) numprint=0;
@@ -916,8 +990,8 @@ int arcnet_probe(struct device *dev)
                        continue;
                }
 
-               /* skip this if an IRQ was given, because maybe we're on a
-                * machine that locks during autoirq!
+               /* skip this completely if an IRQ was given, because maybe
+                * we're on a machine that locks during autoirq!
                 */
                if (!dev->irq)
                {
@@ -927,7 +1001,7 @@ int arcnet_probe(struct device *dev)
                         */
                        airqmask = probe_irq_on();
                        outb(NORXflag,INTMASK);
-                       /*udelay(1);*/
+                       udelay(1);
                        outb(0,INTMASK);
                        airq = probe_irq_off(airqmask);
        
@@ -948,6 +1022,7 @@ int arcnet_probe(struct device *dev)
                }
                
                BUGMSG2(D_INIT,"(%d,", airq);
+               openparen=1;
                
                /* Everything seems okay.  But which shmem, if any, puts
                 * back its signature byte when the card is reset?
@@ -979,17 +1054,17 @@ int arcnet_probe(struct device *dev)
                        if (*cptr == TESTvalue) /* found one */
                        {
                                BUGMSG2(D_INIT,"%lXh)\n", *shmem);
+                               openparen=0;
 
                                /* register the card */
-                               status=arcnet_found(dev,*port,airq,*shmem);
+                               retval=arcnet_found(dev,*port,airq,*shmem);
+                               if (retval) openparen=0;
 
-                               /* remove port and shmem from the lists */
-                               *port=ports[numports-1];
-                               numports--;
+                               /* remove shmem from the list */
                                *shmem=shmems[numshmems-1];
                                numshmems--;
                                
-                               return status;
+                               break;
                        }
                        else
                        {
@@ -997,16 +1072,27 @@ int arcnet_probe(struct device *dev)
                        }
                }
 
-               BUGMSG2(D_INIT,"no matching shmem)\n");
-               BUGMSG(D_INIT_REASONS,"Stage 5: ");
-               BUGLVL(D_INIT_REASONS) numprint=0;
+               if (openparen)
+               {
+                       BUGMSG2(D_INIT,"no matching shmem)\n");
+                       BUGMSG(D_INIT_REASONS,"Stage 5: ");
+                       BUGLVL(D_INIT_REASONS) numprint=0;
+               }
+
                *port=ports[numports-1];
                numports--;
                port--;
+
+               if (!retval) break;
        }
        BUGMSG(D_INIT_REASONS,"\n");
 
-       return -ENODEV;
+       /* Now put back TESTvalue on all leftover shmems.
+        */
+       for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+               *(u_char *)(*shmem) = TESTvalue;
+
+       return retval;
 }
 
 /* Set up the struct device associated with this card.  Called after
@@ -1014,7 +1100,6 @@ int arcnet_probe(struct device *dev)
  */
 int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
 {
-       int irqval;
        u_char *first_mirror,*last_mirror;
        struct arcnet_local *lp;
        
@@ -1023,11 +1108,10 @@ int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
        dev->base_addr=port;
 
        /* reserve the irq */
-       irqval = request_irq(airq,&arcnet_interrupt,0,"arcnet",NULL);
-       if (irqval)
+       if (request_irq(airq,&arcnet_interrupt,0,"arcnet",NULL))
        {
-               BUGMSG(D_NORMAL,"unable to get IRQ %d (irqval=%d).\n",
-                       airq, irqval);
+               BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq);
+               release_region(port,ARCNET_TOTAL_SIZE);
                return -ENODEV;
        }
        irq2dev_map[airq]=dev;
@@ -1054,7 +1138,12 @@ int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
        
        dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
        if (dev->priv == NULL)
+       {
+               irq2dev_map[airq] = NULL;
+               free_irq(airq,NULL);
+               release_region(port,ARCNET_TOTAL_SIZE);
                return -ENOMEM;
+       }
        memset(dev->priv,0,sizeof(struct arcnet_local));
        lp=(struct arcnet_local *)(dev->priv);
        
@@ -1223,7 +1312,7 @@ arcnet_open(struct device *dev)
        if (dev->metric>=1000)
        {
                arcnet_debug=dev->metric-1000;
-               printk("%6s: debug level set to %d\n",dev->name,arcnet_debug);
+               printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug);
                dev->metric=1;
        }
 
@@ -1503,16 +1592,7 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
        out->hdr=(struct ClientData*)skb->data;
        out->skb=skb;
                
-       BUGLVL(D_SKB)
-       {
-               short i;
-               for(i=0; i<skb->len; i++)
-               {
-                       if(i%16 == 0) printk("\n[%04hX] ",i);
-                       printk("%02hX ",((unsigned char*)skb->data)[i]);
-               }
-               printk("\n");
-       }
+       BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx");
 
        out->hdr->sequence=(lp->sequence++);
        
@@ -1739,23 +1819,7 @@ arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
        BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
                        daddr,length);
                        
-       BUGLVL(D_TX)
-       {
-               int countx,county;
-               
-               printk("%6s: packet dump [tx] follows:",dev->name);
-
-               for (county=0; county<16+(length>MTU)*16; county++)
-               {
-                       printk("\n[%04X] ",county*16);
-                       for (countx=0; countx<16; countx++)
-                               printk("%02X ",
-                                       arcpacket->raw[county*16+countx]);
-               }
-               
-               printk("\n");
-       }
-
+       BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>MTU,"tx");
        lp->lastload_dest=daddr;
        lp->txready=lp->txbuf;  /* packet is ready for sending */
 }
@@ -1828,7 +1892,7 @@ arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs)
        if (dev==NULL)
        {
                BUGLVL(D_DURING)
-                       printk("arcnet: irq %d for unknown device.\n", irq);
+                       printk(KERN_DEBUG "arcnet: irq %d for unknown device.\n", irq);
                return;
        }
        
@@ -2075,8 +2139,9 @@ arcnet_inthandler(struct device *dev)
 #endif /* DETECT_RECONFIGS */
        } while (--boguscount && didsomething);
 
-       BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n\n",
+       BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
                        inb(STATUS),boguscount);
+       BUGMSG(D_DURING,"\n");
 
        SETMASK;        /* put back interrupt mask */
 
@@ -2168,22 +2233,7 @@ arcnet_rx(struct device *dev,int recbuf)
                break;
        }
 
-        BUGLVL(D_RX)
-       {
-               int countx,county;
-               
-               printk("%6s: packet dump [rx] follows:",dev->name);
-
-                       for (county=0; county<16+(length>240)*16; county++)
-                       {
-                               printk("\n[%04X] ",county*16);
-                               for (countx=0; countx<16; countx++)
-                                       printk("%02X ",
-                                               arcpacket->raw[county*16+countx]);
-                       }
-                       
-                       printk("\n");
-               }
+        BUGLVL(D_RX) arcnet_dump_packet(dev,arcpacket->raw,length>240,"rx");
 
 
 #ifndef SLOW_XMIT_COPY
@@ -2303,16 +2353,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
                        }
                }
                
-               BUGLVL(D_SKB)
-               {
-                   short i;
-                       for(i=0; i< skb->len; i++)
-                               {
-                                       if( i%16 == 0 ) printk("\n[%04hX] ",i);
-                                       printk("%02hX ",((unsigned char*)skb->data)[i]);
-                               }
-                               printk("\n");
-               }
+               BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
 
                skb->protocol=arcnetA_type_trans(skb,dev);
 
@@ -2473,17 +2514,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
                                in->skb=NULL;
                                in->lastpacket=in->numpackets=0;
                        
-                               BUGLVL(D_SKB)
-                               {
-                                       short i;
-                                       for(i=0; i<skb->len; i++)
-                                               {
-                                               if( i%16 == 0 ) printk("\n[%04hX] ",i);
-                                               printk("%02hX ",((unsigned char*)skb->data)[i]);
-                                       }
-                                       printk("\n");
-                               }
-
+                               BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
                        
                                skb->protocol=arcnetA_type_trans(skb,dev);
                                
@@ -2808,22 +2839,7 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
        BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
                        daddr,length);
                                
-       BUGLVL(D_TX)
-       {
-               int countx,county;
-                       
-               printk("%6s: packet dump [tx] follows:",dev->name);
-
-               for (county=0; county<16+(length>=240)*16; county++)
-               {
-                       printk("\n[%04X] ",county*16);
-                       for (countx=0; countx<16; countx++)
-                               printk("%02X ",
-                                       arcpacket->raw[county*16+countx]);
-               }
-               
-               printk("\n");
-       }
+       BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>=240,"tx");
 
        lp->lastload_dest=daddr;
        lp->txready=lp->txbuf;  /* packet is ready for sending */
@@ -2872,20 +2888,8 @@ arcnetE_rx(struct device *dev,u_char *arcsoft,
                
                memcpy(skb->data,(u_char *)arcsoft+1,length-1);
 
-        BUGLVL(D_SKB)
-        {
-               short i;
-               printk("%6s: rx skb dump follows:\n",dev->name);
-                for(i=0; i<skb->len; i++)
-                {
-                       if (i%16==0)
-                               printk("\n[%04hX] ",i);
-                       else
-                               printk("%02hX ",((u_char *)skb->data)[i]);
-               }
-                printk("\n");
-        }
-        
+        BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
+
        skb->protocol=eth_type_trans(skb,dev);
         
         netif_rx(skb);
@@ -2946,16 +2950,7 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
 
        length = 1 < skb->len ? skb->len : 1;
 
-       BUGLVL(D_SKB)
-       {
-               short i;
-               for(i=0; i<skb->len; i++)
-               {
-                       if (i%16 == 0) printk("\n[%04hX] ",i);
-                       printk("%02hX ",((unsigned char*)skb->data)[i]);
-               }
-               printk("\n");
-       }
+       BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx");
 
        /* fits in one packet? */
        if (length-S_EXTRA_CLIENTDATA<=XMTU)
@@ -3037,16 +3032,7 @@ arcnetS_rx(struct device *dev,u_char *buf,
                soft->saddr=saddr;
                skb->dev = dev;  /* is already lp->sdev */
                
-               BUGLVL(D_SKB)
-               {
-                       short i;
-                       for(i=0; i<skb->len; i++)
-                               {
-                                       if( i%16 == 0 ) printk("\n[%04hX] ",i);
-                                       printk("%02hX ",((unsigned char*)skb->data)[i]);
-                               }
-                               printk("\n");
-               }
+               BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
 
                skb->protocol=arcnetS_type_trans(skb,dev);
 
@@ -3198,7 +3184,8 @@ unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev)
 
 
 #ifdef MODULE
-static char devicename[9] = { 0, };
+
+static char devicename[9] = "";
 static struct device thiscard = {
   devicename, /* device name is inserted by linux/drivers/net/net_init.c */
   0, 0, 0, 0,
@@ -3209,15 +3196,22 @@ static struct device thiscard = {
        
 static int io=0x0;     /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
 static int irqnum=0;   /* or use the insmod io= irqnum= shmem= options */
+static int irq=0;
 static int shmem=0;
-static int num=0;      /* number of device (ie for 0 for arc0, 1 for arc1...) */
+static char *device = NULL;
 
 int
 init_module(void)
 {
-       sprintf(thiscard.name,"arc%d",num);
+       if (device)
+               strcpy(thiscard.name,device);
+#ifndef CONFIG_ARCNET_ETHNAME
+       else if (!thiscard.name[0]) strcpy(thiscard.name,"arc0");
+#endif
 
        thiscard.base_addr=io;
+       
+       if (irq) irqnum=irq;
 
        thiscard.irq=irqnum;
        if (thiscard.irq==2) thiscard.irq=9;
@@ -3252,9 +3246,8 @@ cleanup_module(void)
 
        if (thiscard.irq)
        {
-               free_irq(thiscard.irq,NULL);
-               /* very important! */
                irq2dev_map[thiscard.irq] = NULL;
+               free_irq(thiscard.irq,NULL);
        }
        
        if (thiscard.base_addr) release_region(thiscard.base_addr,
index ca7f77039cb26821ab01aa991821f9d5de50d126..fb2a5d1d9006cab521ca91f0a5fe78f86c76e1d2 100644 (file)
-/* eexpress.c: Intel EtherExpress device driver for Linux. */
 /*
-       Written 1993 by Donald Becker.
-       Copyright 1993 United States Government as represented by the Director,
-       National Security Agency.  This software may only be used and distributed
-       according to the terms of the GNU Public License as modified by SRC,
-       incorporated herein by reference.
-
-       The author may be reached as becker@super.org or
-       C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
-
-       Things remaining to do:
-       Check that the 586 and ASIC are reset/unreset at the right times.
-       Check tx and rx buffer setup.
-       The current Tx is single-buffer-only.
-       Move the theory of operation and memory map documentation.
-       Rework the board error reset
-       The statistics need to be updated correctly.
-
-        Modularized by Pauline Middelink <middelin@polyware.iaf.nl>
-        Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org>
-*/
-
-static const char *version =
-       "eexpress.c:v0.07 1/19/94 Donald Becker (becker@super.org)\n";
+ * eexpress2.c: Intel EtherExpress device driver for Linux
+ *
+ * Original version written 1993 by Donald Becker
+ * Modularized by Pauline Middelink <middelin@polyware.iaf.nl>
+ * Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org>
+ * Reworked 1995 by John Sullivan <js10039@cam.ac.uk>
+ * 
+ *  31jan96 Philip Blundell <pjb27@cam.ac.uk>
+ *     - Tidy up
+ *     - Some debugging.  Now works with 1.3 kernels.
+ *
+ *     Still to do:
+ *     - rationalise debugging
+ *     - fix detect/autoprobe and module routines
+ *     - test under high load, try to chase CU lockups
+ *     - look at RAM size check
+ *
+ * ToDo:
+ *   Move private globals into net_local structure
+ *   Multicast/Promiscuous mode handling
+ *   Put back debug reporting?
+ *   More documentation
+ *   Some worry about whether statistics are reported accurately
+ *
+ */
 
 /*
-  Sources:
-       This driver wouldn't have been written with the availability of the
-       Crynwr driver source code.      It provided a known-working implementation
-       that filled in the gaping holes of the Intel documentation.  Three cheers
-       for Russ Nelson.
+ * The original EtherExpress driver was just about useable, but
+ * suffered from a long startup delay, a hard limit of 16k memory
+ * usage on the card (EtherExpress 16s have either 32k or 64k),
+ * and random locks under load. The last was particularly annoying
+ * and made running eXceed/W preferable to Linux/XFree. After hacking
+ * through the driver for a couple of days, I had fixed most of the
+ * card handling errors, at the expense of turning the code into
+ * a complete jungle, but still hadn't tracked down the lock-ups.
+ * I had hoped these would be an IP bug, but failed to reproduce them
+ * under other drivers, so decided to start from scratch and rewrite
+ * the driver cleanly. And here it is.
+ *
+ * It's still not quite there, but self-corrects a lot more problems.
+ * the 'CU wedged, resetting...' message shouldn't happen at all, but
+ * at least we recover. It still locks occasionally, any ideas welcome.
+ *
+ * The original startup delay experienced by some people was due to the
+ * first ARP request for the address of the default router getting lost.
+ * (mostly the reply we were getting back was arriving before our
+ * hardware address was set up, or before the configuration sequence
+ * had told the card NOT to strip of the frame header). If you a long
+ * startup delay, you may have lost this ARP request/reply, although
+ * the original cause has been fixed. However, it is more likely that
+ * you've just locked under this version.
+ *
+ * The main changes are in the 586 initialization procedure (which was
+ * just broken before - the EExp is a strange beasty and needs careful
+ * handling) the receive buffer handling (we now use a non-terminating
+ * circular list of buffers, which stops the card giving us out-of-
+ * resources errors), and the transmit code. The driver is also more
+ * structured, and I have tried to keep the kernel interface separate
+ * from the hardware interface (although some routines naturally want
+ * to do both).
+ *
+ * John Sullivan
+ *
+ * 18/5/95:
+ *
+ * The lock-ups seem to happen when you access card memory after a 586
+ * reset. This happens only 1 in 12 resets, on a random basis, and
+ * completely locks the machine. As far as I can see there is no
+ * workaround possible - the only thing to be done is make sure we
+ * never reset the card *after* booting the kernel - once at probe time
+ * must be sufficient, and we'll just have to put up with that failing
+ * occasionally (or buy a new NIC). By the way, this looks like a 
+ * definate card bug, since Intel's own driver for DOS does exactly the
+ * same.
+ */
+
+/*
+ * Sources:
+ *
+ * The original eexpress.c by Donald Becker
+ *   Sources: the Crynwr EtherExpress driver source.
+ *            the Intel Microcommunications Databook Vol.1 1990
+ *
+ * wavelan.c and i82586.h
+ *   This was invaluable for the complete '586 configuration details
+ *   and command format.
+ *
+ * The Crynwr sources (again)
+ *   Not as useful as the Wavelan driver, but then I had eexpress.c to
+ *   go off.
+ *
+ * The Intel EtherExpress 16 ethernet card
+ *   Provided the only reason I want to see a working etherexpress driver.
+ *   A lot of fixes came from just observing how the card (mis)behaves when
+ *   you prod it.
+ *
+ */
 
-       Intel Microcommunications Databook, Vol. 1, 1990. It provides just enough
-       info that the casual reader might think that it documents the i82586.
-*/
+static char version[] = 
+"eexpress.c: v0.07 1/19/94 Donald Becker <becker@super.org>\n"
+"            v0.10 4th May 1995 John Sullivan <js10039@cam.ac.uk>\n";
 
 #include <linux/module.h>
 
@@ -57,978 +123,1108 @@ static const char *version =
 #include <linux/skbuff.h>
 #include <linux/malloc.h>
 
-/* use 0 for production, 1 for verification, 2..7 for debug */
+/*
+ * Not actually used yet - may be implemented when the driver has
+ * been debugged!
+ *
+ * Debug Level         Driver Status
+ *     0               Final release
+ *     1               Beta test
+ *     2
+ *     3
+ *     4               Report timeouts & 586 errors (normal debug level)
+ *     5               Report all major events
+ *     6               Dump sent/received packet contents
+ *     7               Report function entry/exit
+ */
+
+#undef NET_DEBUG
+
 #ifndef NET_DEBUG
-#define NET_DEBUG 2
+#define NET_DEBUG 4
 #endif
 static unsigned int net_debug = NET_DEBUG;
 
-/*
-                       Details of the i82586.
-
-   You'll really need the databook to understand the details of this part,
-   but the outline is that the i82586 has two separate processing units.
+#undef F_DEB
 
-   The Rx unit uses a list of frame descriptors and a list of data buffer
-   descriptors.  We use full-sized (1518 byte) data buffers, so there is
-   a one-to-one pairing of frame descriptors to buffer descriptors.
+#include "eth82586.h"
 
-   The Tx ("command") unit executes a list of commands that look like:
-               Status word             Written by the 82586 when the command is done.
-               Command word    Command in lower 3 bits, post-command action in upper 3
-               Link word               The address of the next command.
-               Parameters              (as needed).
-
-       Some definitions related to the Command Word are:
+/*
+ * Private data declarations
  */
-#define CMD_EOL                0x8000                  /* The last command of the list, stop. */
-#define CMD_SUSP       0x4000                  /* Suspend after doing cmd. */
-#define CMD_INTR       0x2000                  /* Interrupt after doing cmd. */
 
-enum commands {
-       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
-       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
-
-/* Information that need to be kept for each board. */
-struct net_local {
+struct net_local 
+{
        struct enet_statistics stats;
-       int last_restart;
-       short rx_head;
-       short rx_tail;
-       short tx_head;
-       short tx_cmd_link;
-       short tx_reap;
+       unsigned long init_time;        /* jiffies when eexp_hw_init586 called */
+       unsigned short rx_first;        /* first rx buf, same as RX_BUF_START */
+       unsigned short rx_last;         /* last rx buf */
+       unsigned short tx_head;         /* next free tx buf */
+       unsigned short tx_reap;         /* first in-use tx buf */
+       unsigned short tx_tail;         /* previous tx buf to tx_head */
+       unsigned short tx_link;         /* last known-executing tx buf */
+       unsigned short last_tx_restart; /* set to tx_link when we restart the CU */
 };
 
-/*
-               Details of the EtherExpress Implementation
-  The EtherExpress takes an unusual approach to host access to packet buffer
-  memory.  The host can use either the Dataport, with independent
-  autoincrementing read and write pointers, or it can I/O map 32 bytes of the
-  memory using the "Shadow Memory Pointer" (SMB) as follows:
-                       ioaddr                                          Normal EtherExpress registers
-                       ioaddr+0x4000...0x400f          Buffer Memory at SMB...SMB+15
-                       ioaddr+0x8000...0x800f          Buffer Memory at SMB+16...SMB+31
-                       ioaddr+0xC000...0xC007          "" SMB+16...SMB+23 (hardware flaw?)
-                       ioaddr+0xC008...0xC00f          Buffer Memory at 0x0008...0x000f
-  The last I/O map set is useful if you put the i82586 System Command Block
-  (the command mailbox) exactly at 0x0008.  (There seems to be some
-  undocumented init structure at 0x0000-7, so I had to use the Crywnr memory
-  setup verbatim for those four words anyway.)
-
-  A problem with using either one of these mechanisms is that you must run
-  single-threaded, or the interrupt handler must restore a changed value of
-  the read, write, or SMB pointers.
-
-  Unlike the Crynwr driver, my driver mostly ignores the I/O mapped "feature"
-  and relies heavily on the dataport for buffer memory access.  To minimize
-  switching, the read_pointer is dedicated to the Rx interrupt handler, and
-  the write_pointer is used by the send_packet() routine (it's carefully saved
-  and restored when it's needed by the interrupt handler).
-  */
-
-/* Offsets from the base I/O address. */
-#define DATAPORT       0       /* Data Transfer Register. */
-#define WRITE_PTR      2       /* Write Address Pointer. */
-#define READ_PTR       4       /* Read Address Pointer. */
-#define SIGNAL_CA      6       /* Frob the 82586 Channel Attention line. */
-#define SET_IRQ                7       /* IRQ Select. */
-#define SHADOW_PTR     8       /* Shadow Memory Bank Pointer. */
-#define MEM_Ctrl       11
-#define MEM_Page_Ctrl  12
-#define Config         13
-#define EEPROM_Ctrl            14
-#define ID_PORT                15
-
-#define EEXPRESS_IO_EXTENT 16
-
-/*     EEPROM_Ctrl bits. */
-
-#define EE_SHIFT_CLK   0x01    /* EEPROM shift clock. */
-#define EE_CS                  0x02    /* EEPROM chip select. */
-#define EE_DATA_WRITE  0x04    /* EEPROM chip data in. */
-#define EE_DATA_READ   0x08    /* EEPROM chip data out. */
-#define EE_CTRL_BITS   (EE_SHIFT_CLK | EE_CS | EE_DATA_WRITE | EE_DATA_READ)
-#define ASIC_RESET             0x40
-#define _586_RESET             0x80
-
-/* Offsets to elements of the System Control Block structure. */
-#define SCB_STATUS     0xc008
-#define SCB_CMD                0xc00A
-#define         CUC_START       0x0100
-#define         CUC_RESUME      0x0200
-#define         CUC_SUSPEND 0x0300
-#define         RX_START        0x0010
-#define         RX_RESUME       0x0020
-#define         RX_SUSPEND      0x0030
-#define SCB_CBL                0xc00C  /* Command BLock offset. */
-#define SCB_RFA                0xc00E  /* Rx Frame Area offset. */
+unsigned short start_code[] = {
+       0x0000,                 /* SCP: set bus to 16 bits */
+       0x0000,0x0000,          /* junk */
+       0x0000,0x0000,          /* address of ISCP (lo,hi) */
 
-/*
-  What follows in 'init_words[]' is the "program" that is downloaded to the
-  82586 memory.         It's mostly tables and command blocks, and starts at the
-  reset address 0xfffff6.
-
-  Even with the additional "don't care" values, doing it this way takes less
-  program space than initializing the individual tables, and I feel it's much
-  cleaner.
-
-  The databook is particularly useless for the first two structures; they are
-  completely undocumented.  I had to use the Crynwr driver as an example.
-
-   The memory setup is as follows:
-   */
-
-#define CONFIG_CMD     0x0018
-#define SET_SA_CMD     0x0024
-#define SA_OFFSET      0x002A
-#define IDLELOOP       0x30
-#define TDR_CMD                0x38
-#define TDR_TIME       0x3C
-#define DUMP_CMD       0x40
-#define DIAG_CMD       0x48
-#define SET_MC_CMD     0x4E
-#define DUMP_DATA      0x56    /* A 170 byte buffer for dump and Set-MC into. */
-
-#define TX_BUF_START   0x0100
-#define NUM_TX_BUFS    4
-#define TX_BUF_SIZE            0x0680  /* packet+header+TBD+extra (1518+14+20+16) */
-#define TX_BUF_END             0x2000
-
-#define RX_BUF_START   0x2000
-#define RX_BUF_SIZE    (0x640) /* packet+header+RBD+extra */
-#define RX_BUF_END             0x4000
+       0x0001,                 /* ISCP: busy - cleared after reset */
+       0x0008,0x0000,0x0000,   /* offsett,address (lo,hi) of SCB */
 
-/*
-  That's it: only 86 bytes to set up the beast, including every extra
-  command available.  The 170 byte buffer at DUMP_DATA is shared between the
-  Dump command (called only by the diagnostic program) and the SetMulticastList
-  command.
-
-  To complete the memory setup you only have to write the station address at
-  SA_OFFSET and create the Tx & Rx buffer lists.
-
-  The Tx command chain and buffer list is setup as follows:
-  A Tx command table, with the data buffer pointing to...
-  A Tx data buffer descriptor.  The packet is in a single buffer, rather than
-     chaining together several smaller buffers.
-  A NoOp command, which initially points to itself,
-  And the packet data.
-
-  A transmit is done by filling in the Tx command table and data buffer,
-  re-writing the NoOp command, and finally changing the offset of the last
-  command to point to the current Tx command.  When the Tx command is finished,
-  it jumps to the NoOp, when it loops until the next Tx command changes the
-  "link offset" in the NoOp.  This way the 82586 never has to go through the
-  slow restart sequence.
-
-  The Rx buffer list is set up in the obvious ring structure.  We have enough
-  memory (and low enough interrupt latency) that we can avoid the complicated
-  Rx buffer linked lists by alway associating a full-size Rx data buffer with
-  each Rx data frame.
-
-  I current use four transmit buffers starting at TX_BUF_START (0x0100), and
-  use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
-
-  */
-
-static short init_words[] = {
-       0x0000,                                 /* Set bus size to 16 bits. */
-       0x0000,0x0000,                  /* Set control mailbox (SCB) addr. */
-       0,0,                                    /* pad to 0x000000. */
-       0x0001,                                 /* Status word that's cleared when init is done. */
-       0x0008,0,0,                             /* SCB offset, (skip, skip) */
-
-       0,0xf000|RX_START|CUC_START,    /* SCB status and cmd. */
-       CONFIG_CMD,                             /* Command list pointer, points to Configure. */
-       RX_BUF_START,                           /* Rx block list. */
-       0,0,0,0,                                /* Error count: CRC, align, buffer, overrun. */
-
-       /* 0x0018: Configure command.  Change to put MAC data with packet. */
-       0, CmdConfigure,                /* Status, command.             */
-       SET_SA_CMD,                             /* Next command is Set Station Addr. */
-       0x0804,                                 /* "4" bytes of config data, 8 byte FIFO. */
-       0x2e40,                                 /* Magic values, including MAC data location. */
-       0,                                              /* Unused pad word. */
-
-       /* 0x0024: Setup station address command. */
-       0, CmdSASetup,
-       SET_MC_CMD,                             /* Next command. */
-       0xaa00,0xb000,0x0bad,   /* Station address (to be filled in) */
-
-       /* 0x0030: NOP, looping back to itself.  Point to first Tx buffer to Tx. */
-       0, CmdNOp, IDLELOOP, 0 /* pad */,
-
-       /* 0x0038: A unused Time-Domain Reflectometer command. */
-       0, CmdTDR, IDLELOOP, 0,
-
-       /* 0x0040: An unused Dump State command. */
-       0, CmdDump, IDLELOOP, DUMP_DATA,
-
-       /* 0x0048: An unused Diagnose command. */
-       0, CmdDiagnose, IDLELOOP,
-
-       /* 0x004E: An empty set-multicast-list command. */
-#ifdef initial_text_tx
-       0, CmdMulticastList, DUMP_DATA, 0,
-#else
-       0, CmdMulticastList, IDLELOOP, 0,
-#endif
+       0x0000,0x0000,          /* SCB: status, commands */
+       0x0000,0x0000,          /* links to first command block, first receive descriptor */
+       0x0000,0x0000,          /* CRC error, alignment error counts */
+       0x0000,0x0000,          /* out of resources, overrun error counts */
 
-       /* 0x0056: A continuous transmit command, only here for testing. */
-       0, CmdTx, DUMP_DATA, DUMP_DATA+8, 0x83ff, -1, DUMP_DATA, 0,
-};
+       0x0000,0x0000,          /* pad */
+       0x0000,0x0000,
 
-/* Index to functions, as function prototypes. */
-
-extern int express_probe(struct device *dev);  /* Called from Space.c */
-
-static int     eexp_probe1(struct device *dev, short ioaddr);
-static int     eexp_open(struct device *dev);
-static int     eexp_send_packet(struct sk_buff *skb, struct device *dev);
-static void    eexp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void eexp_rx(struct device *dev);
-static int     eexp_close(struct device *dev);
-static struct enet_statistics *eexp_get_stats(struct device *dev);
-static void set_multicast_list(struct device *dev);
-
-static int read_eeprom(int ioaddr, int location);
-static void hardware_send_packet(struct device *dev, void *buf, short length);
-static void init_82586_mem(struct device *dev);
-static void init_rx_bufs(struct device *dev);
-
-\f
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, (detachable devices only) allocate space for the
-   device and return success.
-   */
-int
-express_probe(struct device *dev)
-{
-       /* Don't probe all settable addresses, 0x[23][0-7]0, just common ones. */
-       int *port, ports[] = {0x300, 0x270, 0x320, 0x340, 0};
-       int base_addr = dev->base_addr;
+       0x0000,Cmd_Config,      /* startup configure sequence, at 0x0020 */
+       0x0032,                 /* link to next command */
+       0x080c,                 /* 12 bytes follow : fifo threshold=8 */
+       0x2e40,                 /* don't rx bad frames : SRDY/ARDY => ext. sync. : preamble len=8
+                                * take addresses from data buffers : 6 bytes/address */
+       0x6000,                 /* default backoff method & priority : interframe spacing = 0x60 */
+       0xf200,                 /* slot time=0x200 : max collision retry = 0xf */
+       0x0000,                 /* no HDLC : normal CRC : enable broadcast : disable promiscuous/multicast modes */
+       0x003c,                 /* minimum frame length = 60 octets) */
 
-       if (base_addr > 0x1ff)  /* Check a single specified location. */
-               return eexp_probe1(dev, base_addr);
-       else if (base_addr > 0)
-               return ENXIO;           /* Don't probe at all. */
+       0x0000,Cmd_INT|Cmd_SetAddr,
+       0x003e,                 /* link to next command */
+       0x0000,0x0000,0x0000,   /* hardware address placed here, 0x0038 */
+       0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
+       0x003e,
 
-       for (port = &ports[0]; *port; port++) {
-               short id_addr = *port + ID_PORT;
-               unsigned short sum = 0;
-               int i;
-#ifdef notdef
-               for (i = 16; i > 0; i--)
-                       sum += inb(id_addr);
-               printk("EtherExpress ID checksum is %04x.\n", sum);
-#else
-               for (i = 4; i > 0; i--) {
-                       short id_val = inb(id_addr);
-                       sum |= (id_val >> 4) << ((id_val & 3) << 2);
-               }
-#endif
-               if (sum == 0xbaba
-                       && eexp_probe1(dev, *port) == 0)
-                       return 0;
-       }
+       0x0000
 
-       return ENODEV;
-}
+};
 
-int eexp_probe1(struct device *dev, short ioaddr)
-{
-       unsigned short station_addr[3];
-       int i;
+#define CONF_LINK 0x0020
+#define CONF_HW_ADDR 0x0038
 
-       printk("%s: EtherExpress at %#x,", dev->name, ioaddr);
+/* maps irq number to EtherExpress magic value */
+static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
 
-       /* The station address is stored !backwards! in the EEPROM, reverse
-          after reading.  (Hmmm, a little brain-damage there at Intel, eh?) */
-       station_addr[0] = read_eeprom(ioaddr, 2);
-       station_addr[1] = read_eeprom(ioaddr, 3);
-       station_addr[2] = read_eeprom(ioaddr, 4);
+static unsigned char started=0;
 
-       /* Check the first three octets of the S.A. for the manufacturer's code. */
-       if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) {
-               printk(" rejected (invalid address %04x%04x%04x).\n",
-                          station_addr[2], station_addr[1], station_addr[0]);
-               return ENODEV;
-       }
+/*
+ * Prototypes for Linux interface
+ */
 
-       /* We've committed to using the board, and can start filling in *dev. */
-       request_region(ioaddr, EEXPRESS_IO_EXTENT, "eexpress");
-       dev->base_addr = ioaddr;
+extern int                  express_probe(struct device *dev);
+static int                     eexp_open (struct device *dev);
+static int                     eexp_close(struct device *dev);
+static struct enet_statistics *eexp_stats(struct device *dev);
+static int                     eexp_xmit (struct sk_buff *buf, struct device *dev);
 
-       for (i = 0; i < 6; i++) {
-               dev->dev_addr[i] = ((unsigned char*)station_addr)[5-i];
-               printk(" %02x", dev->dev_addr[i]);
-       }
+static void                    eexp_irq  (int irq, void *dev_addr, struct pt_regs *regs);
 
-       /* There is no reason for the driver to care, but I print out the
-          interface to minimize bogus bug reports. */
-       {
-               char irqmap[] = {0, 9, 3, 4, 5, 10, 11, 0};
-               const char *ifmap[] = {"AUI", "BNC", "10baseT"};
-               enum iftype {AUI=0, BNC=1, TP=2};
-               unsigned short setupval = read_eeprom(ioaddr, 0);
-
-               dev->irq = irqmap[setupval >> 13];
-               dev->if_port = (setupval & 0x1000) == 0 ? AUI :
-                       read_eeprom(ioaddr, 5) & 0x1 ? TP : BNC;
-               printk(", IRQ %d, Interface %s.\n", dev->irq, ifmap[dev->if_port]);
-               /* Release the IRQ line so that it can be shared if we don't use the
-                  ethercard. */
-               outb(0x00, ioaddr + SET_IRQ);
-       }
+/*
+ * Prototypes for hardware access functions
+ */
 
-       /* It's now OK to leave the board in reset, pending the open(). */
-       outb(ASIC_RESET, ioaddr + EEPROM_Ctrl);
+static void           eexp_hw_rx        (struct device *dev);
+static void           eexp_hw_tx        (struct device *dev, unsigned short *buf, unsigned short len);
+static int            eexp_hw_probe     (struct device *dev,unsigned short ioaddr);
+static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location);
 
-       if ((dev->mem_start & 0xf) > 0)
-               net_debug = dev->mem_start & 7;
+static unsigned short eexp_hw_lasttxstat(struct device *dev);
+static void           eexp_hw_txrestart (struct device *dev);
 
-       if (net_debug)
-               printk(version);
+static void           eexp_hw_txinit    (struct device *dev);
+static void           eexp_hw_rxinit    (struct device *dev);
+static void           eexp_hw_rxmap     (struct device *dev,unsigned short rx_buf);
 
-       /* Initialize the device structure. */
-       dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
-       if (dev->priv == NULL)
-               return -ENOMEM;
-       memset(dev->priv, 0, sizeof(struct net_local));
+static void           eexp_hw_init586   (struct device *dev);
+static void           eexp_hw_ASICrst   (struct device *dev);
 
-       dev->open               = eexp_open;
-       dev->stop               = eexp_close;
-       dev->hard_start_xmit = eexp_send_packet;
-       dev->get_stats  = eexp_get_stats;
-       dev->set_multicast_list = &set_multicast_list;
+/*
+ * Linux interface
+ */
 
-       /* Fill in the fields of the device structure with ethernet-generic values. */
-       
-       ether_setup(dev);
-       
-       dev->flags&=~IFF_MULTICAST;
-               
-       return 0;
+/*
+ * checks for presence of EtherExpress card
+ */
+
+int express_probe(struct device *dev)
+{
+       unsigned short *port,ports[] = { 0x0300,0x0270,0x0320,0x0340,0 };
+       unsigned short ioaddr = dev->base_addr;
+
+       if (ioaddr&0xfe00)
+               return eexp_hw_probe(dev,ioaddr);
+       else if (ioaddr)
+               return ENXIO;
+
+       for ( port=&ports[0] ; *port ; port++ ) 
+       {
+               unsigned short sum = 0;
+               int i;
+               for ( i=0 ; i<4 ; i++ ) 
+               {
+                       unsigned short t;
+                       t = inb(*port + ID_PORT);
+                       sum |= (t>>4) << ((t & 0x03)<<2);
+               }
+               if (sum==0xbaba && !eexp_hw_probe(dev,*port)) 
+                       return 0;
+       }
+       return ENODEV;
 }
 
-\f
-/* Reverse IRQ map: the value to put in the SET_IRQ reg. for IRQ<index>. */
-static char irqrmap[]={0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0};
+/*
+ * open and initialize the adapter, ready for use
+ */
 
-static int
-eexp_open(struct device *dev)
+static int eexp_open(struct device *dev)
 {
-       int ioaddr = dev->base_addr;
+       int irq = dev->irq;
+       unsigned short ioaddr = dev->base_addr;
+
+#if NET_DEBUG > 6
+       printk("%s: eexp_open()\n", dev->name);
+#endif
 
-       if (dev->irq == 0  ||  irqrmap[dev->irq] == 0)
+       if (!irq || !irqrmap[irq]) 
                return -ENXIO;
 
-       if (irq2dev_map[dev->irq] != 0
-               /* This is always true, but avoid the false IRQ. */
-               || (irq2dev_map[dev->irq] = dev) == 0
-               || request_irq(dev->irq, &eexp_interrupt, 0, "EExpress", NULL)) {
+       if (irq2dev_map[irq] ||
+             /* more consistent, surely? */
+          ((irq2dev_map[irq]=dev),0) ||
+            request_irq(irq,&eexp_irq,0,"EExpress",NULL)) 
                return -EAGAIN;
-       }
-
-       /* Initialize the 82586 memory and start it. */
-       init_82586_mem(dev);
-
-       /* Enable the interrupt line. */
-       outb(irqrmap[dev->irq] | 0x08, ioaddr + SET_IRQ);
 
+       request_region(ioaddr,16,"EExpress");
        dev->tbusy = 0;
        dev->interrupt = 0;
+       eexp_hw_init586(dev);
        dev->start = 1;
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
-static int
-eexp_send_packet(struct sk_buff *skb, struct device *dev)
+/*
+ * close and disable the interface, leaving
+ * the 586 in reset
+ */
+static int eexp_close(struct device *dev)
+{
+       unsigned short ioaddr = dev->base_addr;
+       int irq = dev->irq;
+
+       dev->tbusy = 1; 
+       dev->start = 0;
+  
+       outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
+       started = 0;
+       outw(SCB_CUsuspend|SCB_RUsuspend,ioaddr+SCB_CMD);
+       outb(0,ioaddr+SIGNAL_CA);
+       free_irq(irq,NULL);
+       irq2dev_map[irq] = NULL;
+       outb(i586_RST,ioaddr+EEPROM_Ctrl);
+       release_region(ioaddr,16);
+       return 0;
+}
+
+/*
+ * Return interface stats
+ */
+
+static struct enet_statistics *eexp_stats(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+
+       /* 
+        * Hmmm, this looks a little too easy... The card maintains
+        * some stats in the SCB, and I'm not convinced we're
+        * incrementing the most sensible statistics when the card
+        * returns an error (esp. slow DMA, out-of-resources)
+        */
+       return &lp->stats;
+}
+
+/*
+ * Called to transmit a packet, or to allow us to right ourselves
+ * if the kernel thinks we've died.
+ */
+
+static int eexp_xmit(struct sk_buff *buf, struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
-       int ioaddr = dev->base_addr;
-
-       if (dev->tbusy) {
-               /* If we get here, some higher level has decided we are broken.
-                  There should really be a "kick me" function call instead. */
-               int tickssofar = jiffies - dev->trans_start;
-               if (tickssofar < 5)
-                       return 1;
-               if (net_debug > 1)
-                       printk("%s: transmit timed out, %s?  ", dev->name,
-                                  inw(ioaddr+SCB_STATUS) & 0x8000 ? "IRQ conflict" :
-                                  "network cable problem");
-               lp->stats.tx_errors++;
-               /* Try to restart the adaptor. */
-               if (lp->last_restart == lp->stats.tx_packets) {
-                       if (net_debug > 1) printk("Resetting board.\n");
-                       /* Completely reset the adaptor. */
-                       init_82586_mem(dev);
-               } else {
-                       /* Issue the channel attention signal and hope it "gets better". */
-                       if (net_debug > 1) printk("Kicking board.\n");
-                       outw(0xf000|CUC_START|RX_START, ioaddr + SCB_CMD);
-                       outb(0, ioaddr + SIGNAL_CA);
-                       lp->last_restart = lp->stats.tx_packets;
+       unsigned short ioaddr = dev->base_addr;
+
+#if NET_DEBUG > 6
+       printk("%s: eexp_xmit()\n", dev->name);
+#endif
+
+       outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+       if (dev->tbusy) 
+       {
+               /* This will happen, but hopefully not as often as when
+                * tbusy==0. If it happens too much, we probably ought
+                * to think about unwedging ourselves...
+                */
+               if (test_bit(0,(void *)&started)) 
+               {
+                       if ((jiffies - dev->trans_start)>5) 
+                       {
+                               if (lp->tx_link==lp->last_tx_restart) 
+                               {
+                                       unsigned short boguscount=200,rsst;
+                                       printk("%s: Retransmit timed out, status %04x, resetting...\n",
+                                               dev->name,inw(ioaddr+SCB_STATUS));
+                                       eexp_hw_txinit(dev);
+                                       lp->last_tx_restart = 0;
+                                       outw(lp->tx_link,ioaddr+SCB_CBL);
+                                       outw(0,ioaddr+SCB_STATUS);
+                                       outw(SCB_CUstart,ioaddr+SCB_CMD);
+                                       outb(0,ioaddr+SIGNAL_CA);
+                                       while (!SCB_complete(rsst=inw(ioaddr+SCB_STATUS))) 
+                                       {
+                                               if (!--boguscount) 
+                                               {
+                                                       boguscount=200;
+                                                       printk("%s: Reset timed out status %04x, retrying...\n",
+                                                               dev->name,rsst);
+                                                       outw(lp->tx_link,ioaddr+SCB_CBL);
+                                                       outw(0,ioaddr+SCB_STATUS);
+                                                       outw(SCB_CUstart,ioaddr+SCB_CMD);
+                                                       outb(0,ioaddr+SIGNAL_CA);
+                                               }
+                                       }
+                                       dev->tbusy = 0;
+                                       mark_bh(NET_BH);
+                               }
+                               else
+                               {
+                                       unsigned short status = inw(ioaddr+SCB_STATUS);
+                                       if (SCB_CUdead(status)) 
+                                       {
+                                               unsigned short txstatus = eexp_hw_lasttxstat(dev);
+                                               printk("%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
+                                                       dev->name, status, txstatus);
+                                               eexp_hw_txrestart(dev);
+                                       }
+                                       else
+                                       {
+                                               unsigned short txstatus = eexp_hw_lasttxstat(dev);
+                                               if (dev->tbusy && !txstatus) 
+                                               {
+                                                       printk("%s: CU wedged, status %04x %04x, resetting...\n",
+                                                               dev->name,status,txstatus);
+                                                       eexp_hw_init586(dev); 
+                                                       dev->tbusy = 0;
+                                                       mark_bh(NET_BH);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       if ((jiffies-lp->init_time)>10)
+                       {
+                               unsigned short status = inw(ioaddr+SCB_STATUS);
+                               printk("%s: i82586 startup timed out, status %04x, resetting...\n",
+                                       dev->name, status);
+                               eexp_hw_init586(dev);
+                               dev->tbusy = 0;
+                               mark_bh(NET_BH);
+                       }
                }
-               dev->tbusy=0;
-               dev->trans_start = jiffies;
        }
 
-       /* If some higher layer thinks we've missed an tx-done interrupt
-          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-          itself. */
-       if (skb == NULL) {
+       if (buf==NULL) 
+       {
+               unsigned short status = inw(ioaddr+SCB_STATUS);
+               unsigned short txstatus = eexp_hw_lasttxstat(dev);
+               if (SCB_CUdead(status)) 
+               {
+                       printk("%s: CU has died! status %04x %04x, attempting to restart...\n",
+                               dev->name, status, txstatus);
+                       lp->stats.tx_errors++;
+                       eexp_hw_txrestart(dev);
+               }
                dev_tint(dev);
+               outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
                return 0;
        }
 
-       /* Block a timer-based transmit from overlapping. */
-       if (set_bit(0, (void*)&dev->tbusy) != 0)
-               printk("%s: Transmitter access conflict.\n", dev->name);
-       else {
-               short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-               unsigned char *buf = skb->data;
-
-               /* Disable the 82586's input to the interrupt line. */
-               outb(irqrmap[dev->irq], ioaddr + SET_IRQ);
-               hardware_send_packet(dev, buf, length);
-               dev->trans_start = jiffies;
-               /* Enable the 82586 interrupt input. */
-               outb(0x08 | irqrmap[dev->irq], ioaddr + SET_IRQ);
+       if (set_bit(0,(void *)&dev->tbusy)) 
+       {
+/*    printk("%s: Transmitter busy or access conflict\n",dev->name); */
+               lp->stats.tx_dropped++;
        }
+       else
+       {
+               unsigned short length = (ETH_ZLEN < buf->len) ? buf->len : ETH_ZLEN;
+               unsigned short *data = (unsigned short *)buf->data;
 
-       dev_kfree_skb (skb, FREE_WRITE);
-
-       /* You might need to clean up and record Tx statistics here. */
-       lp->stats.tx_aborted_errors++;
-
+               outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+               eexp_hw_tx(dev,data,length);
+               outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
+       }
+       dev_kfree_skb(buf, FREE_WRITE);
+       outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
        return 0;
 }
-\f
-/*     The typical workload of the driver:
-       Handle the network interface interrupts. */
-static void
-eexp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+
+/*
+ * Handle an EtherExpress interrupt
+ * If we've finished initializing, start the RU and CU up.
+ * If we've already started, reap tx buffers, handle any received packets,
+ * check to make sure we've not become wedged.
+ */
+
+static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
 {
-       struct device *dev = (struct device *)(irq2dev_map[irq]);
+       struct device *dev = irq2dev_map[irq];
        struct net_local *lp;
-       int ioaddr, status, boguscount = 0;
-       short ack_cmd;
+       unsigned short ioaddr,status,ack_cmd;
+       unsigned short old_rp,old_wp;
 
-       if (dev == NULL) {
-               printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+       if (dev==NULL) 
+       {
+               printk("net_interrupt(): irq %d for unknown device caught by EExpress\n",irq);
                return;
        }
-       dev->interrupt = 1;
-       
-       ioaddr = dev->base_addr;
+
+#if NET_DEBUG > 6
+       printk("%s: interrupt\n", dev->name);
+#endif
+
+       dev->interrupt = 1; /* should this be reset on exit? */
+  
        lp = (struct net_local *)dev->priv;
-       
-       status = inw(ioaddr + SCB_STATUS);
-       
-    if (net_debug > 4) {
-               printk("%s: EExp interrupt, status %4.4x.\n", dev->name, status);
-    }
-
-       /* Disable the 82586's input to the interrupt line. */
-       outb(irqrmap[dev->irq], ioaddr + SET_IRQ);
-
-       /* Reap the Tx packet buffers. */
-       while (lp->tx_reap != lp->tx_head) {    /* if (status & 0x8000) */
-               unsigned short tx_status;
-               outw(lp->tx_reap, ioaddr + READ_PTR);
-               tx_status = inw(ioaddr);
-               if (tx_status == 0) {
-                       if (net_debug > 5)  printk("Couldn't reap %#x.\n", lp->tx_reap);
-                       break;
-               }
-               if (tx_status & 0x2000) {
-                       lp->stats.tx_packets++;
-                       lp->stats.collisions += tx_status & 0xf;
-                       dev->tbusy = 0;
-                       mark_bh(NET_BH);        /* Inform upper layers. */
-               } else {
-                       lp->stats.tx_errors++;
-                       if (tx_status & 0x0600)  lp->stats.tx_carrier_errors++;
-                       if (tx_status & 0x0100)  lp->stats.tx_fifo_errors++;
-                       if (!(tx_status & 0x0040))  lp->stats.tx_heartbeat_errors++;
-                       if (tx_status & 0x0020)  lp->stats.tx_aborted_errors++;
-               }
-               if (net_debug > 5)
-                       printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
-               lp->tx_reap += TX_BUF_SIZE;
-               if (lp->tx_reap > TX_BUF_END - TX_BUF_SIZE)
-                       lp->tx_reap = TX_BUF_START;
-               if (++boguscount > 4)
-                       break;
-       }
+       ioaddr = dev->base_addr;
 
-       if (status & 0x4000) { /* Packet received. */
-               if (net_debug > 5)
-                       printk("Received packet, rx_head %04x.\n", lp->rx_head);
-               eexp_rx(dev);
-       }
+       outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
+       old_rp = inw(ioaddr+READ_PTR);
+       old_wp = inw(ioaddr+WRITE_PTR);
+       status = inw(ioaddr+SCB_STATUS);
+       ack_cmd = SCB_ack(status);
 
-       /* Acknowledge the interrupt sources. */
-       ack_cmd = status & 0xf000;
-
-       if ((status & 0x0700) != 0x0200  &&  dev->start) {
-               short saved_write_ptr = inw(ioaddr + WRITE_PTR);
-               if (net_debug > 1)
-                       printk("%s: Command unit stopped, status %04x, restarting.\n",
-                                  dev->name, status);
-               /* If this ever occurs we must re-write the idle loop, reset
-                  the Tx list, and do a complete restart of the command unit. */
-               outw(IDLELOOP, ioaddr + WRITE_PTR);
-               outw(0, ioaddr);
-               outw(CmdNOp, ioaddr);
-               outw(IDLELOOP, ioaddr);
-               outw(IDLELOOP, SCB_CBL);
-               lp->tx_cmd_link = IDLELOOP + 4;
-               lp->tx_head = lp->tx_reap = TX_BUF_START;
-               /* Restore the saved write pointer. */
-               outw(saved_write_ptr, ioaddr + WRITE_PTR);
-               ack_cmd |= CUC_START;
+       if (started==0 && SCB_complete(status)) 
+       {
+               if (SCB_CUstat(status)==2) 
+                       while (SCB_CUstat(inw(ioaddr+SCB_STATUS))==2);
+               started=1;
+               outw(lp->tx_link,ioaddr+SCB_CBL);
+               outw(RX_BUF_START,ioaddr+SCB_RFA);
+               ack_cmd |= SCB_CUstart | SCB_RUstart;
+       }
+       else if (started) 
+       {
+               unsigned short txstatus;
+               txstatus = eexp_hw_lasttxstat(dev);
+       }
+  
+       if (SCB_rxdframe(status)) 
+       {
+               eexp_hw_rx(dev);
        }
 
-       if ((status & 0x0070) != 0x0040  &&  dev->start) {
-               short saved_write_ptr = inw(ioaddr + WRITE_PTR);
-               /* The Rx unit is not ready, it must be hung.  Restart the receiver by
-                  initializing the rx buffers, and issuing an Rx start command. */
+       if ((started&2)!=0 && SCB_RUstat(status)!=4) 
+       {
+               printk("%s: RU stopped status %04x, restarting...\n",
+                       dev->name,status);
                lp->stats.rx_errors++;
-               if (net_debug > 1) {
-                       int cur_rxbuf = RX_BUF_START;
-                       printk("%s: Rx unit stopped status %04x rx head %04x tail %04x.\n",
-                                  dev->name, status, lp->rx_head, lp->rx_tail);
-                       while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE) {
-                               int i;
-                               printk("  Rx buf at %04x:", cur_rxbuf);
-                               outw(cur_rxbuf, ioaddr + READ_PTR);
-                               for (i = 0; i < 0x20; i += 2)
-                                       printk(" %04x", inw(ioaddr));
-                               printk(".\n");
-                               cur_rxbuf += RX_BUF_SIZE;
+               eexp_hw_rxinit(dev);
+               outw(RX_BUF_START,ioaddr+SCB_RFA);
+               ack_cmd |= SCB_RUstart;
+       } 
+       else if (started==1 && SCB_RUstat(status)==4) 
+               started|=2;
+
+       outw(ack_cmd,ioaddr+SCB_CMD);
+       outb(0,ioaddr+SIGNAL_CA);
+       outw(old_rp,ioaddr+READ_PTR);
+       outw(old_wp,ioaddr+WRITE_PTR);
+       outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
+       return;
+}
+
+/*
+ * Hardware access functions
+ */
+
+/*
+ * Check all the receive buffers, and hand any received packets
+ * to the upper levels. Basic sanity check on each frame
+ * descriptor
+ */
+static void eexp_hw_rx(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       unsigned short ioaddr = dev->base_addr;
+       unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+       unsigned short old_rp = inw(ioaddr+READ_PTR);
+       unsigned short rx_block = lp->rx_first;
+       unsigned short boguscount = NUM_RX_BUFS;
+
+#if NET_DEBUG > 6
+       printk("%s: eexp_hw_rx()\n", dev->name);
+#endif
+
+       while (outw(rx_block,ioaddr+READ_PTR),boguscount--) 
+       {
+               unsigned short status = inw(ioaddr);
+               unsigned short rfd_cmd = inw(ioaddr);
+               unsigned short rx_next = inw(ioaddr);
+               unsigned short pbuf = inw(ioaddr);
+               unsigned short pkt_len;
+
+               if (FD_Done(status)) 
+               {
+                       outw(pbuf,ioaddr+READ_PTR);
+                       pkt_len = inw(ioaddr);
+
+                       if (rfd_cmd!=0x0000 || pbuf!=rx_block+0x16
+                               || (pkt_len & 0xc000)!=0xc000) 
+                       {
+                               printk("%s: Rx frame at %04x corrupted, status %04x, cmd %04x, "
+                                       "next %04x, pbuf %04x, len %04x\n",dev->name,rx_block,
+                                       status,rfd_cmd,rx_next,pbuf,pkt_len);
+                               eexp_hw_rxmap(dev,rx_block);
+                               boguscount++;
+                               continue;
+                       }
+                       else if (!FD_OK(status)) 
+                       {
+                               lp->stats.rx_errors++;
+                               if (FD_CRC(status)) 
+                                       lp->stats.rx_crc_errors++;
+                               if (FD_Align(status))
+                                       lp->stats.rx_frame_errors++;
+                               if (FD_Resrc(status))
+                                       lp->stats.rx_fifo_errors++;
+                               if (FD_DMA(status))
+                                       lp->stats.rx_over_errors++;
+                               if (FD_Short(status))
+                                       lp->stats.rx_length_errors++;
                        }
+                       else
+                       {
+                               struct sk_buff *skb;
+                               pkt_len &= 0x3fff;
+                               skb = dev_alloc_skb(pkt_len+16);
+                               if (skb == NULL) 
+                               {
+                                       printk("%s: Memory squeeze, dropping packet\n",dev->name);
+                                       lp->stats.rx_dropped++;
+                                       break;
+                               }
+                               skb->dev = dev;
+                               skb_reserve(skb, 2);
+                               outw(pbuf+10,ioaddr+READ_PTR);
+                               insw(ioaddr,skb_put(skb,pkt_len),(pkt_len+1)>>1);
+                               skb->protocol = eth_type_trans(skb,dev);
+                               netif_rx(skb);
+                               lp->stats.rx_packets++;
+                       }
+                       outw(rx_block,ioaddr+WRITE_PTR);
+                       outw(0x0000,ioaddr);
+                       outw(0x0000,ioaddr);
                }
-               init_rx_bufs(dev);
-               outw(RX_BUF_START, SCB_RFA);
-               outw(saved_write_ptr, ioaddr + WRITE_PTR);
-               ack_cmd |= RX_START;
+               rx_block = rx_next;
        }
+       outw(old_rp,ioaddr+READ_PTR);
+       outw(old_wp,ioaddr+WRITE_PTR);
+}
 
-       outw(ack_cmd, ioaddr + SCB_CMD);
-       outb(0, ioaddr + SIGNAL_CA);
+/*
+ * Hand a packet to the card for transmission
+ * If we get here, we MUST have already checked
+ * to make sure there is room in the transmit
+ * buffer region
+ */
 
-    if (net_debug > 5) {
-               printk("%s: EExp exiting interrupt, status %4.4x.\n", dev->name,
-                          inw(ioaddr + SCB_CMD));
-    }
-       /* Enable the 82586's input to the interrupt line. */
-       outb(irqrmap[dev->irq] | 0x08, ioaddr + SET_IRQ);
-       return;
+static void eexp_hw_tx(struct device *dev, unsigned short *buf, unsigned short len)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       unsigned short ioaddr = dev->base_addr;
+       unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+
+       outw(lp->tx_head,ioaddr+WRITE_PTR);
+       outw(0x0000,ioaddr);
+       outw(Cmd_INT|Cmd_Xmit,ioaddr);
+       outw(lp->tx_head+0x08,ioaddr);
+       outw(lp->tx_head+0x0e,ioaddr);
+       outw(0x0000,ioaddr);
+       outw(0x0000,ioaddr);
+       outw(lp->tx_head+0x08,ioaddr);
+       outw(0x8000|len,ioaddr);
+       outw(-1,ioaddr);
+       outw(lp->tx_head+0x16,ioaddr);
+       outw(0,ioaddr);
+       outsw(ioaddr,buf,(len+1)>>1);
+       outw(lp->tx_tail+0x0c,ioaddr+WRITE_PTR);
+       outw(lp->tx_head,ioaddr);
+       dev->trans_start = jiffies;
+       lp->tx_tail = lp->tx_head;
+       if (lp->tx_head==TX_BUF_START+((NUM_TX_BUFS-1)*TX_BUF_SIZE)) 
+               lp->tx_head = TX_BUF_START;
+       else 
+               lp->tx_head += TX_BUF_SIZE;
+       if (lp->tx_head != lp->tx_reap) 
+               dev->tbusy = 0;
+       outw(old_wp,ioaddr+WRITE_PTR);
 }
 
-static int
-eexp_close(struct device *dev)
+/*
+ * Sanity check the suspected EtherExpress card
+ * Read hardware address, reset card, size memory and
+ * initialize buffer memory pointers. These should
+ * probably be held in dev->priv, incase someone has 2
+ * differently configured cards in their box (Arghhh!)
+ */
+
+static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
 {
-       int ioaddr = dev->base_addr;
+       unsigned short hw_addr[3];
+       int i;
+       unsigned char *chw_addr = (unsigned char *)hw_addr;
 
-       dev->tbusy = 1;
-       dev->start = 0;
+       printk("%s: EtherExpress at %#x, ",dev->name,ioaddr);
 
-       /* Flush the Tx and disable Rx. */
-       outw(RX_SUSPEND | CUC_SUSPEND, ioaddr + SCB_CMD);
-       outb(0, ioaddr + SIGNAL_CA);
+       hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
+       hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
+       hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
 
-       /* Disable the physical interrupt line. */
-       outb(0, ioaddr + SET_IRQ);
+       if (hw_addr[2]!=0x00aa || ((hw_addr[1] & 0xff00)!=0x0000)) 
+       {
+               printk("rejected: invalid address %04x%04x%04x\n",
+                       hw_addr[2],hw_addr[1],hw_addr[0]);
+               return ENODEV;
+       }
 
-       free_irq(dev->irq, NULL);
+       dev->base_addr = ioaddr;
+       for ( i=0 ; i<6 ; i++ ) 
+               dev->dev_addr[i] = chw_addr[5-i];
 
-       irq2dev_map[dev->irq] = 0;
+       {
+               char irqmap[]={0, 9, 3, 4, 5, 10, 11, 0};
+               char *ifmap[]={"AUI", "BNC", "10baseT"};
+               enum iftype {AUI=0, BNC=1, TP=2};
+               unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
 
-       /* Update the statistics here. */
+               dev->irq = irqmap[setupval>>13];
+               dev->if_port = !(setupval & 0x1000) ? AUI :
+                       eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TP : BNC;
 
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
+               printk("IRQ %d, Interface %s, ",dev->irq,ifmap[dev->if_port]);
 
-/* Get the current statistics. This may be called with the card open or
-   closed. */
-static struct enet_statistics *
-eexp_get_stats(struct device *dev)
-{
-       struct net_local *lp = (struct net_local *)dev->priv;
+               outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+               outb(0,ioaddr+SET_IRQ);
+       }
 
-       /* ToDo: decide if there are any useful statistics from the SCB. */
+       eexp_hw_ASICrst(dev);
 
-       return &lp->stats;
-}
+       {
+               unsigned short i586mso = 0x023e;
+               unsigned short old_wp,old_rp,old_a0,old_a1;
+               unsigned short a0_0,a1_0,a0_1,a1_1;
+
+               old_wp = inw(ioaddr+WRITE_PTR);
+               old_rp = inw(ioaddr+READ_PTR);
+               outw(0x8000+i586mso,ioaddr+READ_PTR);
+               old_a1 = inw(ioaddr);
+               outw(i586mso,ioaddr+READ_PTR);
+               old_a0 = inw(ioaddr);
+               outw(i586mso,ioaddr+WRITE_PTR);
+               outw(0x55aa,ioaddr);
+               outw(i586mso,ioaddr+READ_PTR);
+               a0_0 = inw(ioaddr);
+               outw(0x8000+i586mso,ioaddr+WRITE_PTR);
+               outw(0x5a5a,ioaddr);
+               outw(0x8000+i586mso,ioaddr+READ_PTR);
+               a1_0 = inw(ioaddr);
+               outw(i586mso,ioaddr+READ_PTR);
+               a0_1 = inw(ioaddr);
+               outw(i586mso,ioaddr+WRITE_PTR);
+               outw(0x1234,ioaddr);
+               outw(0x8000+i586mso,ioaddr+READ_PTR);
+               a1_1 = inw(ioaddr);
+
+               if ((a0_0 != a0_1) || (a1_0 != a1_1) ||
+                       (a1_0 != 0x5a5a) || (a0_0 != 0x55aa)) 
+               {
+                       printk("32k\n");
+                       RX_BUF_END = 0x7ff6;
+               }
+               else
+               {
+                       printk("64k\n");
+                       NUM_TX_BUFS = 8;
+                       RX_BUF_START = TX_BUF_START + (NUM_TX_BUFS*TX_BUF_SIZE);
+                       RX_BUF_END = 0xfff6;
+               }
 
-/* Set or clear the multicast filter for this adaptor.
- */
-static void
-set_multicast_list(struct device *dev)
-{
-/* This doesn't work yet */
-#if 0
-       short ioaddr = dev->base_addr;
-       if (num_addrs < 0) {
-               /* Not written yet, this requires expanding the init_words config
-                  cmd. */
-       } else if (num_addrs > 0) {
-               /* Fill in the SET_MC_CMD with the number of address bytes, followed
-                  by the list of multicast addresses to be accepted. */
-               outw(SET_MC_CMD + 6, ioaddr + WRITE_PTR);
-               outw(num_addrs * 6, ioaddr);
-               outsw(ioaddr, addrs, num_addrs*3);              /* 3 = addr len in words */
-               /* We must trigger a whole 586 reset due to a bug. */
-       } else {
-               /* Not written yet, this requires expanding the init_words config
-                  cmd. */
-               outw(99, ioaddr);               /* Disable promiscuous mode, use normal mode */
+               outw(0x8000+i586mso,ioaddr+WRITE_PTR);
+               outw(old_a1,ioaddr);
+               outw(i586mso,ioaddr+WRITE_PTR);
+               outw(old_a0,ioaddr);
+               outw(old_wp,ioaddr+WRITE_PTR);
+               outw(old_rp,ioaddr+READ_PTR);
        }
-#endif
-}
-
-/* The horrible routine to read a word from the serial EEPROM. */
+  
+       if (net_debug) 
+               printk(version);
 
-/* The delay between EEPROM clock transitions. */
-#define eeprom_delay() { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }}
-#define EE_READ_CMD (6 << 6)
+       dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+       memset(dev->priv, 0, sizeof(struct net_local));
+       dev->open = eexp_open;
+       dev->stop = eexp_close;
+       dev->hard_start_xmit = eexp_xmit;
+       dev->get_stats = eexp_stats;
+       ether_setup(dev);
+       return 0;
+}
 
-int
-read_eeprom(int ioaddr, int location)
+/*
+ *     Read a word from eeprom location (0-63?)
+ */
+static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location)
 {
+       unsigned short cmd = 0x180|(location&0x7f);
+       unsigned short rval = 0,wval = EC_CS|i586_RST;
        int i;
-       unsigned short retval = 0;
-       short ee_addr = ioaddr + EEPROM_Ctrl;
-       int read_cmd = location | EE_READ_CMD;
-       short ctrl_val = EE_CS | _586_RESET;
-       
-       outb(ctrl_val, ee_addr);
-       
-       /* Shift the read command bits out. */
-       for (i = 8; i >= 0; i--) {
-               short outval = (read_cmd & (1 << i)) ? ctrl_val | EE_DATA_WRITE
-                       : ctrl_val;
-               outb(outval, ee_addr);
-               outb(outval | EE_SHIFT_CLK, ee_addr);   /* EEPROM clock tick. */
+       outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
+       for ( i=0x100 ; i ; i>>=1 ) 
+       {
+               if (cmd&i) 
+                       wval |= EC_Wr;
+               else 
+                       wval &= ~EC_Wr;
+
+               outb(wval,ioaddr+EEPROM_Ctrl);
+               outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
                eeprom_delay();
-               outb(outval, ee_addr);  /* Finish EEPROM a clock tick. */
+               outb(wval,ioaddr+EEPROM_Ctrl);
+               eeprom_delay();
+       }       
+       wval &= ~EC_Wr;
+       outb(wval,ioaddr+EEPROM_Ctrl);
+       for ( i=0x8000 ; i ; i>>=1 ) 
+       {
+               outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
+               eeprom_delay();
+               if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd) 
+                       rval |= i;
+               outb(wval,ioaddr+EEPROM_Ctrl);
                eeprom_delay();
        }
-       outb(ctrl_val, ee_addr);
-       
-       for (i = 16; i > 0; i--) {
-               outb(ctrl_val | EE_SHIFT_CLK, ee_addr);  eeprom_delay();
-               retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
-               outb(ctrl_val, ee_addr);  eeprom_delay();
-       }
-
-       /* Terminate the EEPROM access. */
-       ctrl_val &= ~EE_CS;
-       outb(ctrl_val | EE_SHIFT_CLK, ee_addr);
+       wval &= ~EC_CS;
+       outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
        eeprom_delay();
-       outb(ctrl_val, ee_addr);
+       outb(wval,ioaddr+EEPROM_Ctrl);
        eeprom_delay();
-       return retval;
+       return rval;
 }
 
-static void
-init_82586_mem(struct device *dev)
+/*
+ * Reap tx buffers and return last transmit status.
+ * if ==0 then either:
+ *    a) we're not transmitting anything, so why are we here?
+ *    b) we've died.
+ * otherwise, Stat_Busy(return) means we've still got some packets
+ * to transmit, Stat_Done(return) means our buffers should be empty
+ * again
+ */
+
+static unsigned short eexp_hw_lasttxstat(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
-       short ioaddr = dev->base_addr;
-
-       /* Enable loopback to protect the wire while starting up.
-          This is Superstition From Crynwr. */
-       outb(inb(ioaddr + Config) | 0x02, ioaddr + Config);
-
-       /* Hold the 586 in reset during the memory initialization. */
-       outb(_586_RESET, ioaddr + EEPROM_Ctrl);
-
-       /* Place the write pointer at 0xfff6 (address-aliased to 0xfffff6). */
-       outw(0xfff6, ioaddr + WRITE_PTR);
-       outsw(ioaddr, init_words, sizeof(init_words)>>1);
-
-       /* Fill in the station address. */
-       outw(SA_OFFSET, ioaddr + WRITE_PTR);
-       outsw(ioaddr, dev->dev_addr, 3);
+       unsigned short ioaddr = dev->base_addr;
+       unsigned short old_rp = inw(ioaddr+READ_PTR);
+       unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+       unsigned short tx_block = lp->tx_reap;
+       unsigned short status;
+  
+       if (!test_bit(0,(void *)&dev->tbusy) && lp->tx_head==lp->tx_reap) 
+               return 0x0000;
+
+       do
+       {
+               outw(tx_block,ioaddr+READ_PTR);
+               status = inw(ioaddr);
+               if (!Stat_Done(status)) 
+               {
+                       lp->tx_link = tx_block;
+                       outw(old_rp,ioaddr+READ_PTR);
+                       outw(old_wp,ioaddr+WRITE_PTR);
+                       return status;
+               }
+               else 
+               {
+                       lp->last_tx_restart = 0;
+                       lp->stats.collisions += Stat_NoColl(status);
+                       if (!Stat_OK(status)) 
+                       {
+                               if (Stat_Abort(status)) 
+                                       lp->stats.tx_aborted_errors++;
+                               if (Stat_TNoCar(status) || Stat_TNoCTS(status)) 
+                                       lp->stats.tx_carrier_errors++;
+                               if (Stat_TNoDMA(status)) 
+                                       lp->stats.tx_fifo_errors++;
+                       }
+                       else
+                               lp->stats.tx_packets++;
+               }
+               if (tx_block == TX_BUF_START+((NUM_TX_BUFS-1)*TX_BUF_SIZE)) 
+                       lp->tx_reap = tx_block = TX_BUF_START;
+               else
+                       lp->tx_reap = tx_block += TX_BUF_SIZE;
+               dev->tbusy = 0;
+               mark_bh(NET_BH);
+       }
+       while (lp->tx_reap != lp->tx_head);
 
-       /* The Tx-block list is written as needed.  We just set up the values. */
-#ifdef initial_text_tx
-       lp->tx_cmd_link = DUMP_DATA + 4;
-#else
-       lp->tx_cmd_link = IDLELOOP + 4;
-#endif
-       lp->tx_head = lp->tx_reap = TX_BUF_START;
+       lp->tx_link = lp->tx_tail + 0x08;
+       outw(old_rp,ioaddr+READ_PTR);
+       outw(old_wp,ioaddr+WRITE_PTR);
 
-       init_rx_bufs(dev);
+       return status;
+}
 
-       /* Start the 586 by releasing the reset line. */
-       outb(0x00, ioaddr + EEPROM_Ctrl);
+/* 
+ * This should never happen. It is called when some higher
+ * routine detects the CU has stopped, to try and restart
+ * it from the last packet we knew we were working on,
+ * or the idle loop if we had finished for the time.
+ */
 
-       /* This was time consuming to track down: you need to give two channel
-          attention signals to reliably start up the i82586. */
-       outb(0, ioaddr + SIGNAL_CA);
+static void eexp_hw_txrestart(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       unsigned short ioaddr = dev->base_addr;
+  
+       lp->last_tx_restart = lp->tx_link;
+       outw(lp->tx_link,ioaddr+SCB_CBL);
+       outw(SCB_CUstart,ioaddr+SCB_CMD);
+       outw(0,ioaddr+SCB_STATUS);
+       outb(0,ioaddr+SIGNAL_CA);
 
        {
-               int boguscnt = 50;
-               while (inw(ioaddr + SCB_STATUS) == 0)
-                       if (--boguscnt == 0) {
-                               printk("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
-                                          dev->name, inw(ioaddr + SCB_STATUS), inw(ioaddr + SCB_CMD));
-                               break;
+               unsigned short boguscount=50,failcount=5;
+               while (!inw(ioaddr+SCB_STATUS)) 
+               {
+                       if (!--boguscount) 
+                       {
+                               if (--failcount) 
+                               {
+                                       printk("%s: CU start timed out, status %04x, cmd %04x\n",
+                                               dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD));
+                                       outw(lp->tx_link,ioaddr+SCB_CBL);
+                                       outw(0,ioaddr+SCB_STATUS);
+                                       outw(SCB_CUstart,ioaddr+SCB_CMD);
+                                       outb(0,ioaddr+SIGNAL_CA);
+                                       boguscount = 100;
+                               }
+                               else
+                               {
+                                       printk("%s: Failed to restart CU, resetting board...\n",dev->name);
+                                       eexp_hw_init586(dev);
+                                       dev->tbusy = 0;
+                                       mark_bh(NET_BH);
+                                       return;
+                               }
                        }
-               /* Issue channel-attn -- the 82586 won't start without it. */
-               outb(0, ioaddr + SIGNAL_CA);
+               }
        }
-
-       /* Disable loopback. */
-       outb(inb(ioaddr + Config) & ~0x02, ioaddr + Config);
-       if (net_debug > 4)
-               printk("%s: Initialized 82586, status %04x.\n", dev->name,
-                          inw(ioaddr + SCB_STATUS));
-       return;
 }
 
-/* Initialize the Rx-block list. */
-static void init_rx_bufs(struct device *dev)
+/*
+ * Writes down the list of transmit buffers into card
+ * memory. Initial seperate, repeated transmits link
+ * them into a circular list, such that the CU can
+ * be constantly active, and unlink them as we reap
+ * transmitted packet buffers, so the CU doesn't loop
+ * and endlessly transmit packets. (Try hacking the driver
+ * to send continuous broadcast messages, say ARP requests
+ * on a subnet with Windows boxes running on Novell and
+ * LAN Workplace with EMM386. Amusing to watch them all die
+ * horribly leaving the Linux boxes up!)
+ */
+
+static void eexp_hw_txinit(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
-       short ioaddr = dev->base_addr;
-
-       int cur_rxbuf = lp->rx_head = RX_BUF_START;
-       
-       /* Initialize each Rx frame + data buffer. */
-       do {    /* While there is room for one more. */
-               outw(cur_rxbuf, ioaddr + WRITE_PTR);
-               outw(0x0000, ioaddr);                           /* Status */
-               outw(0x0000, ioaddr);                           /* Command */
-               outw(cur_rxbuf + RX_BUF_SIZE, ioaddr); /* Link */
-               outw(cur_rxbuf + 22, ioaddr);           /* Buffer offset */
-               outw(0xFeed, ioaddr);                           /* Pad for dest addr. */
-               outw(0xF00d, ioaddr);
-               outw(0xF001, ioaddr);
-               outw(0x0505, ioaddr);                           /* Pad for source addr. */
-               outw(0x2424, ioaddr);
-               outw(0x6565, ioaddr);
-               outw(0xdeaf, ioaddr);                           /* Pad for protocol. */
-
-               outw(0x0000, ioaddr);                           /* Buffer: Actual count */
-               outw(-1, ioaddr);                                       /* Buffer: Next (none). */
-               outw(cur_rxbuf + 0x20, ioaddr);         /* Buffer: Address low */
-               outw(0x0000, ioaddr);
-               /* Finally, the number of bytes in the buffer. */
-               outw(0x8000 + RX_BUF_SIZE-0x20, ioaddr);
-               
-               lp->rx_tail = cur_rxbuf;
-               cur_rxbuf += RX_BUF_SIZE;
-       } while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
-       
-       /* Terminate the list by setting the EOL bit, and wrap the pointer to make
-          the list a ring. */
-       outw(lp->rx_tail + 2, ioaddr + WRITE_PTR);
-       outw(0xC000, ioaddr);                                   /* Command, mark as last. */
-       outw(lp->rx_head, ioaddr);                              /* Link */
+       unsigned short ioaddr = dev->base_addr;
+       unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+       unsigned short tx_block = TX_BUF_START;
+       unsigned short curtbuf;
+
+       for ( curtbuf=0 ; curtbuf<NUM_TX_BUFS ; curtbuf++ ) 
+       {
+               outw(tx_block,ioaddr+WRITE_PTR);
+               outw(0x0000,ioaddr);
+               outw(Cmd_INT|Cmd_Xmit,ioaddr);
+               outw(tx_block+0x08,ioaddr);
+               outw(tx_block+0x0e,ioaddr);
+               outw(0x0000,ioaddr);
+               outw(0x0000,ioaddr);
+               outw(tx_block+0x08,ioaddr);
+               outw(0x8000,ioaddr);
+               outw(-1,ioaddr);
+               outw(tx_block+0x16,ioaddr);
+               outw(0x0000,ioaddr);
+               tx_block += TX_BUF_SIZE;
+       }
+       lp->tx_head = TX_BUF_START;
+       lp->tx_reap = TX_BUF_START;
+       lp->tx_tail = tx_block - TX_BUF_SIZE;
+       lp->tx_link = lp->tx_tail + 0x08;
+       RX_BUF_START = tx_block;
+       outw(old_wp,ioaddr+WRITE_PTR);
 }
 
-static void
-hardware_send_packet(struct device *dev, void *buf, short length)
+/* is this a standard test pattern, or dbecker randomness? */
+
+unsigned short rx_words[] = 
+{
+       0xfeed,0xf00d,0xf001,0x0505,0x2424,0x6565,0xdeaf
+};
+
+/*
+ * Write the circular list of receive buffer descriptors to
+ * card memory. Note, we no longer mark the end of the list,
+ * so if all the buffers fill up, the 82586 will loop until
+ * we free one. This may sound dodgy, but it works, and
+ * it makes the error detection in the interrupt handler
+ * a lot simpler.
+ */
+
+static void eexp_hw_rxinit(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
-       short ioaddr = dev->base_addr;
-       short tx_block = lp->tx_head;
-
-       /* Set the write pointer to the Tx block, and put out the header. */
-       outw(tx_block, ioaddr + WRITE_PTR);
-       outw(0x0000, ioaddr);           /* Tx status */
-       outw(CMD_INTR|CmdTx, ioaddr);           /* Tx command */
-       outw(tx_block+16, ioaddr);      /* Next command is a NoOp. */
-       outw(tx_block+8, ioaddr);       /* Data Buffer offset. */
-
-       /* Output the data buffer descriptor. */
-       outw(length | 0x8000, ioaddr); /* Byte count parameter. */
-       outw(-1, ioaddr);                       /* No next data buffer. */
-       outw(tx_block+22, ioaddr);      /* Buffer follows the NoOp command. */
-       outw(0x0000, ioaddr);           /* Buffer address high bits (always zero). */
-
-       /* Output the Loop-back NoOp command. */
-       outw(0x0000, ioaddr);           /* Tx status */
-       outw(CmdNOp, ioaddr);           /* Tx command */
-       outw(tx_block+16, ioaddr);      /* Next is myself. */
-
-       /* Output the packet using the write pointer.
-          Hmmm, it feels a little like a 3c501! */
-       outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-
-       /* Set the old command link pointing to this send packet. */
-       outw(lp->tx_cmd_link, ioaddr + WRITE_PTR);
-       outw(tx_block, ioaddr);
-       lp->tx_cmd_link = tx_block + 20;
-
-       /* Set the next free tx region. */
-       lp->tx_head = tx_block + TX_BUF_SIZE;
-       if (lp->tx_head > TX_BUF_END - TX_BUF_SIZE)
-               lp->tx_head = TX_BUF_START;
+       unsigned short ioaddr = dev->base_addr;
+       unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+       unsigned short rx_block = RX_BUF_START;
 
-    if (net_debug > 4) {
-               printk("%s: EExp @%x send length = %d, tx_block %3x, next %3x, "
-                          "reap %4x status %4.4x.\n", dev->name, ioaddr, length,
-                          tx_block, lp->tx_head, lp->tx_reap, inw(ioaddr + SCB_STATUS));
-    }
+       NUM_RX_BUFS = 0;
+       lp->rx_first = rx_block;
+       do 
+       {
+               NUM_RX_BUFS++;
+               outw(rx_block,ioaddr+WRITE_PTR);
+               outw(0x0000,ioaddr);
+               outw(0x0000,ioaddr);
+               outw(rx_block+RX_BUF_SIZE,ioaddr);
+               outw(rx_block+0x16,ioaddr);
+               outsw(ioaddr, rx_words, sizeof(rx_words)>>1);
+               outw(0x8000,ioaddr);
+               outw(-1,ioaddr);
+               outw(rx_block+0x20,ioaddr);
+               outw(0x0000,ioaddr);
+               outw(0x8000|(RX_BUF_SIZE-0x20),ioaddr);
+               lp->rx_last = rx_block;
+               rx_block += RX_BUF_SIZE;
+       } while (rx_block <= RX_BUF_END-RX_BUF_SIZE);
+
+       outw(lp->rx_last+4,ioaddr+WRITE_PTR);
+       outw(lp->rx_first,ioaddr);
+
+       outw(old_wp,ioaddr+WRITE_PTR);
+}
 
-       if (lp->tx_head != lp->tx_reap)
-               dev->tbusy = 0;
+/*
+ * This really ought not to be necessary now. Repairs a single
+ * damaged receive buffer. If buffer memory is getting bashed
+ * enough to call this, we probably have bigger problems that can
+ * be fixed here.
+ */
+static void eexp_hw_rxmap(struct device *dev, unsigned short rx_buf)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       unsigned short ioaddr = dev->base_addr;
+       unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+
+       outw(rx_buf,ioaddr+WRITE_PTR);
+       outw(0x0000,ioaddr);
+       outw(0x0000,ioaddr);
+       outw((rx_buf==lp->rx_last)?lp->rx_first:(rx_buf+RX_BUF_SIZE),ioaddr);
+       outw(rx_buf+0x16,ioaddr);
+       outsw(ioaddr, rx_words, sizeof(rx_words)>>1);
+       outw(0x8000,ioaddr);
+       outw(-1,ioaddr);
+       outw(rx_buf+0x20,ioaddr);
+       outw(0x0000,ioaddr);
+       outw(0x8000|(RX_BUF_SIZE-0x20),ioaddr);
+       outw(old_wp,ioaddr+WRITE_PTR);
 }
 
-static void
-eexp_rx(struct device *dev)
+/*
+ * Reset the 586, fill memory (including calls to
+ * eexp_hw_[(rx)(tx)]init()) unreset, and start
+ * the configuration sequence. We don't wait for this
+ * to finish, but allow the interrupt handler to start
+ * the CU and RU for us. We can't start the receive/
+ * transmission system up before we know that the
+ * hardware is configured correctly
+ */
+static void eexp_hw_init586(struct device *dev)
 {
        struct net_local *lp = (struct net_local *)dev->priv;
-       short ioaddr = dev->base_addr;
-       short saved_write_ptr = inw(ioaddr + WRITE_PTR);
-       short rx_head = lp->rx_head;
-       short rx_tail = lp->rx_tail;
-       short boguscount = 10;
-       short frame_status;
-
-       /* Set the read pointer to the Rx frame. */
-       outw(rx_head, ioaddr + READ_PTR);
-       while ((frame_status = inw(ioaddr)) < 0) {              /* Command complete */
-               short rfd_cmd = inw(ioaddr);
-               short next_rx_frame = inw(ioaddr);
-               short data_buffer_addr = inw(ioaddr);
-               short pkt_len;
-               
-               /* Set the read pointer the data buffer. */
-               outw(data_buffer_addr, ioaddr + READ_PTR);
-               pkt_len = inw(ioaddr);
-
-               if (rfd_cmd != 0  ||  data_buffer_addr != rx_head + 22
-                       ||  (pkt_len & 0xC000) != 0xC000) {
-                       printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x"
-                                  "next %04x data-buf @%04x %04x.\n", dev->name, rx_head,
-                                  frame_status, rfd_cmd, next_rx_frame, data_buffer_addr,
-                                  pkt_len);
-               } else if ((frame_status & 0x2000) == 0) {
-                       /* Frame Rxed, but with error. */
-                       lp->stats.rx_errors++;
-                       if (frame_status & 0x0800) lp->stats.rx_crc_errors++;
-                       if (frame_status & 0x0400) lp->stats.rx_frame_errors++;
-                       if (frame_status & 0x0200) lp->stats.rx_fifo_errors++;
-                       if (frame_status & 0x0100) lp->stats.rx_over_errors++;
-                       if (frame_status & 0x0080) lp->stats.rx_length_errors++;
-               } else {
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-
-                       pkt_len &= 0x3fff;
-                       skb = dev_alloc_skb(pkt_len+2);
-                       if (skb == NULL) {
-                               printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-                               lp->stats.rx_dropped++;
-                               break;
-                       }
-                       skb->dev = dev;
-                       skb_reserve(skb,2);
+       unsigned short ioaddr = dev->base_addr;
 
-                       outw(data_buffer_addr + 10, ioaddr + READ_PTR);
+       started = 0;
+       set_loopback;
 
-                       insw(ioaddr, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
-               
-                       skb->protocol=eth_type_trans(skb,dev);
-                       netif_rx(skb);
-                       lp->stats.rx_packets++;
-               }
+       outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+       outb(i586_RST,ioaddr+EEPROM_Ctrl);
 
-               /* Clear the status word and set End-of-List on the rx frame. */
-               outw(rx_head, ioaddr + WRITE_PTR);
-               outw(0x0000, ioaddr);
-               outw(0xC000, ioaddr);
-#ifndef final_version
-               if (next_rx_frame != rx_head + RX_BUF_SIZE
-                       && next_rx_frame != RX_BUF_START) {
-                       printk("%s: Rx next frame at %#x is %#x instead of %#x.\n", dev->name,
-                                  rx_head, next_rx_frame, rx_head + RX_BUF_SIZE);
-                       next_rx_frame = rx_head + RX_BUF_SIZE;
-                       if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE)
-                               next_rx_frame = RX_BUF_START;
+       {
+               unsigned short wcnt;
+               wcnt = 0;
+               outw(0,ioaddr+WRITE_PTR);
+               while ((wcnt+=2) != RX_BUF_END+12) 
+                       outw(0,ioaddr);
+       } 
+  
+       outw(RX_BUF_END,ioaddr+WRITE_PTR);
+       outsw(ioaddr, start_code, sizeof(start_code)>>1);
+       outw(CONF_HW_ADDR,ioaddr+WRITE_PTR);
+       outsw(ioaddr,dev->dev_addr,3);
+       eexp_hw_txinit(dev);
+       eexp_hw_rxinit(dev);
+       outw(0,ioaddr+WRITE_PTR);
+       outw(1,ioaddr);
+       outb(0,ioaddr+EEPROM_Ctrl);
+       outw(0,ioaddr+SCB_CMD);
+       outb(0,ioaddr+SIGNAL_CA);
+       {
+               unsigned short rboguscount=50,rfailcount=5;
+               while (outw(0,ioaddr+READ_PTR),inw(ioaddr)) 
+               {
+                       if (!--rboguscount) 
+                       {
+                               printk("%s: i82586 reset timed out, kicking...\n",
+                                       dev->name);
+                               outw(0,ioaddr+SCB_CMD);
+                               outb(0,ioaddr+SIGNAL_CA);
+                               rboguscount = 100;
+                               if (!--rfailcount) 
+                               {
+                                       printk("%s: i82586 not responding, giving up.\n",
+                                               dev->name);
+                                       return;
+                               }
+                       }
                }
-#endif
-               outw(rx_tail+2, ioaddr + WRITE_PTR);
-               outw(0x0000, ioaddr);   /* Clear the end-of-list on the prev. RFD. */
-
-#ifndef final_version
-               outw(rx_tail+4, ioaddr + READ_PTR);
-               if (inw(ioaddr) != rx_head) {
-                       printk("%s: Rx buf link mismatch, at %04x link %04x instead of %04x.\n",
-                                  dev->name, rx_tail, (outw(rx_tail+4, ioaddr + READ_PTR),inw(ioaddr)),
-                                  rx_head);
-                       outw(rx_head, ioaddr);
+       }
+
+       outw(CONF_LINK,ioaddr+SCB_CBL);
+       outw(0,ioaddr+SCB_STATUS);
+       outw(0xf000|SCB_CUstart,ioaddr+SCB_CMD);
+       outb(0,ioaddr+SIGNAL_CA);
+       {
+               unsigned short iboguscount=50,ifailcount=5;
+               while (!inw(ioaddr+SCB_STATUS)) 
+               {
+                       if (!--iboguscount) 
+                       {
+                               if (--ifailcount) 
+                               {
+                                       printk("%s: i82586 initialization timed out, status %04x, cmd %04x\n",
+                                               dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD));
+                                       outw(CONF_LINK,ioaddr+SCB_CBL);
+                                       outw(0,ioaddr+SCB_STATUS);
+                                       outw(0xf000|SCB_CUstart,ioaddr+SCB_CMD);
+                                       outb(0,ioaddr+SIGNAL_CA);
+                                       iboguscount = 100;
+                               }
+                               else 
+                               {
+                                       printk("%s: Failed to initialize i82586, giving up.\n",dev->name);
+                                       return;
+                               }
+                       }
                }
-#endif
+       }
+  
+       outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
+       clear_loopback;
+       lp->init_time = jiffies;
+       if (started) 
+               printk("%s: Uh? We haven't started yet\n",dev->name);
+       return;
+}
+
+/* 
+ * completely reset the EtherExpress hardware. We will most likely get
+ * an interrupt during this whether we want one or not. It is best,
+ * therefore, to call this while we don't have a request_irq() on.
+ */
+
+static void eexp_hw_ASICrst(struct device *dev)
+{
+       unsigned short ioaddr = dev->base_addr;
+       unsigned short wrval = 0x0001,succount=0,boguscount=500;
+
+       outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
 
-               rx_tail = rx_head;
-               rx_head = next_rx_frame;
-               if (--boguscount == 0)
-                       break;
-               outw(rx_head, ioaddr + READ_PTR);
+       set_loopback;  /* yet more paranoia - since we're resetting the ASIC
+                       * that controls this function, how can it possibly work?
+                        */
+       started = 0;
+       outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl);
+       while (succount<20) 
+       {
+               if (wrval == 0xffff) 
+                       wrval = 0x0001;
+               outw(0,ioaddr+WRITE_PTR);
+               outw(wrval,ioaddr);
+               outw(0,ioaddr+READ_PTR);
+               if (wrval++ == inw(ioaddr)) 
+                       succount++;
+               else 
+               {
+                       succount = 0;
+                       if (!boguscount--) 
+                       {
+                               boguscount = 500;
+                               printk("%s: Having problems resetting EtherExpress ASIC, continuing...\n",
+                                       dev->name);
+                               wrval = 0x0001;
+                               outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl);
+                       }
+               }
        }
-       
-       lp->rx_head = rx_head;
-       lp->rx_tail = rx_tail;
-       
-       /* Restore the original write pointer. */
-       outw(saved_write_ptr, ioaddr + WRITE_PTR);
+       outb(i586_RST,ioaddr+EEPROM_Ctrl);
 }
-\f
+
+/*
+ * MODULE stuff
+ */
+
 #ifdef MODULE
-static char devicename[9] = { 0, };
-static struct device dev_eexpress = {
-       devicename, /* device name is inserted by linux/drivers/net/net_init.c */
-       0, 0, 0, 0,
-       0, 0,
-       0, 0, 0, NULL, express_probe };
-       
-
-static int irq=0x300;
-static int io=0;       
-
-int
-init_module(void)
+
+static struct device dev_eexpress = 
 {
-       if (io == 0)
-               printk("eexpress: You should not use auto-probing with insmod!\n");
-       dev_eexpress.base_addr=io;
-       dev_eexpress.irq=irq;
-       if (register_netdev(&dev_eexpress) != 0)
+       "EExpress", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe 
+};
+
+int irq = 0;
+int io = 0;
+
+int init_module(void)
+{
+       dev_eexpress.base_addr = io;
+       dev_eexpress.irq = irq;
+       if (register_netdev(&dev_eexpress) != 0) 
                return -EIO;
        return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
        unregister_netdev(&dev_eexpress);
        kfree_s(dev_eexpress.priv,sizeof(struct net_local));
-       dev_eexpress.priv=NULL;
-
-       /* If we don't do this, we can't re-insmod it later. */
-       release_region(dev_eexpress.base_addr, EEXPRESS_IO_EXTENT);
+       dev_eexpress.priv = NULL;
 }
-#endif /* MODULE */
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c eexpress.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
- * End:
- */
+#endif
diff --git a/drivers/net/eth82586.h b/drivers/net/eth82586.h
new file mode 100644 (file)
index 0000000..852d298
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * eth82586.h: Intel EtherExpress defines
+ *
+ * Written 1995 by John Sullivan
+ * See eexpress.c for furthur details
+ * documentation and usage to do.
+ */
+
+/*
+ * EtherExpress card register addresses
+ * as offsets from the base IO region (dev->base_addr)
+ */
+
+#define DATAPORT 0x0000
+#define WRITE_PTR 0x0002
+#define READ_PTR 0x0004
+#define SIGNAL_CA 0x0006
+#define SET_IRQ 0x0007
+#define SM_PTR 0x0008
+#define MEM_Ctrl 0x000b
+#define MEM_Page_Ctrl 0x000c
+#define Config 0x000d
+#define EEPROM_Ctrl 0x000e
+#define ID_PORT 0x000f
+
+/*
+ * offset to shadowed memory, 0 <= x <= 31. We don't use this yet,
+ * but may in the future. Is shadow memory access any faster than
+ * dataport access?
+ */
+#define SM_ADDR(x) (0x4000+((x&0x10)<<10)+(x&0xf))
+
+/* Always mirrors eexp-memory at 0x0008-0x000f */
+#define SCB_STATUS 0xc008
+#define SCB_CMD 0xc00a
+#define SCB_CBL 0xc00c
+#define SCB_RFA 0xc00e
+
+
+
+/*
+ * card register defines
+ */
+
+/* SET_IRQ */
+#define SIRQ_en 0x08
+#define SIRQ_dis 0x00
+
+/* Config */
+#define set_loopback outb(inb(ioaddr+Config)|0x02,ioaddr+Config)
+#define clear_loopback outb(inb(ioaddr+Config)&0xfd,ioaddr+Config)
+
+/* EEPROM_Ctrl */
+#define EC_Clk 0x01
+#define EC_CS  0x02
+#define EC_Wr  0x04
+#define EC_Rd  0x08
+#define ASIC_RST 0x40
+#define i586_RST  0x80
+
+#define eeprom_delay() { int _i = 40; while (--_i>0) { __SLOW_DOWN_IO; }}
+
+/*
+ * i82586 Memory Configuration
+ */
+
+/* (System Configuration Pointer) System start up block, read after 586_RST */
+#define SCP_START 0xfff6
+
+
+/* Intermediate System Configuration Pointer */
+#define ISCP_START 0x0000
+/* System Command Block */
+#define SCB_START 0x0008
+
+/*
+ * Start of buffer region. If we have 64k memory, eexp_hw_probe() may raise
+ * NUM_TX_BUFS. RX_BUF_END is set to the end of memory, and all space between
+ * the transmit buffer region and end of memory used for as many receive buffers
+ * as we can fit. See eexp_hw_[(rx)(tx)]init().
+ */
+#define TX_BUF_START 0x0100
+#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
+unsigned short NUM_TX_BUFS=4;
+unsigned short RX_BUF_START;
+#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
+unsigned short RX_BUF_END=0x7ff6; /* updated automatically to 0xfff6 on 64k cards */
+unsigned short NUM_RX_BUFS = 4;
+
+
+
+/*
+ * SCB defines
+ */
+
+/* these functions take the SCB status word and test the relavent status bit */
+#define SCB_complete(s) ((s&0x8000)!=0)
+#define SCB_rxdframe(s) ((s&0x4000)!=0)
+#define SCB_CUdead(s) ((s&0x2000)!=0)
+#define SCB_RUdead(s) ((s&0x1000)!=0)
+#define SCB_ack(s) (s & 0xf000)
+
+/* Command unit status: 0=idle, 1=suspended, 2=active */
+#define SCB_CUstat(s) ((s&0x0300)>>8)
+
+/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
+#define SCB_RUstat(s) ((s&0x0070)>>4)
+
+/* SCB commands */
+#define SCB_CUnop     0x0000
+#define SCB_CUstart   0x0100
+#define SCB_CUresume  0x0200
+#define SCB_CUsuspend 0x0300
+#define SCB_CUabort   0x0400
+
+/* ? */
+#define SCB_resetchip 0x0080
+
+#define SCB_RUnop     0x0000
+#define SCB_RUstart   0x0010
+#define SCB_RUresume  0x0020
+#define SCB_RUsuspend 0x0030
+#define SCB_RUabort   0x0040
+
+
+/*
+ * Command block defines
+ */
+
+#define Stat_Done(s)   ((s&0x8000)!=0)
+#define Stat_Busy(s)   ((s&0x4000)!=0)
+#define Stat_OK(s)     ((s&0x2000)!=0)
+#define Stat_Abort(s)  ((s&0x1000)!=0)
+#define Stat_STFail    ((s&0x0800)!=0)
+#define Stat_TNoCar(s) ((s&0x0400)!=0)
+#define Stat_TNoCTS(s) ((s&0x0200)!=0)
+#define Stat_TNoDMA(s) ((s&0x0100)!=0)
+#define Stat_TDefer(s) ((s&0x0080)!=0)
+#define Stat_TColl(s)  ((s&0x0040)!=0)
+#define Stat_TXColl(s) ((s&0x0020)!=0)
+#define Stat_NoColl(s) (s&0x000f)
+
+/* Cmd_END will end AFTER the command if this is the first
+ * command block after an SCB_CUstart, but BEFORE the command
+ * for all subsequent commands. Best strategy is to place
+ * Cmd_INT on the last command in the sequence, followed by a
+ * dummy Cmd_Nop with Cmd_END after this.
+ */
+#define Cmd_END     0x8000
+#define Cmd_SUS     0x4000
+#define Cmd_INT     0x2000
+
+#define Cmd_Nop     0x0000
+#define Cmd_SetAddr 0x0001
+#define Cmd_Config  0x0002
+#define Cmd_MCast   0x0003
+#define Cmd_Xmit    0x0004
+#define Cmd_TDR     0x0005
+#define Cmd_Dump    0x0006
+#define Cmd_Diag    0x0007
+
+
+/*
+ * Frame Descriptor (Receive block) defines
+ */
+
+#define FD_Done(s)  ((s&0x8000)!=0)
+#define FD_Busy(s)  ((s&0x4000)!=0)
+#define FD_OK(s)    ((s&0x2000)!=0)
+
+#define FD_CRC(s)   ((s&0x0800)!=0)
+#define FD_Align(s) ((s&0x0400)!=0)
+#define FD_Resrc(s) ((s&0x0200)!=0)
+#define FD_DMA(s)   ((s&0x0100)!=0)
+#define FD_Short(s) ((s&0x0080)!=0)
+#define FD_NoEOF(s) ((s&0x0040)!=0)
index def0a471a60a6acf4f3b4a76bdd919b7b28d3402..e783f34fd0ec804ee5742463b8612a613d4aa22d 100644 (file)
@@ -940,9 +940,9 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                }
        }
 
-    /* Clear any other interrupt, and set interrupt enable. */
-    outw(0x0000, dev->base_addr + LANCE_ADDR);
-    outw(0x7940, dev->base_addr + LANCE_DATA);
+       /* Clear any other interrupt, and set interrupt enable. */
+       outw(0x0000, dev->base_addr + LANCE_ADDR);
+       outw(0x7940, dev->base_addr + LANCE_DATA);
 
        if (lance_debug > 4)
                printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
@@ -979,7 +979,7 @@ lance_rx(struct device *dev)
                }
                else 
                {
-                       /* Malloc up new buffer, compatible with net-2e. */
+                       /* Malloc up new buffer, compatible with net3. */
                        short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;
                        struct sk_buff *skb;
                        
index e60a677c6115ea9d383244c4167d3f1d62581c4c..26bd0a14dd6713ee2bdd06753cfa6e042bc2d92b 100644 (file)
@@ -87,7 +87,7 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/segment.h>
-#include <net/if.h>
+#include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
@@ -101,8 +101,8 @@ typedef struct sk_buff           sk_buff;
 #define skb_data(skb)       ((unsigned char *) (skb)->data)
 #endif
 
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
 #include <linux/if_arp.h>
 #include "slhc.h"
 #include <linux/ppp_defs.h>
index 98c838692b123b1f90ac9421279c9b33e8ee1379..9fcca56369309ae1f7397f94a24851be07488f67 100644 (file)
@@ -1402,7 +1402,7 @@ static void sl_keepalive(unsigned long sls)
 {
        struct slip *sl=(struct slip *)sls;
 
-       if(sls==NULL)
+       if(sl == NULL)
                return;
 
        if( sl->keepalive)
index d12652573e0deb5edd9dbe3dad9119ffa667a76d..5e463d4c94e3c454538ddbda47b2b97571766c24 100644 (file)
@@ -1,17 +1,22 @@
 /* lance.c: Linux/Sparc/Lance driver */
 /*
-       Written 1995 by Miguel de Icaza
+       Written 1995, 1996 by Miguel de Icaza
   Sources:
        The Linux  depca driver
        The Linux  lance driver.
        The Linux  skeleton driver.
         The NetBSD Sparc/Lance driver.
-       Theo Deraadt (deraadt@theos.com)
+       Theo de Raadt (deraadt@openbsd.org)
        NCR92C990 Lan Controller manual
-*/
 
+1.4:
+       Added support to run with a ledma on the Sun4m
+*/
+#undef DEBUG_DRIVER
 static char *version =
-       "lance.c:v1.2 29/Oct/95 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+       "sunlance.c:v1.4 17/Feb/96 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+
+static char *lancestr = "LANCE";
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -43,9 +48,6 @@ static char *version =
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#define MASK_INTERRUPTS   1
-#define UNMASK_INTERRUPTS 0
-
 /* Define: 2^2 Tx buffers and 2^4 Rx buffers */
 #ifndef LANCE_LOG_TX_BUFFERS
 #define LANCE_LOG_TX_BUFFERS 2
@@ -114,8 +116,8 @@ static char *version =
 #define RX_RING_LEN_BITS               ((LANCE_LOG_RX_BUFFERS) << 29)
 
 #define PKT_BUF_SZ             1544
-#define RX_BUFF_SIZE            1536
-#define TX_BUFF_SIZE            1536
+#define RX_BUFF_SIZE            PKT_BUF_SZ
+#define TX_BUFF_SIZE            PKT_BUF_SZ
 
 struct lance_rx_desc {
     unsigned short rmd0;        /* low address of packet */
@@ -155,14 +157,15 @@ struct lance_init_block {
 };
 
 struct lance_private {
-       char *name;
-       volatile struct lance_regs *ll;
-       volatile struct lance_init_block *init_block;
-       
-       int rx_new, tx_new;
-       int rx_old, tx_old;
-
-       struct enet_statistics stats;
+    char *name;
+    volatile struct lance_regs *ll;
+    volatile struct lance_init_block *init_block;
+    
+    int rx_new, tx_new;
+    int rx_old, tx_old;
+    
+    struct enet_statistics stats;
+    struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */
 };
 
 #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
@@ -178,7 +181,8 @@ struct lance_regs {
 int sparc_lance_debug = 2;
 
 /* The Lance uses 24 bit addresses */
-/* The DVMA will provide the remaining bytes for us */
+/* On the Sun4c the DVMA will provide the remaining bytes for us */
+/* On the Sun4m we have to instruct the ledma to provide them    */
 #define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
 
 /* Load the CSR registers */
@@ -277,7 +281,8 @@ lance_init_ring (struct device *dev)
     ib->filter [1] = 0;
 }
 
-static int init_restart_lance (struct lance_private *lp)
+static int
+init_restart_lance (struct lance_private *lp)
 {
     volatile struct lance_regs *ll = lp->ll;
     int i;
@@ -290,13 +295,19 @@ static int init_restart_lance (struct lance_private *lp)
        ;
     if ((i == 100) || (ll->rdp & LE_C0_ERR)){
        printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
+       if (lp->ledma)
+           printk ("dcsr=%8.8x\n", (unsigned int) lp->ledma->regs->cond_reg);
        return -1;
     }
 
     /* Clear IDON by writing a "1", enable interrupts and start lance */
     ll->rdp = LE_C0_IDON;
     ll->rdp = LE_C0_INEA | LE_C0_STRT;
-    printk ("LANCE opened after %d ticks, csr0=%4.4x\n", i, ll->rdp);
+
+    /* On the 4m, enable dma interrupts */
+    if (lp->ledma)
+       lp->ledma->regs->cond_reg |= DMA_INT_ENAB;
+
     return 0;
 }
 
@@ -307,8 +318,6 @@ lance_rx (struct device *dev)
     volatile struct lance_init_block *ib = lp->init_block;
     volatile struct lance_regs *ll = lp->ll;
     volatile struct lance_rx_desc *rd;
-    int i;
-    int entry;
     unsigned char bits;
 
 #ifdef TEST_HITS
@@ -322,71 +331,28 @@ lance_rx (struct device *dev)
     printk ("]");
 #endif
     
-#ifdef OLD_METHOD
-    ll->rdp = LE_C0_RINT|LE_C0_INEA;
-    /* FIXME: Add slot prediction */
-    for (rd = &ib->brx_ring [i = 0]; i < RX_RING_SIZE; i++, rd++){
-       int bits;
-       
-       bits = rd->rmd1_bits;
-
-       /* Check if we own the packet */
-       if (bits & LE_R1_OWN)
-           continue;
-
-       /* We got an incomplete frame? */
-       if ((bits & LE_R1_POK) != LE_R1_POK){
-           /* Count only the end frame as a tx error, not the beginning */
-           if (bits & LE_R1_EOP) lp->stats.rx_errors++;
-           if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
-           if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
-           if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
-           if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
-       } else {
-           int pkt_len = rd->mblength;
-           struct sk_buff *skb;
-           char *buf;
-           
-           skb = dev_alloc_skb (pkt_len+2);
-           if (skb == NULL){
-               printk ("%s: Memory squeeze, deferring packet.\n", dev->name);
-               lp->stats.rx_dropped++;
-               rd->rmd1_bits = LE_R1_OWN;
-               return 0;
-           }
-           
-           skb->dev = dev;
-           skb_reserve (skb, 2);               /* 16 byte align */
-           buf = skb_put (skb, pkt_len);       /* make room */
-           memcpy (buf, &(ib->rx_buf [i][0]), pkt_len);
-           skb->protocol = eth_type_trans (skb,dev);
-           netif_rx (skb);
-           lp->stats.rx_packets++;
-       }
-
-       /* Return the packet to the pool */
-       rd->rmd1_bits = LE_R1_OWN;
-    }
-#else
     ll->rdp = LE_C0_RINT|LE_C0_INEA;
     for (rd = &ib->brx_ring [lp->rx_new];
         !((bits = rd->rmd1_bits) & LE_R1_OWN);
         rd = &ib->brx_ring [lp->rx_new]){
+       int pkt_len;
+       struct sk_buff *skb;
+       char *buf;
 
        /* We got an incomplete frame? */
        if ((bits & LE_R1_POK) != LE_R1_POK){
-           printk ("Incomplete frame\n");
+           lp->stats.rx_over_errors++;
+           lp->stats.rx_errors++;
+           continue;
+       } else if (bits & LE_R1_ERR){
            /* Count only the end frame as a tx error, not the beginning */
-           if (bits & LE_R1_EOP) lp->stats.rx_errors++;
            if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
            if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
            if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
            if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
+           if (bits & LE_R1_EOP) lp->stats.rx_errors++;
        } else {
-           int pkt_len = rd->mblength;
-           struct sk_buff *skb;
-           char *buf;
-
+           pkt_len = rd->mblength;
            skb = dev_alloc_skb (pkt_len+2);
            if (skb == NULL){
                printk ("%s: Memory squeeze, deferring packet.\n", dev->name);
@@ -409,7 +375,6 @@ lance_rx (struct device *dev)
        rd->rmd1_bits = LE_R1_OWN;
        lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK;
     }
-#endif
     return 0;
 }
 
@@ -446,9 +411,13 @@ lance_tx (struct device *dev)
                /* Stop the lance */
                ll->rdp = LE_CSR0;
                ll->rap = LE_C0_STOP;
+               lance_init_ring (dev);
+               load_csrs (lp);
                init_restart_lance (lp);
+               return 0;
            }
-       }
+        } else
+               lp->stats.tx_packets++;
        
        j = (j + 1) & TX_RING_MOD_MASK;
     }
@@ -469,13 +438,19 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
     lp = (struct lance_private *) dev->priv;
     ll = lp->ll;
 
+    if (lp->ledma)
+       if (lp->ledma->regs->cond_reg & DMA_HNDL_ERROR){
+           printk ("%s: should reset my ledma (dmacsr=%8.8x, csr=%4.4x\n", dev->name,
+                   (unsigned int) lp->ledma->regs->cond_reg, ll->rdp); 
+           printk ("send mail to miguel@nuclecu.unam.mx\n");
+       }
     if (dev->interrupt)
        printk ("%s: again", dev->name);
     
     dev->interrupt = 1;
 
     csr0 = ll->rdp;
-    
+
     /* Acknowledge all the interrupt sources ASAP */
     ll->rdp = csr0 & 0x004f;
     
@@ -512,17 +487,21 @@ lance_open (struct device *dev)
     int status = 0;
 
     last_dev = dev;
-    
-    /* Stop the Lance */
-    ll->rap = LE_CSR0;
-    ll->rdp = LE_C0_STOP;
 
-    if (request_irq (dev->irq, &lance_interrupt, 0, "LANCE", NULL)){
+    if (request_irq (dev->irq, &lance_interrupt, 0, lancestr, NULL)){
        printk ("Lance: Can't get irq %d\n", dev->irq);
        return -EAGAIN;
     }
+    /* Stop the Lance */
+    ll->rap = LE_CSR0;
+    ll->rdp = LE_C0_STOP;
+
     irq2dev_map [dev->irq] = dev;
 
+    /* On the 4m, setup the ledma to provide the upper bits for buffers */
+    if (lp->ledma)
+       lp->ledma->regs->dma_test = ((unsigned int) lp->init_block) & 0xff000000;
+
     lance_init_ring (dev);
     load_csrs (lp);
 
@@ -531,28 +510,15 @@ lance_open (struct device *dev)
     dev->start = 1;
 
     status = init_restart_lance (lp);
-
-    /* To make life easier to us while Sparc Linux becomes self hosting: */
-    {
-           struct rtentry server_route;
-           struct sockaddr_in *sin;
-           
-           sin=(struct sockaddr_in *)&server_route.rt_dst;
-           *sin=server;
-           sin=(struct sockaddr_in *)&server_route.rt_genmask;
-           sin->sin_family=AF_INET;
-           sin->sin_addr.s_addr= ip_get_mask (dev->pa_addr);
-           server_route.rt_dev[0]=dev;
-           server_route.
-           server_route.rt_flags=RTF_HOST|RTF_UP;
-
-           if(ip_rt_new(&server_route)==-1)
-                   printk("Unable to add NFS server route.\n");
-    }
-    ip_rt_add (RTF_UP,
-              dev->pa_addr & ip_get_mask (dev->pa_addr),
-              ip_get_mask (dev->pa_addr),
-              0, dev, dev->mtu, 0, 0);
+    if (lp->ledma)
+       lp->ledma->regs->cond_reg |= DMA_INT_ENAB;
+#if 0
+    /* To emulate SunOS, we add a route to the local network */
+    rt_add (RTF_UP,
+           dev->pa_addr & ip_get_mask (dev->pa_addr),
+           ip_get_mask (dev->pa_addr),
+           0, dev, dev->mtu, 0, 0);
+#endif
     return status;
 }
 
@@ -575,7 +541,8 @@ lance_close (struct device *dev)
     return 0;
 }
 
-inline static int lance_reset (struct device *dev)
+inline static int
+lance_reset (struct device *dev)
 {
     struct lance_private *lp = (struct lance_private *)dev->priv;
     volatile struct lance_regs *ll = lp->ll;
@@ -584,9 +551,15 @@ inline static int lance_reset (struct device *dev)
     /* Stop the lance */
     ll->rdp = LE_CSR0;
     ll->rap = LE_C0_STOP;
-#ifdef DEBUG_DRIVER
-    printk ("Lance stopped: csr0=%4.4x\n", ll->rdp);
-#endif
+
+    /* On the 4m, reset the dma too */
+    if (lp->ledma){
+       printk ("resetting ledma\n");
+       lp->ledma->regs->cond_reg |= DMA_RST_ENET;
+       udelay (200);
+       lp->ledma->regs->cond_reg &= ~DMA_RST_ENET;
+       lp->ledma->regs->cond_reg |= DMA_INT_ENAB;
+    }
     lance_init_ring (dev);
     load_csrs (lp);
     dev->trans_start = jiffies;
@@ -597,9 +570,11 @@ inline static int lance_reset (struct device *dev)
 #ifdef DEBUG_DRIVER
     printk ("Lance restart=%d\n", status);
 #endif
+    return status;
 }
 
-static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
+static int
+lance_start_xmit (struct sk_buff *skb, struct device *dev)
 {
     struct lance_private *lp = (struct lance_private *)dev->priv;
     volatile struct lance_regs *ll = lp->ll;
@@ -649,9 +624,13 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
 
 #ifdef DEBUG_DRIVER
     /* dump the packet */
-    for (i = 0; i < 64; i++){
-       if ((i % 16) == 0) printk ("\n");
-       printk ("%2.2x ", skb->data [i]);
+    {
+       int i;
+       
+       for (i = 0; i < 64; i++){
+           if ((i % 16) == 0) printk ("\n");
+           printk ("%2.2x ", skb->data [i]);
+       }
     }
 #endif
     len = (skblen < ETH_ZLEN) ? ETH_ZLEN : skblen;
@@ -692,7 +671,7 @@ lance_get_stats (struct device *dev)
 }
 
 static void
-lance_set_multicast (struct device *dev)
+lance_set_multicast (struct device *dev, int num_addrs, void *addrs)
 {
 #ifdef NOT_YET
     struct lance_private *lp = (struct lance_private *) dev->priv;
@@ -714,6 +693,19 @@ lance_set_multicast (struct device *dev)
 #endif
 }
 
+/* On 4m, find the associated dma for the lance chip */
+static struct Linux_SBus_DMA *
+find_ledma (struct linux_sbus_device *dev)
+{
+    struct Linux_SBus_DMA *p;
+
+    for (p = dma_chain; p; p = p->next)
+       if (p->SBus_dev == dev)
+           return p;
+    return 0;
+}
+
+/* FIXME: the probe code should be able to detect  */
 int sparc_lance_probe (struct device *dev)
 {
     static unsigned version_printed = 0;
@@ -721,6 +713,7 @@ int sparc_lance_probe (struct device *dev)
     int    found = 0;
     struct linux_sbus *bus;
     struct linux_sbus_device *sdev = 0;
+    struct Linux_SBus_DMA *ledma = 0;
     struct lance_private *lp;
     volatile struct lance_regs *ll;
 
@@ -733,6 +726,12 @@ int sparc_lance_probe (struct device *dev)
                found = 1;
                break;
            }
+           if (strcmp (sdev->prom_name, "ledma") == 0){
+               ledma = find_ledma (sdev);
+               found = 1;
+               sdev = sdev->child;
+               break;
+           }
        }
     }
     if (!found)
@@ -743,6 +742,8 @@ int sparc_lance_probe (struct device *dev)
        dev = init_etherdev (0, sizeof (struct lance_private));
     } else {
        dev->priv = kmalloc (sizeof (struct lance_private), GFP_KERNEL);
+       if (dev->priv == NULL)
+               return -ENOMEM;
     }
     if (sparc_lance_debug && version_printed++ == 0)
        printk (version);
@@ -759,18 +760,22 @@ int sparc_lance_probe (struct device *dev)
        printk ("%2.2x%c", dev->dev_addr [i] = idprom->id_eaddr [i], i == 5 ? ' ': ':');
     }
     /* Get the IO region */
+    prom_apply_sbus_ranges (&sdev->reg_addrs [0], sdev->num_registers);
     ll = sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0,
-                        sizeof (struct lance_regs), "Lance driver", 0x0, 0x0);
-    
+                        sizeof (struct lance_regs), lancestr,
+                        sdev->reg_addrs[0].which_io, 0x0);
+
     /* Make certain the data structures used by the LANCE are aligned. */
     dev->priv = (void *)(((int)dev->priv + 7) & ~7);
     lp = (struct lance_private *) dev->priv;
+    memset ((char *)dev->priv, 0, sizeof (struct lance_private));
     
     lp->init_block = (void *)
-       sparc_dvma_malloc (sizeof (struct lance_init_block), "LANCE");
+       sparc_dvma_malloc (sizeof (struct lance_init_block), lancestr);
     
     lp->ll = ll;
-    lp->name = "LANCE";
+    lp->name = lancestr;
+    lp->ledma = ledma;
 
     /* This should never happen. */
     if ((int)(lp->init_block->brx_ring) & 0x07) {
@@ -787,7 +792,7 @@ int sparc_lance_probe (struct device *dev)
     dev->irq = (unsigned char) sdev->irqs [0].pri;
     dev->dma = 0;
     ether_setup (dev);
-    
+
     return 0;
 }
 /*
diff --git a/drivers/net/tunnel.c b/drivers/net/tunnel.c
deleted file mode 100644 (file)
index 5a3d6b4..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/* tunnel.c: an IP tunnel driver
-
-       The purpose of this driver is to provide an IP tunnel through
-       which you can tunnel network traffic transparently across subnets.
-
-       This was written by looking at Nick Holloway's dummy driver
-       Thanks for the great code!
-
-               -Sam Lantinga   (slouken@cs.ucdavis.edu)  02/01/95
-               
-       Minor tweaks:
-               Cleaned up the code a little and added some pre-1.3.0 tweaks.
-               dev->hard_header/hard_header_len changed to use no headers.
-               Comments/bracketing tweaked.
-               Made the tunnels use dev->name not tunnel: when error reporting.
-               Added tx_dropped stat
-               
-               -Alan Cox       (Alan.Cox@linux.org) 21 March 95
-*/
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <netinet/in.h>
-#include <linux/ip.h>
-#include <linux/string.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/ip.h>
-
-#include <net/checksum.h>              /* If using 1.3.0-pre net code */
-
-#define ip_header_len  sizeof(struct iphdr)
-
-static int tunnel_xmit(struct sk_buff *skb, struct device *dev);
-static struct enet_statistics *tunnel_get_stats(struct device *dev);
-
-#ifdef MODULE
-static int tunnel_open(struct device *dev)
-{
-       MOD_INC_USE_COUNT;
-       return 0;
-}
-
-static int tunnel_close(struct device *dev)
-{
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-#endif
-
-
-int tunnel_init(struct device *dev)
-{
-       static int tun_msg=0;
-       if(!tun_msg)
-       {
-               printk ( KERN_INFO "tunnel: version v0.1a\n" );
-               tun_msg=1;
-       }
-
-       /* Fill in fields of the dev structure with ethernet-generic values. */
-       ether_setup(dev);
-
-       /* Custom initialize the device structure. */
-       dev->hard_start_xmit = tunnel_xmit;
-       dev->get_stats = tunnel_get_stats;
-       dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
-       if (dev->priv == NULL)
-               return -ENOMEM;
-       memset(dev->priv, 0, sizeof(struct enet_statistics));
-#ifdef MODULE
-       dev->open = &tunnel_open;
-       dev->stop = &tunnel_close;
-#endif
-       /* Now stomp the bits that are different */
-       dev->type = ARPHRD_TUNNEL;      /* IP tunnel hardware type (Linux 1.1.89) */
-       dev->flags |= IFF_NOARP;
-       dev->flags |= IFF_LOOPBACK;     /* Why doesn't tunnel work without this? [ should do now - AC]*/
-       dev->addr_len=0;
-       dev->tx_queue_len=2;            /* Small queue - it should all run through */
-       dev->hard_header_len=0;
-       dev->hard_header=NULL;
-       dev->header_cache_bind=NULL;
-       dev->rebuild_header=NULL;
-       /* End of stomp 8) */
-       return 0;
-}
-
-#ifdef TUNNEL_DEBUG
-void print_ip(struct iphdr *ip)
-{
-       unsigned char *ipaddr;
-
-       printk("IP packet:\n");
-       printk("--- header len = %d\n", ip->ihl*4);
-       printk("--- ip version: %d\n", ip->version);
-       printk("--- ip protocol: %d\n", ip->protocol);
-       ipaddr=(unsigned char *)&ip->saddr;
-       printk("--- source address: %u.%u.%u.%u\n", 
-                       *ipaddr, *(ipaddr+1), *(ipaddr+2), *(ipaddr+3));
-       ipaddr=(unsigned char *)&ip->daddr;
-       printk("--- destination address: %u.%u.%u.%u\n", 
-                       *ipaddr, *(ipaddr+1), *(ipaddr+2), *(ipaddr+3));
-       printk("--- total packet len: %d\n", ntohs(ip->tot_len));
-}
-#endif
-
-/* This function assumes it is being called from dev_queue_xmit()
-   and that skb is filled properly by that function.
-   We also presume that if we return 0, we need to free skb, but
-   if we return 1, we don't free anything.  Right?  Wrong?
-*/
-
-static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
-{
-       struct enet_statistics *stats;
-       struct sk_buff *skb2;           /* The output packet */
-       int newlen;                     /* The length of skb2->data */
-       struct iphdr *iph;              /* Our new IP header */
-
-       /*
-        *      Return if there is nothing to do 
-        */
-        
-       if (skb == NULL || dev == NULL)
-               return 0;
-
-       /* 
-        *      Make sure we are not busy (check lock variable) 
-        */
-        
-       stats = (struct enet_statistics *)dev->priv;
-       cli();
-       if (dev->tbusy != 0) 
-       {
-               sti();
-               stats->tx_errors++;
-               return(1);
-       }
-       dev->tbusy = 1;
-       sti();
-  
-       /*
-        *      Perform some sanity checks on the packet 
-        */
-        
-       if ( ! dev->pa_dstaddr ) 
-       {
-               printk("%s: packet sent through tunnel to never-never land!\n", dev->name);
-               dev_kfree_skb(skb, FREE_WRITE);
-               dev->tbusy = 0;
-               return(1);
-       }
-
-       iph=(struct iphdr *)skb->data;
-       if ( iph->version != 4 ) 
-       {  
-               /* 
-                *      Bad IP packet? Possibly an ARP packet 
-                */
-               printk("%s: Bad IP packet: ip version %d\n", dev->name, iph->version);
-               dev_kfree_skb(skb, FREE_WRITE);
-               dev->tbusy = 0;
-               return(0);
-       }
-
-
-       /* 
-        *      Check for routing loops 
-        */
-        
-       if ( iph->protocol == IPPROTO_IPIP && iph->saddr == dev->pa_addr ) 
-       {
-               /* 
-                *      We really should do an ICMP reply here... 
-                */
-               printk("%s: Warning: IP routing loop!\n", dev->name);
-               dev->tbusy = 0;
-               dev_kfree_skb(skb, FREE_WRITE);
-               return(0);
-       }
-
-       if ( iph->daddr == dev->pa_addr ) 
-       {
-               printk("%s: Received inbound packet -- not handled.\n",dev->name);
-               dev_kfree_skb(skb, FREE_WRITE);
-               dev->tbusy = 0;
-               return(0);
-       }
-
-#ifdef TUNNEL_DEBUG
-printk("Old IP Header....\n");
-print_ip(iph);
-#endif
-       /*
-        * Everything is okay: 
-        *              See if we need to allocate memory for a new packet 
-        */
-
-       newlen = (skb->len + ip_header_len);
-       if ( !(skb2 = dev_alloc_skb(newlen)) ) 
-       {
-               printk("%s: No free memory.\n",dev->name);
-               dev_kfree_skb(skb, FREE_WRITE);
-               dev->tbusy = 0;
-               stats->tx_dropped++;
-               return(1);
-       }
-
-       /* Copy the packet to a new buffer, adding a new ip header */
-       skb2->free=1;
-       skb_put(skb2,newlen);
-       iph=skb2->h.iph=(struct iphdr *)skb2->data;
-       skb2->ip_hdr=iph;
-       memcpy(skb2->h.iph, skb->data, ip_header_len );
-       memcpy(skb2->data + ip_header_len, skb->data, skb->len);
-       /* Free the old packet, we no longer need it */
-       dev_kfree_skb(skb, FREE_WRITE);
-
-       /* Correct the fields in the new ip header */
-       ++iph->ttl;     /* Note: ip_forward() decrements ttl, so compensate */
-       iph->saddr = dev->pa_addr;
-       iph->daddr = dev->pa_dstaddr;
-       iph->protocol = IPPROTO_IPIP;
-       iph->ihl = 5;
-       iph->tot_len = htons(skb2->len);
-       iph->frag_off = 0;
-
-       /* Here is where we compute the IP checksum */
-       /* ip_fast_csum() is an inline function from net/inet/ip.h/checksum.h */
-       iph->check = 0;
-       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-
-#ifdef TUNNEL_DEBUG
-printk("New IP Header....\n");
-print_ip(iph);
-#endif
-       /* Now send the packet on its way */
-#ifdef TUNNEL_DEBUG
-       printk("tunnel: calling ip_forward()\n");
-#endif
-       if(ip_forward(skb2, dev, 0, iph->daddr))
-               kfree_skb(skb2, FREE_WRITE);
-
-#ifdef TUNNEL_DEBUG
-       printk("Packet sent through tunnel interface!\n");
-#endif
-       /* Record statistics */
-       stats->tx_packets++;
-
-#ifdef TUNNEL_DEBUG
-       printk("tunnel: Updated usage statistics.\n");
-#endif
-       dev->tbusy=0;
-       return 0;
-}
-
-static struct enet_statistics *
-tunnel_get_stats(struct device *dev)
-{
-       return((struct enet_statistics*) dev->priv);
-}
-
-#ifdef MODULE
-
-static int tunnel_probe(struct device *dev)
-{
-       tunnel_init(dev);
-       return 0;
-}
-
-static struct device dev_tunnel = {
-       "tunl0\0   ", 
-               0, 0, 0, 0,
-               0x0, 0,
-               0, 0, 0, NULL, tunnel_probe };
-
-int init_module(void)
-{
-       /* Find a name for this unit */
-       int ct= 1;
-       
-       while(dev_get(dev_tunnel.name)!=NULL && ct<100)
-       {
-               sprintf(dev_tunnel.name,"tunl%d",ct);
-               ct++;
-       }
-       
-#ifdef TUNNEL_DEBUG
-       printk("tunnel: registering device %s\n", dev_tunnel.name);
-#endif
-       if (register_netdev(&dev_tunnel) != 0)
-               return -EIO;
-       return 0;
-}
-
-void cleanup_module(void)
-{
-       unregister_netdev(&dev_tunnel);
-       kfree_s(dev_tunnel.priv,sizeof(struct enet_statistics));
-       dev_tunnel.priv=NULL;
-}
-#endif /* MODULE */
index 19111dd33c0f0ece16295fda5af5e985c881ecae..e70409b59a226ffbf281995cf6543acf5696b1ae 100644 (file)
@@ -2023,7 +2023,7 @@ wavelan_set_multicast_list(device *dev)
        unsigned long   x;
 
        if (wavelan_debug > 0)
-               printk("%s: ->wavelan_set_multicast_list(dev=0x%x)", dev->name, dev);
+               printk("%s: ->wavelan_set_multicast_list(dev=%p)", dev->name, dev);
 
        lp = (net_local *)dev->priv;
 
index 505a3aef0e407c1d20de870e1369220905cfd579..de49f45f0a3c20305aeababa987e5e40c6b0b3c7 100644 (file)
@@ -640,14 +640,14 @@ const char *ultrastor_info(struct Scsi_Host * shpnt)
     static char buf[64];
 
     if (config.slot)
-      sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u\n",
+      sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u",
              config.slot, config.interrupt);
     else if (config.subversion)
-      sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u\n",
+      sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u",
              config.port_address, (int)config.bios_segment,
              config.interrupt);
     else
-      sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u\n",
+      sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u",
              config.port_address, (int)config.bios_segment,
              config.interrupt, config.dma_channel);
     return buf;
@@ -884,7 +884,7 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt)
        printk("Ux4F: abort while completed command pending\n");
        restore_flags(flags);
        cli();
-       ultrastor_interrupt(0, NULL);
+       ultrastor_interrupt(0, NULL, NULL);
        restore_flags(flags);
        return SCSI_ABORT_SUCCESS;  /* FIXME - is this correct? -ERY */
       }
index b4b35ada707d2833cb2b8fc727e2382f4a27815a..5d3bc2d53b8b2ad58cd0d39e2f0561999ed8be33 100644 (file)
@@ -1,2 +1,2 @@
-3.5-beta7
+3.5-beta10
 0x030505
index 78edc3239cbb34ba7caf75c22adfd9d9615ee8eb..abfc426dede1b04600e01a0d0d58b1bcc19a9066 100644 (file)
@@ -1,5 +1,19 @@
-Changelog for version 3.5-beta7
--------------------------------
+Changelog for version 3.5-beta10
+--------------------------------
+
+Since 3.5-beta8
+- Fixed for compatibility with Linux 1.3.70 and later.
+- Changed boot time passing of 16 bit DMA channel number to SB driver.
+
+Since 3.5-beta8
+- Minor changes
+
+Since 3.5-beta7
+- enhancements to configure program (by Jeff Tranter):
+  - prompts are in same format as 1.3.x Linux kernel config program
+  - on-line help for each question
+  - fixed some compile warnings detected by gcc/g++ -Wall
+  - minor grammatical changes to prompts
 
 Since 3.5-beta6
 - Fixed bugs in mmap() support.
@@ -28,8 +42,8 @@ Since 3.5-beta1
 - Bugfixes.
 - Full duplex audio with MAD16+CS4231 may work now. The driver configures
   SB DMA of MAD16 so that it doesn't conflict with codec's DMA channels.
-  The side effect is that all 8 bit DMA channels (0,1,3) are populated in duplex
-  mode.
+  The side effect is that all 8 bit DMA channels (0,1,3) are populated in 
+  duplex mode.
 
 Since 3.5-alpha9
 - Bugfixes (mostly in Jazz16 and ESS1688/688 supports).
diff --git a/drivers/sound/Config.std b/drivers/sound/Config.std
new file mode 100644 (file)
index 0000000..447e82f
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Sound driver configuration
+#
+#--------
+# There is another confic script which is compatible with rest of
+# the kernel. It can be activated by running 'make mkscript' in this
+# directory. Please note that this is an _experimental_ feature which
+# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro).
+#--------
+#
+$MAKE -C drivers/sound config || exit 1
+
index 202e180a6a6f8c41d2a8e52aa9b3e1471bae0d4e..50d8969cf4f21f54ed320f17ce1a5398c5e2f22f 100644 (file)
@@ -58,6 +58,7 @@ ifndef HOSTCC
 CC     = gcc
 HOSTCC = gcc
 CFLAGS = -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486
+USE_DEPEND=y
 else
 include $(TOPDIR)/Rules.make
 endif
@@ -69,7 +70,7 @@ sound.a: $(OBJS)
 
 clean:
        rm -f core core.* *.o *.a tmp_make *~ x y z *%
-       rm -f configure sound_stub.c objects/*.o
+       rm -f configure sound_stub.c objects/*.o 
 
 indent:
        for n in *.c;do echo indent $$n;indent $$n;done
@@ -144,9 +145,11 @@ modules: local.h sound.o
        ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o
 
 
+ifdef USE_DEPEND
 #
 # include a dependency file if one exists
 #
 ifeq (.depend,$(wildcard .depend))
 include .depend
 endif
+endif
index 704ff5cb5fdce4b633661f41fc80bcaa36cc2e64..807177dfc65353deda05b85df09c03cf6735610e 100644 (file)
+Version 3.5-beta10 release notes
+--------------------------------
 
-Version 3.5-beta6 release notes
--------------------------------
+Most up to date information about this driver is available from 
+http://personal.eunet.fi/pp/voxware.
 
-IMPORTANT! This version of the driver is compatible only with Linux versions
-          1.3.59 to 1.3.6x. It may work with few earlier ones as a loadable
-          module but...
 
-          This is a BETA test version. Most known bugs should have been fixed.
-          However it's possible that there are still bugs. Please report them
-          to me ASAP so that they can be fixed before Linux 1.4. But look
-          at the web page (see below) before sending me a bug report. 
 
-          Crashing with GUS should be fixed now.
-          Recording is still disabled with ESS1688/688 cards since it
-          causes a crash.
 
 Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux ftp 
 sites). It gives instructions about using sound with Linux. It's bit out of
 date but still very useful. Information about bug fixes and such things
 is available from the web page (see below).
 
-*****************************************************************
-* NEW! Driver's home page is http://personal.eunet.fi/pp/voxware*
-* The file Readme.cards contains card specific instructions     *
-* about configuring various cards.                             *
-*****************************************************************
-
-There are some programming information (little bit old) in the
-Hacker's Guide 
-(ftp://nic.funet.fi/pub/OS/Linux/ALPHA/sound/snd-sdk-doc-0.1.ps.gz).
-Believe me: The file is really there. The directory is just hidden and
-you have to cd into it before the file is visible. Note: This directory
-was accidently removed some time ago but it's now back.
-
-I have got many patches from various persons during last year. Some of
-them are still on my mailbox and they should be included in versions
-after v3.5 (I will not add aditional features before v3.5 is ready).
+New Programmer's Guide is currently under work (Feb/March 96). Please
+check http://personal.eunet.fi/pp/voxware for more info.
 
    ====================================================
--  THIS VERSION ____REQUIRES____ Linux 1.3.64 OR LATER.
+-  THIS VERSION ____REQUIRES____ Linux 1.3.70 OR LATER.
    ====================================================
 
--  THIS VERSION MAY NOT WORK WITH Linux VERSIONS RELEASED
-   AFTER end of Feb 1996. If this version doesn't compile with
-   your kernel version, please use the sound driver version
-   included in your kernel.
+It's very likely that this driver version is incompatible with
+Linux versions later than 2.x.
 
-You may need the snd-util-3.5.tar.gz and snd-data-0.1.tar.Z
-packages to use this driver. They should be in the same
-ftp site or BBS from where you got this driver. For
-example at nic.funet.fi:pub/OS/Linux/*.
+Packages "snd-util-3.5.tar.gz" and "snd-data-0.1.tar.Z"
+contain usefull utilities to be used with this driver.
 
 If you are looking for the installation instructions, please
-look at linux/Readme.
+look at Readme.linux.
 
 Supported soundcards
 --------------------
 
-Gravis Ultrasound (GUS)
-GUS MAX
-GUS with the 16 bit sampling daughtercard
-GUS ACE
-GUS PnP support should be available around May 1996.
-PAS16
-Windows Sound System compatible soundcards
-ECHO-PSS (cards based on the PSS architecture by Analog Devices.
-       Including Orchid SW32, Cardinal DSP16 among others).
-               (NOTE! WSS mode may not work (DMA channel setup problem)).
-MediaTriX AudioTriX Pro (OPL4 and the optional effect daughtercard
-       require special initialization. There is a program (setfx) in
-       the snd-util-3.0.tar.gz package which does it).
-Ensoniq SoundScape & SoundScape Elite
-Ensonig SoundScape PnP not supported yet (summer 1996?)
-MV Jazz16 based soundcards (ProSonic, 3D etc).
-SoundMan Wave
-Mozart (OAK OTI-601 interface chip) based soundcards.
-MAD16 (an interface chip by OPTi) based soundcards (TB Tropez ???).
-(NOTE! The MAD16 looks similar to the Mozart chip. It could be a good
-idea to configure MAD16 cards as Mozart ones. The MAD16 driver doesn't set
-up MPU401 which the Mozart one does.
-CS4232 based cards such as AcerMagic S23.
-ESS ES1688 based soundcards.
-
-
-In addition all Sound Blaster models and clones (up to AWE32) work if
-you want to use them. SB16/SB32/AWE32 PnP models don't work yet. See the web
-page for more info.
-
-The Emu synthesizer chip of AWE32 will not be supported soon. The same is
-true with the ASP chip also. Creative Technology will not release detailed
-information about them so it's not possible to support them.
-
-===========================================================================
-If your card is compatible with SB, MPU401 or Windows Sound System, it
-may work with the driver even if it's not listed in the above list. In this
-case it may require initialization using DOS. Just start DOS and cold
-boot to Linux (etc.) by hitting ctrl-alt-del. 
-===========================================================================
-
-Compatibility with the earlier versions
----------------------------------------
-
-There have been some changes in soundcard.h after v2.5 of the driver
-(v2.90 is compatible with this one). Binaries compiled with this version
-of soundcard.h will not work with v2.0 and earlier.
+See Readme.cards.
+
+Please check http://personal.eunet.fi/pp/voxware if you don't find
+your soundcard there.
 
 Contributors
 ------------
@@ -225,29 +156,15 @@ In general the printout of of /dev/sndstat should tell what is the problem.
 It's possible that there are bugs in the sound driver but 99% of the problems
 reported to me are caused by somehow incorrect setup during "make config".
 
-For owners of TI TM4000M notebooks
-----------------------------------
-
-There appears to be some kind of conflict between the sound support
-(MV Jazz), mouse port and the sound driver. You could try to configure kernel
-with the C&T 82C710 mouse port support disabled.
+Best regards,
 
 Hannu
 
-Regards,
-
 Hannu Savolainen
-hannu@voxware.pp.fi
+hannu@voxware.pp.fi    
+(Please check http:/personal.eunet.fi/pp/voxware before mailing me).
 
 Snail mail:    Hannu Savolainen
                Hiekkalaiturintie 3 A 8
                00980 Helsinki
                Finland
-
-NOTE!  I propably don't answer to Snail mail or FAX messages. Sending answer
-       to each of them is simply too expensive and time consuming. However I
-       try to reply every email message I get (within a week). If you don't 
-       get response, please check how your address is written in the message
-       header. I can't answer if I don't have a valid reply address.
-
-Sound driver's home page is http://personal.eunet.fi/pp/voxware
index 0d7822104018265ba45e21ffe5ed1f43945d8d47..02217f2bde701e7556caf034c2060e81de1859d1 100644 (file)
@@ -1,8 +1,10 @@
 Configuring version 3.5 (for Linux) with some most common soundcards
 ====================================================================
 
-NOTE! This document may contain some error. Please inform me
-      if you find any mistakes.
+IMPORTANT!     This document covers only cards that were "known" when
+               this driver version was released. Please look at
+               http://personal.eunet.fi/pp/voxware for info about
+               cards introduced recently.
 
 Cards that are not (fully) supported by this driver
 ---------------------------------------------------
@@ -164,10 +166,14 @@ Audio Excell DSP16
        Support for this card is made by Riccardo Faccetti
        (riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info.
        
-Crystal CS4232 based cards such as AcerMagic S23 and many PC motherboards.
+Crystal CS4232 based cards such as AcerMagic S23 and many PC motherboards
+       (Compaq, HP, Intel, ...).
        CS4232 is a PnP multimedia chip which contains a CS3231A codec,
        SB and MPU401 emulations. There is support for OPL3 too.
-       (Unfortunately the MPU401 mode doesn't work).
+       This is a temporary driver which uses the chip in non PnP mode
+       (The final driver should be included in version 3.6 of the driver).
+       Unfortunately the MPU401 mode doesn't work. The chip may also stop
+       working after it has been used few times (only cold boot resets it).
 
 Turtle Beach Maui and Tropez
        This driver version supports sample, patch and program loading commands
@@ -527,11 +533,16 @@ If you have problems in recording with GUS MAX, you could try to use
 just one 8 bit DMA channel. Recording will not work with one DMA
 channel if it's a 16 bit one.
 
+Microphone input of GUS MAX is connected to mixer in little bit nonstandard
+way. There is actually two microphone volume controls. Normal "mic" controls
+only recording level. Mixer control "speaker" is used to control volume of
+microphone signal connected directly to line/speaker out. So just decrease
+volume of "speaker" if you have problems with microphone feedback.
 
 GUS ACE works too but any attempt to record or to use the MIDI port
 will fail.
 
-GUS PnP (with RAM) is supported but it needs to be initialized using
+GUS PnP (with RAM) is partially supported but it needs to be initialized using
 DOS before booting Linux. This may fail on machines having PnP BIOS.
 
 MPU401 and Windows Sound System
@@ -688,13 +699,10 @@ Tropez is jumper configurable and not connected to the MAD16 chip.
 It can be used by enabling the stand alone MPU401 support but you have
 to initialize it by using the MS-DOS SNDSETUP program.
 
-There are some other OPTi chips which may be used in soundcards such as
-82C930 and MAC32. These chips are not supported by the driver yet. Please
-contact me if you have a soundcard which uses these chips.
-
 Some MAD16 based cards may cause feedback, whistle or terrible noise if the
 line3 mixer channel is turned too high. This happens at least with Shuttle
-Sound System.
+Sound System. Current driver versions set volume of line3 low enough so
+this should not be a problem.
 
 If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer
 chip (_not_ an OPL3), you have to apped line containing #define MAD16_OPL4
index 72def564d372dea45c6d49092ecd571236149608..a37ab3515dd4047593982039c8ae0cd096ac78ae 100644 (file)
@@ -3,161 +3,39 @@ Installation
 
 IMPORTANT!     Read this if you are installing a separately
                distributed version of this driver.
+
                Check that your kernel version works with this
                release of the driver (see Readme). Also verify
                that your current kernel version doesn't have more
-               recent sound driver version than this one.
-
-- Since you are reading this, you have already installed the files so
-  let's skip this step. To be serious, the sound driver belongs
-  to linux/drivers/sound. 
+               recent sound driver version than this one. IT'S HIGHLY
+               RECOMMENDED THAT YOU USE THE SOUND DRIVER VERSION THAT
+               IS DISTRIBUTED WITH KERNEL SOURCES.
+
+- When installing separately distributed sound driver you should first
+  read the above notice. Then try to find proper directory where and how
+  to install the driver sources. You should not try to install a separately
+  distributed driver version if you are not able to find the proper way
+  yourself (in this case use the version that is distributed with kernel
+  sources). Remove old version of linux/drivers/sound directory before
+  installing new files.
 
 - To build the device files you need to run the enclosed shell scrip 
-  (see below).
-
-- If you are installing a separately distributed version, copy the
-  soundcard.h to /usr/include/linux. It may contain some new stuff.
-
-- Copy the sound/ultrasound.h  to /usr/include/sys
-  (Remove the old one from /usr/include/sys /usr/include/linux first).
-
-- Ensure you have the following symlink:
-  ln -s /usr/include/linux/soundcard.h /usr/include/sys/soundcard.h
+  (see below). You need to do this only when installing sound driver
+  first time or when upgrading to much recent version than the earlier
+  one.
 
 - Configure and compile Linux as normally (remember to include the
-  sound support during "make config").
+  sound support during "make config"). Please refer to kernel documentation
+  for instructions about configuring and compiling kernel. File Readme.cards
+  contains card spesific instructions for configuring this driver for
+  use with various soundcards.
 
 Boot time configuration (using lilo and insmod) 
 -----------------------------------------------
 
-NOTE!  This information is little bit obsolete since it doesn't cover
-       some cards recently added to the driver. The following text
-       describes parameters just for some older cards. In addition
-       this method will not work with cards which have more than one
-       DMA channel or if the driver number is bigger than 15. (Driver
-       numbers are defined in soundcard.h).
-
--------------------------------------------------------------------
-NOTE2! This method to configure the sound driver is not normally
-       required. All configuration information is entered when the
-       kernel/driver is compiled. This method just gives a way
-       to override some configuration parameters during boot.
-
-       So THE METHOD PRESENTED IN THIS CHAPTER IS NORMALLY COMPLETELY
-       USELESS. DON'T USE IT UNLESS YOU HAVE A VERY SPECIAL REASON TO
-       DO THAT.
-
-       !!!!!!!!!!!!!!!!!!!! PLEASE NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-       !!! Finding a working sound= command line is a difficult   !!!
-       !!! and timeconsuming task. For this reason I will not     !!!
-       !!! answer to messages asking about how to do it. So       !!!
-       !!! please don't use this method if you have any problems  !!!
-       !!! with it.                                               !!!
-       !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
--------------------------------------------------------------------
-
-This version of the sound driver has capability to accept the configuration
-parameters from the boot loader (for example lilo). By default the 
-driver is booted using the parameters given before compiling the driver
-('make config' or 'make soundconf'). If the kernel is booted using lilo and
-the boot command is given manually, it's possible to give the configuration
-parameters on the command line. Just hold down the <Alt> key when lilo
-starts. Then give the boot command manually and append a sound= argument
-to the boot command line. For example:
-
-lilo boot: linux sound=0x222071,0x138800
-
-The sound= argument could contain several configuration entries separated by a
-comma. Each option gives the configuration for one sound device.
-Give the options in the order given below. Other order of use is undefined.
-Each option is encoded as the following:
-
-       0xTaaaId, where
-          ||  ||
-          ||  |+----   d = DMA channel (0, 1, 3, 5, 6 or 7)
-          ||  +-----   I = IRQ (HEXADECIMAL!!! 1=1, ..., 9=9, 10=a, ..., 15=f)
-          |+-------- aaa = I/O address (hexadecimal)
-         +----------  T = device type  1=FM Synth (YM3812 or OPL3)
-                                       2=SoundBlaster (1.0 to 2.0, Pro, 16)
-                                       3=ProAudioSpectrum16
-                                       4=Gravis UltraSound
-                                       5=MPU-401 UART midi
-                                       6=SB16 (16 bit DMA number)
-                                       7=SB16 Midi (MPU-401 emulation)
-                       (There are some new ones also but they are currently
-                       not documented. The card numbers are in soundcard.h).
-
-These are the configuration templates for various soundcards:
-
-       0)      Disable the sound driver
-               
-               sound=0
-
-       1)      AdLib
-
-               sound=0x138800
-
-       2)      SoundBlaster family and compatibles
-
-               sound=0x2220Id,0x138800   (remember to set the IRQ and DMA)
-       or if you have SB16 or SB16ASP, you have to use the following:
-               (use the same IRQ (the I colums) in all three places. The
-                the D is the 16 bit DMA channel (5 to 7) and the d is 
-                the 8 bit one (1 or 3). The X is the 2nd digit of the
-                midi IO address (3 or 0)).
-               sound=0x2220Id,0x6220ID,0x73X0I0,0x138800
-
-       3)      ProAudioSpectrum16, ProAudioStudio16, Logitech Soundman16 etc.
-
-               sound=0x3388Id,0x2220Id,0x138800 (set the DMAs and IRQs)
-         
-       4)      Gravis UltraSound
-
-               sound=0x42X0Id  (X is 1, 2, 3 or 4. Set the DMA and IRQ)
-       
-       5)      MPU-401
-
-               sound=0x5aaaI0
-
-If you have more than one soundcards, you have to concatenate the options
-for each of the cards. There cannot be more than one sound= argument in the
-command line. For example use "sound=0x5aaaI0,0x138800" if you have AdLib
-and MPU-401 on your system. 
-If there are two or more sound= arguments
-in the boot command line, just the last one takes effect. The earlier ones
-will be ignored silently.
-
-The boot time configuration feature is intended mainly for distributors of
-precompiled kernels. When this feature is used, drivers for all of the
-cards have to be enabled before compiling the driver. The configurator program
-doesn't enable MPU-401 when the full driver option is selected. It must be
-enabled by uncommenting "#define EXCLUDE_MPU401" in the sound/local.h.
-
-Important note!
-
-The sound driver is enabled by default. If the kernel is booted without
-using the sound=0 option, the sound driver is initialized using the compile
-time parameters. This could be dangerous (specially if the MPU-401 driver
-is enabled with I/O address 0x330 (used by AHA-1542 also)). If you want to
-compile the driver to be inactive by default, you have to append a
-#define SND_DEFAULT_ENABLE     0
-to the sound/local.h before compiling the driver.
-
-Remember to check that the sound setup routine is included in the 
-bootparams structure in linux/init/main.c. It should contain the following
-lines:
-
-#ifdef CONFIG_SOUND
-       { "sound=", sound_setup },
-#endif
-
-In case these lines were not there, you have to insert them (the driver works
-without them but it's not possible to give the boot time parameters for the
-sound driver). Add also the following line somewhere near the beginning of
-linux/init/main.c:
-
-extern void sound_setup(char *str, int *ints);
+This information has been removed. Too many users did't believe
+that it's really not necessary to use this method. Please look at
+Readme of sound driver version 3.0.1 if you still want to use this method.
 
 Problems
 --------
@@ -171,33 +49,25 @@ command:
 and look at the output. It should display some usefull info about the
 driver configuration. If there is no /dev/sndstat 
 (/dev/sndstat: No such file or directory), ensure that you have executed the
-soundinstall script (at the end of this file). The message: 
-/dev/dsp: No such device means that you don't have the sound driver installed
-on your kernel or the driver version is earlier than 1.99.6.
+soundinstall script (at the end of this file).
 
+Common error messages:
 
 - /dev/???????: No such file or directory.
 Run the script at the end of this file.
 
 - /dev/???????: No such device.
-You have not booted with a kernel containing the driver or the I/O address
-configuration doesn't match your hardaware. 
+You are not running kernel which contains the sound driver. When using
+modularized sound driver this error means that the sound driver is not
+loaded.
 
-- The module player (str) plays just a second and then stops completely.
-You have incorrect IRQ settings (usual with SB cards).
+- /dev/????: No such device or address.
+Sound driver didn't detect suitable card when initializing. Please look at
+Readme.cards for info about configuring the driver with your card. Also
+check for possible boot (insmod) time error messages in /var/adm/messages.
 
-- There is pauses in the playback of the module player (str).
-The str program requires more than 40% of the speed of a 486/50 to play
-without pauses at 44 kHz speed. A 386/25 can hardly play faster than 22 kHz.
-You should use lower speed (-s speed), buy a faster computer or a Gravis 
-UltraSound card. (If you already have GUS, you should use gmod and not the
-str). If the DSP_BUFFSIZE in the sound/local.h is less than (nr_channels*
-speed_in_Hz * (bits/8))/2, it could explain the pausing problem. Also check
-that the turbo swich is on and don't run applications like weather forecasting
-on background. Sometimes (very rarely) an IRQ conflict can cause similar
-problems with SB cards.
-If you want to play modules on a 386sx while recompiling the world, buy a GUS.
-It runs without burning your CPU.
+- Other messages or problems
+Please check http://personal.eunet.fi/pp/voxware for more info.
 
 Hannu Savolainen
 hannu@voxware.pp.fi
index cfec50bcd29f3ccc8054a1664eb263c41a038f8f..1d6009bf293bee6cb93925d07612aa1a037d2c5a 100644 (file)
@@ -39,6 +39,9 @@
  */
 #include <linux/config.h>
 
+
+#define DEB(x)
+#define DEB1(x)
 #include "sound_config.h"
 
 #if defined(CONFIG_AD1848)
@@ -151,7 +154,7 @@ static void
 ad_write (ad1848_info * devc, int reg, int data)
 {
   unsigned long   flags;
-  int             timeout = 90000;
+  int             timeout = 900000;
 
   while (timeout > 0 &&
         inb (devc->base) == 0x80)      /*Are we initializing */
@@ -178,7 +181,7 @@ wait_for_calibration (ad1848_info * devc)
    */
 
   timeout = 100000;
-  while (timeout > 0 && inb (devc->base) & 0x80)
+  while (timeout > 0 && inb (devc->base) == 0x80)
     timeout--;
   if (inb (devc->base) & 0x80)
     printk ("ad1848: Auto calibration timed out(1).\n");
@@ -189,7 +192,7 @@ wait_for_calibration (ad1848_info * devc)
   if (!(ad_read (devc, 11) & 0x20))
     return;
 
-  timeout = 20000;
+  timeout = 40000;
   while (timeout > 0 && ad_read (devc, 11) & 0x20)
     timeout--;
   if (ad_read (devc, 11) & 0x20)
@@ -199,31 +202,11 @@ wait_for_calibration (ad1848_info * devc)
 static void
 ad_mute (ad1848_info * devc)
 {
-  int             i;
-  unsigned char   prev;
-
-  /*
-     * Save old register settings and mute output channels
-   */
-  for (i = 6; i < 8; i++)
-    {
-      prev = devc->saved_regs[i] = ad_read (devc, i);
-      ad_write (devc, i, prev | 0x80);
-    }
 }
 
 static void
 ad_unmute (ad1848_info * devc)
 {
-  int             i;
-
-  /*
-     * Restore back old volume registers (unmute)
-   */
-  for (i = 6; i < 8; i++)
-    {
-      ad_write (devc, i, devc->saved_regs[i] & ~0x80);
-    }
 }
 
 static void
@@ -440,6 +423,8 @@ ad1848_mixer_reset (ad1848_info * devc)
   switch (devc->mode)
     {
     case MD_4231:
+    case MD_4231A:
+    case MD_1845:
       devc->supported_devices = MODE2_MIXER_DEVICES;
       break;
 
@@ -584,7 +569,7 @@ ad1848_open (int dev, int mode)
   ad1848_trigger (dev, 0);
   restore_flags (flags);
 /*
- * Mute output until the playback really starts. This decreases clicking.
+ * Mute output until the playback really starts. This decreases clicking (hope so).
  */
   ad_mute (devc);
 
@@ -597,7 +582,7 @@ ad1848_close (int dev)
   unsigned long   flags;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
-  DDB (printk ("ad1848_close(void)\n"));
+  DEB (printk ("ad1848_close(void)\n"));
 
   save_flags (flags);
   cli ();
@@ -1393,7 +1378,7 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture
    */
   static int      init_values[] =
   {
-    0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x80, 0x80,
+    0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
     0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
 
   /* Positions 16 to 31 just for CS4231 */
@@ -1525,13 +1510,11 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture
       if (!share_dma)
        {
          if (sound_alloc_dma (dma_playback, "Sound System"))
-           printk ("ad1848.c: Can't allocate DMA%d for playback\n",
-                   dma_playback);
+           printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback);
 
-         if (dma_capture != dma_playback && dma_capture != -1)
+         if (dma_capture != dma_playback)
            if (sound_alloc_dma (dma_capture, "Sound System (capture)"))
-             printk ("ad1848.c: Can't allocate DMA%d for capture\n",
-                     dma_capture);
+             printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture);
        }
 
       /*
@@ -1707,16 +1690,26 @@ probe_ms_sound (struct address_info *hw_config)
 
   if ((tmp = inb (hw_config->io_base + 3)) == 0xff)    /* Bus float */
     {
+      int             ret;
+
       DDB (printk ("I/O address is inactive (%x)\n", tmp));
-      return 0;
+      if (!(ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp)))
+       return 0;
+      return 1;
     }
   if ((tmp & 0x3f) != 0x04 &&
       (tmp & 0x3f) != 0x0f &&
       (tmp & 0x3f) != 0x00)
     {
+      int             ret;
+
       DDB (printk ("No MSS signature detected on port 0x%x (0x%x)\n",
                   hw_config->io_base, inb (hw_config->io_base + 3)));
-      return 0;
+      DDB (printk ("Trying to detect codec anyway but IRQ/DMA may not work\n"));
+      if (!(ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp)))
+       return 0;
+
+      return 1;
     }
 
   if (hw_config->irq > 11)
index b66110262435eef4052cf0429cc5a39671797f2f..4a7a8d9251001d928a40f8c99807f60d24027238 100644 (file)
@@ -51,7 +51,7 @@ static int      audio_format[MAX_AUDIO_DEV];
 static int      local_conversion[MAX_AUDIO_DEV];
 
 static int
-set_format (int dev, long fmt)
+set_format (int dev, int fmt)
 {
   if (fmt != AFMT_QUERY)
     {
@@ -80,7 +80,7 @@ int
 audio_open (int dev, struct fileinfo *file)
 {
   int             ret;
-  long            bits;
+  int             bits;
   int             dev_type = dev & 0x0f;
   int             mode = file->mode & O_ACCMODE;
 
index 25f3f6e0c07b17d1507ba4e309593365a260c1e4..e10831eecd14099911780e433b9f0f46f990c64b 100644 (file)
@@ -37,6 +37,8 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
 
 #define B(x)   (1 << (x))
 
@@ -176,12 +178,12 @@ char           *questions[] =
   "Support for MAD16 and/or Mozart based cards",
   "Support for Crystal CS4232 based (PnP) cards",
   "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers",
-  "Support for PnP soundcards (_EXPERIMENTAL_)",
+  "Support for PnP sound cards (_EXPERIMENTAL_)",
 
   "SoundBlaster Pro support",
   "SoundBlaster 16 support",
   "Audio Excel DSP 16 initialization support",
-  "/dev/dsp and /dev/audio supports (usually required)",
+  "/dev/dsp and /dev/audio support",
   "This should not be asked",
   "MIDI interface support",
   "This should not be asked",
@@ -190,6 +192,99 @@ char           *questions[] =
   "Is the sky really falling"
 };
 
+/* help text for each option */
+char           *help[] =
+{
+  "Enable this option only if you have a Pro Audio Spectrum 16,\n"
+  "Pro Audio Studio 16, or Logitech SoundMan 16. Don't enable this if\n"
+  "you have some other card made by MediaVision or Logitech as\n"
+  "they are not PAS16 compatible.\n",
+
+  "Enable this if you have an original SoundBlaster card made by\n"
+  "Creative Labs or a 100%% hardware compatible clone. For an\n"
+  "unknown card you may want to try this if it claims to be\n"
+  "SoundBlaster compatible.\n",
+
+  "Enable this option if your sound card has a Yamaha OPL2 or OPL3\n"
+  "FM synthesizer chip.\n",
+
+  "Enable this option for any type of Gravis Ultrasound card\n"
+  "including the GUS or GUS MAX.\n",
+
+  "The MPU401 interface is supported by almost all sound cards. However,\n"
+  "some natively supported cards have their own driver for\n"
+  "MPU401. Enabling the MPU401 option with these cards will cause a\n"
+  "conflict. Also enabling MPU401 on a system that doesn't really have a\n"
+  "MPU401 could cause some trouble. It's safe to enable this if you have a\n"
+  "true MPU401 MIDI interface card.\n",
+
+  "This option enables support for MIDI interfaces based on the 6850\n"
+  "UART chip. This interface is rarely found on sound cards.\n",
+
+  "Enable this option if you have an Orchid SW32, Cardinal DSP16 or other\n"
+  "sound card based on the PSS chipset (AD1848 codec, ADSP-2115 DSP chip,\n"
+  "and Echo ESC614 ASIC CHIP).\n",
+
+  "Enable this if you have installed the 16-bit sampling daughtercard on\n"
+  "your GUS card. Do not use if you have a GUS MAX as enabling this option\n"
+  "disables GUS MAX support.\n",
+
+  "Enable this option if you have a Gravis Ultrasound MAX sound\n"
+  "card\n",
+
+  "Enable this option if you have the original Windows Sound System\n"
+  "card made by Microsoft or the Aztech SG 16 Pro or NX16 Pro.\n",
+
+  "Enable this if you have a sound card based on the Ensoniq\n"
+  "Soundscape chipset. Such cards are being manufactured by Ensoniq,\n"
+  "Spea and Reveal (Reveal makes other cards as well).\n",
+
+  "Enable this option if you have the AudioTriX Pro sound card\n"
+  "manufactured by MediaTrix.\n",
+
+  "Enable this if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi\n"
+  "82C928 or 82C929) audio interface chip. These chips are currently\n"
+  "quite common so it's possible that many no-name cards have one of\n"
+  "them. In addition the MAD16 chip is used in some cards made by known\n"
+  "manufacturers such as Turtle Beach (Tropez), Reveal (some models) and\n"
+  "Diamond (latest ones).\n",
+
+  "Enable this if you have a card based on the Crystal CS4232 chip set.\n",
+
+  "Enable this option if you have a Turtle Beach Wave Front, Maui,\n"
+  "or Tropez sound card.\n",
+
+  "Use this option to enable experimental support for cards that\n"
+  "use the Plug and Play protocol.\n",
+
+  "Enable this option if your card is a SoundBlaster Pro or\n"
+  "SoundBlaster 16. It also works with many SoundBlaster Pro clones.\n",
+
+  "Enable this if you have a SoundBlaster 16, including the AWE32.\n",
+
+  "Enable this if you have an Audio Excel DSP16 card. See the file\n"
+  "Readme.aedsp16 for more information.\n",
+
+  "This option enables the A/D and D/A converter (PCM) devices\n"
+  "supported by almost all sound cards.\n",
+
+  "This should not be asked",
+
+  "This enables the dev/midixx devices and access to any MIDI ports\n"
+  "using /dev/sequencer and /dev/music. This option also affects any\n"
+  "MPU401 and/or General MIDI compatible devices.\n",
+
+  "This should not be asked",
+
+  "This enables the Yamaha FM synthesizer chip used on many sound\n"
+  "cards.\n",
+
+  "This enables the /dev/sequencer and /dev/music devices used for\n"
+  "playing computer music.\n",
+
+  "Is the sky really falling"
+};
+
 struct kludge
   {
     char           *name;
@@ -244,11 +339,18 @@ can_select_option (int nr)
 }
 
 int
-think_positively (int def_answ)
+think_positively (char *prompt, int def_answ, char *help)
 {
   char            answ[512];
   int             len;
 
+response:
+  fprintf (stderr, prompt);
+  if (def_answ)
+    fprintf (stderr, " [Y/n/?] ");
+  else
+    fprintf (stderr, " [N/y/?] ");
+
   if ((len = read (0, answ, sizeof (answ))) < 1)
     {
       fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
@@ -263,6 +365,14 @@ think_positively (int def_answ)
                                 */
     return def_answ;
 
+  if (answ[0] == '?')
+    {                          /* display help message */
+      fprintf (stderr, "\n");
+      fprintf (stderr, help);
+      fprintf (stderr, "\n");
+      goto response;
+    }
+
   answ[len - 1] = 0;
 
   if (!strcmp (answ, "y") || !strcmp (answ, "Y"))
@@ -322,7 +432,7 @@ ask_int_choice (int mask, char *macro,
       for (i = 0; i < OPT_LAST; i++)
        if (mask == B (i))
          {
-           int             j;
+           unsigned int    j;
 
            for (j = 0; j < strlen (choices); j++)
              if (choices[j] == '\'')
@@ -343,7 +453,8 @@ ask_int_choice (int mask, char *macro,
        return;
 
       fprintf (stderr, "\n%s\n", question);
-      fprintf (stderr, "Possible values are: %s\n", choices);
+      if (strcmp (choices, ""))
+       fprintf (stderr, "Possible values are: %s\n", choices);
 
       if (format == FMT_INT)
        {
@@ -375,7 +486,7 @@ ask_int_choice (int mask, char *macro,
 void
 rebuild_file (char *line)
 {
-  char           *method, *new, *old, *var, *p;
+  char           *method, *next, *old, *var, *p;
 
   method = p = line;
 
@@ -388,7 +499,7 @@ rebuild_file (char *line)
     p++;
   *p++ = 0;
 
-  new = p;
+  next = p;
   while (*p && *p != ' ')
     p++;
   *p++ = 0;
@@ -398,11 +509,11 @@ rebuild_file (char *line)
     p++;
   *p++ = 0;
 
-  fprintf (stderr, "Rebuilding file %s (%s %s)\n", new, method, old);
+  fprintf (stderr, "Rebuilding file `%s' (%s %s)\n", next, method, old);
 
   if (strcmp (method, "bin2hex") == 0)
     {
-      if (!bin2hex (old, new, var))
+      if (!bin2hex (old, next, var))
        {
          fprintf (stderr, "Rebuild failed\n");
          exit (-1);
@@ -410,7 +521,7 @@ rebuild_file (char *line)
     }
   else if (strcmp (method, "hex2hex") == 0)
     {
-      if (!hex2hex (old, new, var))
+      if (!hex2hex (old, next, var))
        {
          fprintf (stderr, "Rebuild failed\n");
          exit (-1);
@@ -418,8 +529,8 @@ rebuild_file (char *line)
     }
   else
     {
-      fprintf (stderr, "Failed to build '%s' - unknown method %s\n",
-              new, method);
+      fprintf (stderr, "Failed to build `%s' - unknown method %s\n",
+              next, method);
       exit (-1);
     }
 }
@@ -432,7 +543,7 @@ use_old_config (char *filename)
 
   FILE           *oldf;
 
-  fprintf (stderr, "Copying old configuration from %s\n", filename);
+  fprintf (stderr, "Copying old configuration from `%s'\n", filename);
 
   if ((oldf = fopen (filename, "r")) == NULL)
     {
@@ -638,74 +749,66 @@ ask_parameters (void)
                  "I/O base for SB",
                  FMT_HEX,
                  0x220,
-                 "");
+                 "Check from manual of the card");
 
   ask_int_choice (B (OPT_SB), "SBC_IRQ",
                  "SoundBlaster IRQ",
                  FMT_INT,
                  7,
-                 "");
+                 "Check from manual of the card");
 
   ask_int_choice (B (OPT_SB), "SBC_DMA",
                  "SoundBlaster DMA",
                  FMT_INT,
                  1,
-                 "");
+                 "0, 1 or 3");
 
   ask_int_choice (B (OPT_SB), "SB_DMA2",
-                 "SoundBlaster 16 bit DMA (if required)",
+               "SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
                  FMT_INT,
-                 -1,
+                 5,
                  "5, 6 or 7");
 
   ask_int_choice (B (OPT_SB), "SB_MPU_BASE",
                  "MPU401 I/O base of SB16, Jazz16 and ES1688",
                  FMT_HEX,
                  0,
-                 "");
+                 "Check from manual of the card");
 
   ask_int_choice (B (OPT_SB), "SB_MPU_IRQ",
                  "SB MPU401 IRQ (SB16, Jazz16 and ES1688)",
                  FMT_INT,
                  -1,
-                 "");
+                 "Check from manual of the card");
 
   ask_int_choice (B (OPT_PAS), "PAS_IRQ",
                  "PAS16 IRQ",
                  FMT_INT,
                  10,
-                 "");
+                 "3, 4, 5, 7, 9, 10, 11, 12, 14 or 15");
 
   ask_int_choice (B (OPT_PAS), "PAS_DMA",
                  "PAS16 DMA",
                  FMT_INT,
                  3,
-                 "");
+                 "0, 1, 3, 5, 6 or 7");
 
   if (selected_options & B (OPT_PAS))
     {
-      fprintf (stderr, "\nEnable Joystick port on ProAudioSpectrum (y/N) ? ");
-      if (think_positively (0))
-       printf ("#define PAS_JOYSTICK_ENABLE\n");
+      if (think_positively ("Enable Joystick port on ProAudioSpectrum", 0,
+       "Enable this option if you want to use the joystick port provided\n"
+                           "on the PAS sound card.\n"));
 
+      printf ("#define PAS_JOYSTICK_ENABLE\n");
 
-      fprintf (stderr, "PAS16 could be noisy with some mother boards\n"
-              "There is a command line switch (was it :T?)\n"
-              "in the DOS driver for PAS16 which solves this.\n"
-              "Don't enable this feature unless you have problems!\n"
-              "Do you have to use this switch with DOS (Y/n) ?");
-      if (think_positively (0))
+      if (think_positively ("Enable PAS16 bus clock option", 0,
+       "The PAS16 can be noisy with some motherboards. There is a command\n"
+       "line switch (:T?) in the DOS driver for PAS16 which solves this.\n"
+      "Don't enable this feature unless you have problems and have to use\n"
+                           "this switch with DOS\n"))
        printf ("#define BROKEN_BUS_CLOCK\n");
-
-      fprintf (stderr, "PAS16 has SoundBlaster emulation. You should disable\n"
-              "this feature if you have another SB compatible card\n"
-              "on the machine\n"
-              "Do you want to disable SB emulation of PAS16 (y/N) ?");
-      if (think_positively (0))
-       printf ("#define DISABLE_SB_EMULATION\n");
     }
 
-
   ask_int_choice (B (OPT_GUS), "GUS_BASE",
                  "I/O base for GUS",
                  FMT_HEX,
@@ -717,19 +820,19 @@ ask_parameters (void)
                  "GUS IRQ",
                  FMT_INT,
                  15,
-                 "");
+                 "3, 5, 7, 9, 11, 12 or 15");
 
   ask_int_choice (B (OPT_GUS), "GUS_DMA",
                  "GUS DMA",
                  FMT_INT,
                  6,
-                 "");
+                 "1, 3, 5, 6 or 7");
 
   ask_int_choice (B (OPT_GUS), "GUS_DMA2",
                  "Second DMA channel for GUS",
                  FMT_INT,
                  -1,
-                 "");
+                 "1, 3, 5, 6 or 7");
 
   ask_int_choice (B (OPT_GUS16), "GUS16_BASE",
                  "I/O base for the 16 bit daughtercard of GUS",
@@ -754,13 +857,13 @@ ask_parameters (void)
                  "I/O base for MPU401",
                  FMT_HEX,
                  0x330,
-                 "");
+                 "Check from manual of the card");
 
   ask_int_choice (B (OPT_MPU401), "MPU_IRQ",
                  "MPU401 IRQ",
                  FMT_INT,
                  9,
-                 "");
+                 "Check from manual of the card");
 
   ask_int_choice (B (OPT_MAUI), "MAUI_BASE",
                  "I/O base for Maui",
@@ -880,8 +983,11 @@ ask_parameters (void)
     {
       int             reveal_spea;
 
-      fprintf (stderr, "Is your SoundScape card made/marketed by Reveal or Spea? ");
-      reveal_spea = think_positively (0);
+      reveal_spea = think_positively (
+                 "Is your SoundScape card made/marketed by Reveal or Spea",
+                                      0,
+                "Enable if you have a SoundScape card with the Reveal or\n"
+                                      "Spea name on it.\n");
       if (reveal_spea)
        printf ("#define REVEAL_SPEA\n");
 
@@ -1081,7 +1187,7 @@ dump_fixed_defines (void)
 
   while (extra_options[i].name != NULL)
     {
-      int             n = 0, j;
+      int             j;
 
       for (j = 0; j < OPT_LAST; j++)
        if (!(DISABLED_OPTIONS & B (j)))
@@ -1099,8 +1205,7 @@ dump_fixed_defines (void)
 int
 main (int argc, char *argv[])
 {
-  int             i, num, full_driver = 1;
-  char            answ[10];
+  int             i, full_driver = 1;
   char            old_config_file[200];
 
   if (getuid () != 0)          /* Not root */
@@ -1136,16 +1241,18 @@ main (int argc, char *argv[])
        }
     }
 
-  fprintf (stderr, "\nConfiguring the sound support\n\n");
+  fprintf (stderr, "\nConfiguring Sound Support\n\n");
 
   if (access (oldconf, R_OK) == 0)
     {
-      fprintf (stderr, "Old configuration exists in %s. Use it (Y/n) ? ",
-              oldconf);
-      if (think_positively (1))
+      char            str[255];
+
+      sprintf (str, "Old configuration exists in `%s'. Use it", oldconf);
+      if (think_positively (str, 1,
+      "Enable this option to load the previously saved configuration file\n"
+                           "for all of the sound driver parameters.\n"))
        if (use_old_config (oldconf))
          exit (0);
-
     }
 
   printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n");
@@ -1177,10 +1284,7 @@ main (int argc, char *argv[])
              {
                int             def_answ = hw_table[i].default_answ;
 
-               fprintf (stderr,
-                        def_answ ? "  %s (Y/n) ? " : "  %s (y/N) ? ",
-                        questions[i]);
-               if (think_positively (def_answ))
+               if (think_positively (questions[i], def_answ, help[i]))
                  if (hw_table[i].alias)
                    selected_options |= B (hw_table[i].alias);
                  else
@@ -1191,30 +1295,29 @@ main (int argc, char *argv[])
 
   if (selected_options & B (OPT_SBPRO))
     {
-      fprintf (stderr, "Do you want support for the mixer of SG NX Pro ? ");
-      if (think_positively (0))
+      if (think_positively (
+                            "Support for the SG NX Pro mixer", 0,
+       "Enable this if you want to support the additional mixer functions\n"
+                         "provided on Sound Galaxy NX Pro sound cards.\n"))
        printf ("#define __SGNXPRO__\n");
     }
 
   if (selected_options & B (OPT_SB))
     {
-      fprintf (stderr, "Do you want support for the MV Jazz16 (ProSonic etc.) ? ");
-      if (think_positively (0))
+      if (think_positively ("Support for the MV Jazz16 (ProSonic etc.)", 0,
+         "Enable this if you have an MV Jazz16 or ProSonic sound card.\n"))
        {
-         fprintf (stderr, "Do you have SoundMan Wave (y/N) ? ");
-
-         if (think_positively (0))
+         if (think_positively ("Do you have SoundMan Wave", 0,
+                               "Enable this option of you have the Logitech SoundMan Wave sound card.\n"))
            {
              printf ("#define SM_WAVE\n");
 
            midi0001_again:
-             fprintf
-               (stderr,
-                "Logitech SoundMan Wave has a microcontroller which must be initialized\n"
-                "before MIDI emulation works. This is possible only if the microcode\n"
-                "file is compiled into the driver.\n"
-                "Do you have access to the MIDI0001.BIN file (Y/n) ? ");
-             if (think_positively (1))
+             if (think_positively (
+                          "Do you have access to the MIDI0001.BIN file", 1,
+                                    "The Logitech SoundMan Wave has a microcontroller which must be\n"
+                                    "initialized before MIDI emulation works. This is possible only if the\n"
+                          "microcode file is compiled into the driver.\n"))
                {
                  char            path[512];
 
@@ -1225,10 +1328,11 @@ main (int argc, char *argv[])
 
                  if (!bin2hex (path, "smw-midi0001.h", "smw_ucode"))
                    {
-                     fprintf (stderr, "couldn't open %s file\n",
+                     fprintf (stderr, "Couldn't open file %s\n",
                               path);
-                     fprintf (stderr, "try again with correct path? ");
-                     if (think_positively (1))
+                     if (think_positively ("Try again with correct path", 1,
+                                           "The specified file could not be opened. Enter the correct path to the\n"
+                                           "file.\n"))
                        goto midi0001_again;
                    }
                  else
@@ -1241,19 +1345,16 @@ main (int argc, char *argv[])
        }
     }
 
-  if (selected_options & B (OPT_SBPRO))
+  if (selected_options & B (OPT_SB))
     {
-      fprintf (stderr, "\n\nThe Logitech SoundMan Games supports 44 kHz in stereo\n"
-              "while the standard SB Pro supports just 22 kHz/stereo\n"
-              "You have an option to enable the SM Games mode.\n"
-              "However do enable it only if you are _sure_ that your\n"
-              "card is a SM Games. Enabling this feature with a\n"
-              "plain old SB Pro _will_ cause troubles with stereo mode.\n"
-              "\n"
-              "DANGER! Read the above once again before answering 'y'\n"
-              "Answer 'n' in case you are unsure what to do!\n");
-      fprintf (stderr, "Do you have a Logitech SoundMan Games (y/N) ? ");
-      if (think_positively (0))
+      if (think_positively ("Do you have a Logitech SoundMan Games", 0,
+        "The Logitech SoundMan Games supports 44 kHz in stereo while the\n"
+      "standard SB Pro supports just 22 kHz stereo. You have the option of\n"
+                           "enabling SM Games mode.  However, enable it only if you are sure that\n"
+      "your card is an SM Games. Enabling this feature with a plain old SB\n"
+                           "Pro will cause troubles with stereo mode.\n\n"
+                 "DANGER! Read the above once again before answering 'y'\n"
+                           "Answer 'n' if you are unsure what to do!\n"))
        printf ("#define SM_GAMES\n");
     }
 
@@ -1266,8 +1367,12 @@ main (int argc, char *argv[])
 
       if (selected_options & B (OPT_SBPRO))
        {
-         fprintf (stderr, "Do you want support for the Audio Excel SoundBlaster pro mode ? ");
-         if (think_positively (1))
+
+         if (think_positively (
+           "Do you want support for the Audio Excel SoundBlaster Pro mode",
+                                1,
+                                "Enable this option if you want the Audio Excel sound card to operate\n"
+                                "in SoundBlaster Pro mode.\n"))
            {
              printf ("#define AEDSP16_SBPRO\n");
              sel1 = 1;
@@ -1276,8 +1381,12 @@ main (int argc, char *argv[])
 
       if ((selected_options & B (OPT_MSS)) && (sel1 == 0))
        {
-         fprintf (stderr, "Do you want support for the Audio Excel Microsoft Sound System mode? ");
-         if (think_positively (1))
+
+         if (think_positively (
+                                "Do you want support for the Audio Excel Microsoft Sound System mode",
+                                1,
+                                "Enable this option if you want the Audio Excel sound card to operate\n"
+                                "in Microsoft Sound System mode.\n"))
            {
              printf ("#define AEDSP16_MSS\n");
              sel1 = 1;
@@ -1297,12 +1406,9 @@ main (int argc, char *argv[])
   if (selected_options & B (OPT_PSS))
     {
     genld_again:
-      fprintf
-       (stderr,
-       "if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n"
-        "then you must include the LD in the kernel.\n"
-        "Do you wish to include a LD (Y/n) ? ");
-      if (think_positively (1))
+      if (think_positively ("Do you wish to include an LD file", 1,
+                           "If you want to emulate the SoundBlaster card and you have a DSPxxx.LD\n"
+                     "file then you must include the LD in the kernel.\n"))
        {
          char            path[512];
 
@@ -1313,10 +1419,9 @@ main (int argc, char *argv[])
 
          if (!bin2hex (path, "synth-ld.h", "pss_synth"))
            {
-             fprintf (stderr, "couldn't open %s as the ld file\n",
-                      path);
-             fprintf (stderr, "try again with correct path? ");
-             if (think_positively (1))
+             fprintf (stderr, "couldn't open `%s' as the LD file\n", path);
+             if (think_positively ("try again with correct path", 1,
+                                   "The given LD file could not opened.\n"))
                goto genld_again;
            }
          else
@@ -1339,24 +1444,21 @@ main (int argc, char *argv[])
   if (selected_options & B (OPT_TRIX))
     {
     hex2hex_again:
-      fprintf (stderr, "MediaTriX audioTriX Pro has a onboard microcontroller\n"
-              "which needs to be initialized by downloading\n"
-              "the code from file TRXPRO.HEX in the DOS driver\n"
-              "directory. If you don't have the TRXPRO.HEX handy\n"
-              "you may skip this step. However SB and MPU-401\n"
-              "modes of AudioTriX Pro will not work without\n"
-              "this file!\n"
-              "\n"
-              "Do you want to include TRXPRO.HEX in your kernel (Y/n) ? ");
-
-      if (think_positively (1))
+
+      if (think_positively ("Do you want to include TRXPRO.HEX in your kernel",
+                           1,
+       "The MediaTriX AudioTrix Pro has an onboard microcontroller which\n"
+                           "needs to be initialized by downloading the code from the file TRXPRO.HEX\n"
+                           "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n"
+                           "you may skip this step. However, the SB and MPU-401 modes of AudioTriX\n"
+                           "Pro will not work without this file!\n"))
        {
          char            path[512];
 
          fprintf (stderr,
                 "Enter the path to your TRXPRO.HEX file (pwd is sound): ");
          scanf ("%s", path);
-         fprintf (stderr, "including HEX file %s\n", path);
+         fprintf (stderr, "including HEX file `%s'\n", path);
 
          if (!hex2hex (path, "trix_boot.h", "trix_boot"))
            goto hex2hex_again;
@@ -1365,13 +1467,10 @@ main (int argc, char *argv[])
        }
     }
 
-  if (selected_options & B (OPT_SB))
-    selected_options |= B (OPT_SBPRO) | B (OPT_SB16);
-
   if (!(selected_options & ANY_DEVS))
     {
       printf ("invalid_configuration__run_make_config_again\n");
-      fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n\n");
+      fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device    ***\n\n");
       exit (0);
     }
 
@@ -1382,7 +1481,6 @@ main (int argc, char *argv[])
       else
        printf ("#undef  CONFIG_%s\n", hw_table[i].macro);
 
-
   printf ("\n");
 
   i = 0;
@@ -1400,8 +1498,8 @@ main (int argc, char *argv[])
 
   ask_parameters ();
 
-  printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
-  fprintf (stderr, "The sound driver is now configured.\n");
+  printf ("#define SELECTED_SOUND_OPTIONS\t0x%08lx\n", selected_options);
+  fprintf (stderr, "\nThe sound driver is now configured.\n");
 
 #if defined(SCO) || defined(ISC) || defined(SYSV)
   fprintf (stderr, "Remember to update the System file\n");
@@ -1409,8 +1507,13 @@ main (int argc, char *argv[])
 
   if (!old_config_used)
     {
-      fprintf (stderr, "Save copy of this configuration to %s (Y/n)", oldconf);
-      if (think_positively (1))
+      char            str[255];
+
+      sprintf (str, "Save copy of this configuration to `%s'", oldconf);
+      if (think_positively (str, 1,
+       "If you enable this option then the sound driver configuration is\n"
+      "saved to a file. If you later need to recompile the kernel you have\n"
+                         "the option of using the saved configuration.\n"))
        {
          char            cmd[200];
 
@@ -1436,7 +1539,7 @@ bin2hex (char *path, char *target, char *varname)
     {
       FILE           *sf = fopen (target, "w");
 
-      fprintf (sf, "/* automaticaly generated by configure */\n");
+      fprintf (sf, "/* automatically generated by configure */\n");
       fprintf (sf, "static unsigned char %s[] = {\n", varname);
       while (1)
        {
@@ -1445,7 +1548,7 @@ bin2hex (char *path, char *target, char *varname)
            break;
          if (i != 0 && (i % 10) == 0)
            fprintf (sf, "\n");
-         fprintf (sf, "0x%02x,", c & 0xFFL);
+         fprintf (sf, "0x%02lx,", c & 0xFFL);
          i++;
        }
       fprintf (sf, "};\n"
index c59f41381ff5a373e3c2d19d5d97050b9884809a..acba7456a21e110b04e0162f876d75f557ef7e9a 100644 (file)
@@ -88,6 +88,10 @@ probe_cs4232 (struct address_info *hw_config)
   int             base = hw_config->io_base, irq = hw_config->irq;
   int             dma1 = hw_config->dma, dma2 = hw_config->dma2;
 
+  static wait_handle *cs_sleeper = NULL;
+  static volatile struct snd_wait cs_sleep_flag =
+  {0};
+
   osp = hw_config->osp;
 
 /*
@@ -118,12 +122,31 @@ probe_cs4232 (struct address_info *hw_config)
 
   for (n = 0; n < 4; n++)
     {
+      cs_sleep_flag.mode = WK_NONE;
 /*
  * Wake up the card by sending a 32 byte Crystal key to the key port.
  */
       for (i = 0; i < 32; i++)
        CS_OUT (crystal_key[i]);
 
+
+      {
+       unsigned long   tl;
+
+       if (HZ / 10)
+         current_set_timeout (tl = jiffies + (HZ / 10));
+       else
+         tl = (unsigned long) -1;
+       cs_sleep_flag.mode = WK_SLEEP;
+       module_interruptible_sleep_on (&cs_sleeper);
+       if (!(cs_sleep_flag.mode & WK_WAKEUP))
+         {
+           if (jiffies >= tl)
+             cs_sleep_flag.mode |= WK_TIMEOUT;
+         }
+       cs_sleep_flag.mode &= ~WK_SLEEP;
+      };                       /* Delay */
+
 /*
  * Now set the CSN (Card Select Number).
  */
@@ -154,6 +177,24 @@ probe_cs4232 (struct address_info *hw_config)
 
       CS_OUT2 (0x33, 0x01);    /* Activate logical dev 0 */
 
+
+      {
+       unsigned long   tl;
+
+       if (HZ / 10)
+         current_set_timeout (tl = jiffies + (HZ / 10));
+       else
+         tl = (unsigned long) -1;
+       cs_sleep_flag.mode = WK_SLEEP;
+       module_interruptible_sleep_on (&cs_sleeper);
+       if (!(cs_sleep_flag.mode & WK_WAKEUP))
+         {
+           if (jiffies >= tl)
+             cs_sleep_flag.mode |= WK_TIMEOUT;
+         }
+       cs_sleep_flag.mode &= ~WK_SLEEP;
+      };                       /* Delay */
+
 /*
  * Initialize logical device 3 (MPU)
  */
@@ -173,12 +214,48 @@ probe_cs4232 (struct address_info *hw_config)
  */
       CS_OUT (0x79);
 
+
+      {
+       unsigned long   tl;
+
+       if (HZ / 5)
+         current_set_timeout (tl = jiffies + (HZ / 5));
+       else
+         tl = (unsigned long) -1;
+       cs_sleep_flag.mode = WK_SLEEP;
+       module_interruptible_sleep_on (&cs_sleeper);
+       if (!(cs_sleep_flag.mode & WK_WAKEUP))
+         {
+           if (jiffies >= tl)
+             cs_sleep_flag.mode |= WK_TIMEOUT;
+         }
+       cs_sleep_flag.mode &= ~WK_SLEEP;
+      };                       /* Delay */
+
 /*
  * Then try to detect the codec part of the chip
  */
 
       if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp))
        return 1;
+
+
+      {
+       unsigned long   tl;
+
+       if (HZ)
+         current_set_timeout (tl = jiffies + (HZ));
+       else
+         tl = (unsigned long) -1;
+       cs_sleep_flag.mode = WK_SLEEP;
+       module_interruptible_sleep_on (&cs_sleeper);
+       if (!(cs_sleep_flag.mode & WK_WAKEUP))
+         {
+           if (jiffies >= tl)
+             cs_sleep_flag.mode |= WK_TIMEOUT;
+         }
+       cs_sleep_flag.mode &= ~WK_SLEEP;
+      };                       /* Longer delay */
     }
 
   return 0;
index ccfcfea978215e4c36a2a7a3829a5ae8868dbe39..7f65ea82c6949d04860efe0620df08f6088bf974 100644 (file)
@@ -26,7 +26,6 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <linux/config.h>
 
 
 #ifndef _DEV_TABLE_H_
@@ -411,12 +410,7 @@ struct sound_timer_operations {
 #endif
 
 #ifdef CONFIG_MSS
-       /* always define full MSS even for DEC Alphas, just in case... */
                {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
-#      ifdef __alpha__
-       /* MSS without IRQ/DMA config registers (for DEC Alphas) */
-               {SNDCARD_PSEUDO_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
-#      endif
 #      ifdef MSS2_BASE
                {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, -1}, SND_DEFAULT_ENABLE},
 #      endif
@@ -430,7 +424,10 @@ struct sound_timer_operations {
 #      ifndef SBC_DMA
 #              define SBC_DMA          1
 #      endif
-               {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, -1}, SND_DEFAULT_ENABLE},
+#      ifndef SB_DMA2
+#              define SB_DMA2          -1
+#      endif
+               {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, SB_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 #if defined(CONFIG_MAUI) 
                {SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
@@ -451,9 +448,6 @@ struct sound_timer_operations {
 #endif
 
 #if defined(CONFIG_SB) 
-#if defined(CONFIG_AUDIO) && defined(SB_DMA2)
-               {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB_DMA2, -1}, SND_DEFAULT_ENABLE},
-#endif
 #if defined(CONFIG_MIDI) && defined(SB_MPU_BASE)
                {SNDCARD_SB16MIDI,{SB_MPU_BASE, SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
index 0892fe63b5b1e078a9487dd66c18365ff06485ef..6c434807cc2102893189f2e0d6223df1a0c34d79 100644 (file)
@@ -738,7 +738,13 @@ DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
 
     case SNDCTL_DSP_GETBLKSIZE:
       if (!(dmap_out->flags & DMA_ALLOC_DONE))
-       reorganize_buffers (dev, dmap_out, 0);
+       {
+         reorganize_buffers (dev, dmap_out,
+                             (audio_devs[dev]->open_mode == OPEN_READ));
+         if (audio_devs[dev]->flags & DMA_DUPLEX)
+           reorganize_buffers (dev, dmap_in,
+                               (audio_devs[dev]->open_mode == OPEN_READ));
+       }
 
       return snd_ioctl_return ((int *) arg, dmap_out->fragment_size);
       break;
@@ -1403,6 +1409,7 @@ DMAbuf_outputintr (int dev, int event_type)
 
              dmap->cfrag = -1;
              dmap->flags |= DMA_EMPTY;
+             dmap->counts[dmap->qtail] = dmap->fragment_size;
            }
        }
 
@@ -1410,6 +1417,10 @@ DMAbuf_outputintr (int dev, int event_type)
        {
          if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
            {
+
+             if (dmap->counts[dmap->qhead] == 0)
+               dmap->counts[dmap->qhead] = dmap->fragment_size;
+
              audio_devs[dev]->output_block (dev, dmap->raw_buf_phys +
                                          dmap->qhead * dmap->fragment_size,
                                             dmap->counts[dmap->qhead], 1,
index 131fe3c5923ffab7ae6ec0477151ddae0c8f1ba8..84fbc5c3d21bf1c50283dd7f61b475ed1f163c30 100644 (file)
@@ -837,7 +837,7 @@ gus_initialize (void)
 
   gus_select_voice (0);                /* This disables writes to IRQ/DMA reg */
 
-  gusintr (0, NULL, NULL);      /* Serve pending interrupts */
+  gusintr (0, NULL, NULL);     /* Serve pending interrupts */
   restore_flags (flags);
 }
 
@@ -3537,10 +3537,16 @@ static struct sound_lowlev_timer gus_tmr =
 static void
 gus_tmr_install (int io_base)
 {
+  struct sound_lowlev_timer *tmr;
+
   select_addr = io_base;
   data_addr = io_base + 1;
 
+  tmr = &gus_tmr;
+
+#ifdef THIS_GETS_FIXED
   sound_timer_init (&gus_tmr, "GUS");
+#endif
 }
 #endif
 
index 642b2f3e6a9e8d3f7037388b86ee296e96bef73e..05d12b1cf9fd09d292e0460deaca33666b72c294 100644 (file)
@@ -95,7 +95,7 @@ int hex2hex(char *source, char *target, char *varline)
 
 
        fprintf(outf, "/*\n *\t Computer generated file. Do not edit.\n */\n");
-        fprintf(outf, "static int %s_len = %d\n", varline, l);
+        fprintf(outf, "static int %s_len = %d;\n", varline, l);
        fprintf(outf, "static unsigned char %s[] = {\n", varline);
 
        for (i=0;i<l;i++)
index 9d073f0014767c778079e4db10fd95488526c5d7..4e1e9973aabb7a128353289614053cc2baa7dba4 100644 (file)
@@ -1231,6 +1231,7 @@ opl3_init (long mem_start, int ioaddr, int *osp)
 
       devc->v_alloc->max_voice = devc->nr_voice = 18;
       devc->fm_info.nr_drums = 0;
+      devc->fm_info.synth_subtype = FM_TYPE_OPL3;
       devc->fm_info.capabilities |= SYNTH_CAP_OPL3;
       strcpy (devc->fm_info.name, "Yamaha OPL-3");
 
index b52ff967c481439d0949a013ae92c43cac7a46cb..853937f03a6f6458de274a1a5b1d82dee9cb0a4b 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+#include <linux/utsname.h>
 
 #include <linux/wrapper.h>
 
index 9dd47c4737dadca5db161a77d80287f5175e2763..4f2e5c9c73eb42bb7abcf3b0d06decddb294a265 100644 (file)
@@ -324,6 +324,9 @@ pas_pcm_output_block (int dev, unsigned long buf, int count,
       pcm_count = count;
     }
   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+#ifdef NO_TRIGGER
+  pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
+#endif
 
   pcm_mode = PCM_DAC;
 
@@ -370,12 +373,16 @@ pas_pcm_start_input (int dev, unsigned long buf, int count,
       pcm_count = count;
     }
   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+#ifdef NO_TRIGGER
+  pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
+#endif
 
   pcm_mode = PCM_ADC;
 
   restore_flags (flags);
 }
 
+#ifndef NO_TRIGGER
 static void
 pas_pcm_trigger (int dev, int state)
 {
@@ -394,6 +401,7 @@ pas_pcm_trigger (int dev, int state)
 
   restore_flags (flags);
 }
+#endif
 
 static int
 pas_pcm_prepare_for_input (int dev, int bsize, int bcount)
@@ -426,7 +434,11 @@ static struct audio_operations pas_pcm_operations =
   NULL,
   NULL,
   NULL,
+#ifndef NO_TRIGGER
   pas_pcm_trigger
+#else
+  NULL
+#endif
 };
 
 long
index 1285c4da93d6863ef9d969bb3152864015d5b68f..d7290006788f50ae942a7b93ad5696d4444e4748 100644 (file)
@@ -48,7 +48,7 @@ static int      dsp_16bit = 0;
 static int      dsp_stereo = 0;
 static int      dsp_current_speed = 8000;
 static int      dsp_busy = 0;
-static int      dma16, dma8;
+static int      dma16 = -1, dma8 = -1;
 static int      trigger_bits = 0;
 static unsigned long dsp_count = 0;
 
@@ -157,7 +157,7 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
     {
     case SOUND_PCM_WRITE_RATE:
       if (local)
-       return dsp_set_speed ((long) arg);
+       return dsp_set_speed ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_speed (get_fs_long ((long *) arg)));
 
     case SOUND_PCM_READ_RATE:
@@ -167,12 +167,12 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
 
     case SNDCTL_DSP_STEREO:
       if (local)
-       return dsp_set_stereo ((long) arg);
+       return dsp_set_stereo ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg)));
 
     case SOUND_PCM_WRITE_CHANNELS:
       if (local)
-       return dsp_set_stereo ((long) arg - 1) + 1;
+       return dsp_set_stereo ((int) arg - 1) + 1;
       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1);
 
     case SOUND_PCM_READ_CHANNELS:
@@ -182,7 +182,7 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
 
     case SNDCTL_DSP_SETFMT:
       if (local)
-       return dsp_set_bits ((long) arg);
+       return dsp_set_bits ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg)));
 
     case SOUND_PCM_READ_BITS:
@@ -521,6 +521,15 @@ sb16_dsp_init (long mem_start, struct address_info *hw_config)
   return mem_start;
 }
 
+static void
+set_dma (int dma)
+{
+  if (dma >= 0 && dma < 4)
+    dma8 = dma;
+  if (dma >= 5 && dma <= 7)
+    dma16 = dma;
+}
+
 int
 sb16_dsp_detect (struct address_info *hw_config)
 {
@@ -528,22 +537,38 @@ sb16_dsp_detect (struct address_info *hw_config)
   extern int      sbc_major, Jazz16_detected;
 
   extern void     Jazz16_set_dma16 (int dma);
+  int             irq;
 
   if (sb16_dsp_ok)
-    return 1;                  /* Can't drive two cards */
+    {
+      return 1;                        /* Can't drive two cards */
+    }
+
+  irq = hw_config->irq;
+  set_dma (hw_config->dma);
+  set_dma (hw_config->dma2);
 
   if (Jazz16_detected)
     {
-      Jazz16_set_dma16 (hw_config->dma);
+      Jazz16_set_dma16 (dma16);
       sb16_dsp_ok = 1;
       return 1;
     }
 
-  if (!(sb_config = sound_getconf (SNDCARD_SB)))
-    {
-      printk ("SB16 Error: Plain SB not configured\n");
-      return 0;
-    }
+  if (dma8 == -1)
+    if (!(sb_config = sound_getconf (SNDCARD_SB)))
+      {
+       printk ("SB16 Error: Plain SB not configured\n");
+       return 0;
+      }
+    else
+      {
+       dma8 = sb_config->dma;
+       irq = sb_config->irq;
+      }
+
+  if (dma16 == -1)
+    dma16 = dma8;
 
   /*
    * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0;
@@ -555,20 +580,18 @@ sb16_dsp_detect (struct address_info *hw_config)
   if (sbc_major < 4)           /* Set by the plain SB driver */
     return 0;                  /* Not a SB16 */
 
-  if (hw_config->dma < 4)
-    if (hw_config->dma != sb_config->dma)
+  if (dma16 < 4)
+    if (dma16 != dma8)
       {
        printk ("SB16 Error: Invalid DMA channel %d/%d\n",
-               sb_config->dma, hw_config->dma);
+               dma8, dma16);
        return 0;
       }
 
-  dma16 = hw_config->dma;
-  dma8 = sb_config->dma;
-  set_irq_hw (sb_config->irq);
-  sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
+  set_irq_hw (irq);
+  sb_setmixer (DMA_NR, (1 << dma16) | (1 << dma8));
 
-  DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
+  DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, dma16));
 
   /*
      * dsp_showmessage(0xe3,99);
index 5f85e76fe6d803fe4244545341c8c568325b5099..33ea1fa15628a02f2331d7db851277cb941c88cc 100644 (file)
@@ -125,7 +125,9 @@ sb16midi_open (int dev, int mode,
       return -EBUSY;
     }
 
-  sb16midi_input_loop ();
+  reset_sb16midi ();
+  while (input_avail ())
+    sb16midi_read ();
 
   midi_input_intr = input;
   sb16midi_opened = mode;
@@ -228,24 +230,16 @@ static struct midi_operations sb16midi_operations =
   NULL
 };
 
-long
-attach_sb16midi (long mem_start, struct address_info *hw_config)
+static void
+enter_uart_mode (void)
 {
   int             ok, timeout;
   unsigned long   flags;
 
-  sb16midi_base = hw_config->io_base;
-
-  if (!sb16midi_detected)
-    return mem_start;
-
-  request_region (hw_config->io_base, 4, "SB MIDI");
-
   save_flags (flags);
   cli ();
-  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);   /*
-                                                                        * Wait
-                                                                        */
+  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);
+
   input_byte = 0;
   sb16midi_cmd (UART_MODE_ON);
 
@@ -258,6 +252,18 @@ attach_sb16midi (long mem_start, struct address_info *hw_config)
        ok = 1;
 
   restore_flags (flags);
+}
+
+long
+attach_sb16midi (long mem_start, struct address_info *hw_config)
+{
+  sb16midi_base = hw_config->io_base;
+
+  if (!sb16midi_detected)
+    return mem_start;
+
+  request_region (hw_config->io_base, 4, "SB MIDI");
+  enter_uart_mode ();
 
   if (num_midis >= MAX_MIDI_DEV)
     {
@@ -281,9 +287,6 @@ reset_sb16midi (void)
    * Send the RESET command. Try again if no success at the first time.
    */
 
-  if (inb (STATPORT) == 0xff)
-    return 0;
-
   ok = 0;
 
   /*save_flags(flags);cli(); */
index a9acfbaca3c96c10fdad79aca36ba3c5263e9ae2..7e798e8f8d28f222532c2ca1635739236035ca22 100644 (file)
@@ -65,7 +65,7 @@ void
 unload_sb (struct address_info *hw_config)
 {
   release_region (hw_config->io_base, 16);
-  sb_dsp_unload ();
+  sb_dsp_unload (hw_config);
 }
 
 #endif
index 19e246061ba48ccfb01b54072ffea049e7b05d30..9113afa277df7808fc2334f21e533428d52ddca5 100644 (file)
@@ -55,6 +55,7 @@ int             sb_no_recording = 0;
 static int      dsp_count = 0;
 static int      trigger_bits;
 static int      mpu_base = 0, mpu_irq = 0;
+static int      sb16_inited = 0;
 
 /*
  * The DSP channel can be used either for input or output. Variable
@@ -1613,11 +1614,20 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
 
   sb_dsp_ok = 1;
   sb_reset_dsp ();
+
+  if (sb16 || hw_config->dma2 >= 0)
+    {
+      if (sb16_dsp_detect (hw_config))
+       {
+         sb16_inited = 1;
+         return sb16_dsp_init (mem_start, hw_config);
+       }
+    }
   return mem_start;
 }
 
 void
-sb_dsp_unload (void)
+sb_dsp_unload (struct address_info *hw_config)
 {
   sound_free_dma (dma8);
 
@@ -1634,6 +1644,9 @@ sb_dsp_unload (void)
     {
       snd_release_irq (ess_mpu_irq);
     }
+
+  if (sb16_inited)
+    unload_sb16 (hw_config);
 }
 
 void
index 7111958d50fe989656030e1fcde5c846c6ab6b2a..e592aa6092302ddd2bcc1b4333b36e9fcbbb3c4a 100644 (file)
@@ -83,7 +83,7 @@ void tenmicrosec(int *osp);
 void request_sound_timer (int count);
 void sound_stop_timer(void);
 int snd_ioctl_return(int *addr, int value);
-int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, void *, struct pt_regs *), char *name, int *osp);
+int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, void*, struct pt_regs *), char *name, int *osp);
 void snd_release_irq(int vect);
 void sound_dma_malloc(int dev);
 void sound_dma_free(int dev);
@@ -106,7 +106,7 @@ int sb_get_irq(void);
 void sb_free_irq(void);
 int sb_dsp_command (unsigned char val);
 int sb_reset_dsp (void);
-void sb_dsp_unload(void);
+void sb_dsp_unload(struct address_info *);
 
 /*     From sb16_dsp.c */
 void sb16_dsp_interrupt (int irq);
index 416d86975fcf9e8cd1fd01494f220f46dabb0732..3e1a24f8a59802b30871460955ff8becd5dca679 100644 (file)
@@ -115,6 +115,18 @@ init_status (void)
              "\n");
 #endif
 
+  put_status ("Kernel: ");
+  put_status (system_utsname.sysname);
+  put_status (" ");
+  put_status (system_utsname.nodename);
+  put_status (" ");
+  put_status (system_utsname.release);
+  put_status (" ");
+  put_status (system_utsname.version);
+  put_status (" ");
+  put_status (system_utsname.machine);
+  put_status ("\n");
+
   if (!put_status ("Config options: "))
     return;
   if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
@@ -139,7 +151,7 @@ init_status (void)
          return;
       }
 
-  if (!put_status ("\n\nCard config: \n"))
+  if (!put_status ("\nCard config: \n"))
     return;
 
   for (i = 0; i < num_sound_cards; i++)
@@ -418,6 +430,8 @@ sound_open_sw (int dev, struct fileinfo *file)
       break;
 
     case SND_DEV_CTL:
+      if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers)
+       return -ENXIO;
       return 0;
       break;
 
index 28fc7e533ca421f872e2a136e9787971fc6ead39..d6f30766b0dfc299fe39bda0e71a86ed4f980a51 100644 (file)
@@ -1,2 +1,2 @@
-#define SOUND_VERSION_STRING "3.5-beta7-960223"
+#define SOUND_VERSION_STRING "3.5-beta10-960301"
 #define SOUND_INTERNAL_VERSION 0x030505
index 4047af6cc88b1aafbc3eb3f37476ac99f4d08ed9..064ee22fce7de1ec961812f6ecef3cca72761b76 100644 (file)
@@ -269,7 +269,7 @@ set_mt32 (struct sscape_info *devc, int value)
                 value ? 1 : 0);
   if (host_read (devc) != CMD_ACK)
     {
-      printk ("SNDSCAPE: Setting MT32 mode failed\n");
+      /* printk ("SNDSCAPE: Setting MT32 mode failed\n"); */
     }
   host_close (devc);
 }
index aeb1e8eb468a40591a6546448e50fcfe047e2367..8b7a242a37f8f696e1fa79e9067f8bdf5a91c343 100644 (file)
@@ -157,4 +157,7 @@ else
   endif
 endif
 
+# binfmt_script is always there
+BINFMTS += binfmt_script.o
+
 include $(TOPDIR)/Rules.make
index 18bb816d89e669dd6fe91f4da93a0801df90bf3d..209b41252cddd8d68ca3c30c1b3488b0254b9d6d 100644 (file)
@@ -196,6 +196,59 @@ aout_core_dump(long signr, struct pt_regs * regs)
        return retval;
 }
 
+/*
+ * create_aout_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.
+ */
+static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm, int ibcs)
+{
+       unsigned long *argv,*envp;
+       unsigned long * sp;
+       int argc = bprm->argc;
+       int envc = bprm->envc;
+
+       sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
+#ifdef __alpha__
+/* whee.. test-programs are so much fun. */
+       put_user(0, --sp);
+       put_user(0, --sp);
+       if (bprm->loader) {
+               put_user(0, --sp);
+               put_user(0x3eb, --sp);
+               put_user(bprm->loader, --sp);
+               put_user(0x3ea, --sp);
+       }
+       put_user(bprm->exec, --sp);
+       put_user(0x3e9, --sp);
+#endif
+       sp -= envc+1;
+       envp = sp;
+       sp -= argc+1;
+       argv = sp;
+#ifdef __i386__
+       if (!ibcs) {
+               put_user(envp,--sp);
+               put_user(argv,--sp);
+       }
+#endif
+       put_user(argc,--sp);
+       current->mm->arg_start = (unsigned long) p;
+       while (argc-->0) {
+               put_user(p,argv++);
+               while (get_user(p++)) /* nothing */ ;
+       }
+       put_user(NULL,argv);
+       current->mm->arg_end = current->mm->env_start = (unsigned long) p;
+       while (envc-->0) {
+               put_user(p,envp++);
+               while (get_user(p++)) /* nothing */ ;
+       }
+       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.
@@ -328,13 +381,9 @@ beyond_if:
 
        set_brk(current->mm->start_brk, current->mm->brk);
 
-       fd_offset = setup_arg_pages(ex.a_text,bprm->page) - MAX_ARG_PAGES*PAGE_SIZE;
-       p += fd_offset;
-       if (bprm->loader)
-               bprm->loader += fd_offset;
-       bprm->exec += fd_offset;
+       p = setup_arg_pages(p, bprm);
        
-       p = (unsigned long)create_tables((char *)p, bprm,
+       p = (unsigned long) create_aout_tables((char *)p, bprm,
                                        current->personality != PER_LINUX);
        current->mm->start_stack = p;
 #ifdef __alpha__
index d2f0d8b7d1ce9ddb6a8b07a4215d30418cdd36ed..5fa1356855806a7f3442e5610e63f2ef0c4c23fc 100644 (file)
@@ -94,22 +94,7 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
 {
        unsigned long *argv,*envp, *dlinfo;
        unsigned long * sp;
-       struct vm_area_struct *mpnt;
-
-       mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
-       if (mpnt) {
-               mpnt->vm_mm = current->mm;
-               mpnt->vm_start = PAGE_MASK & (unsigned long) p;
-               mpnt->vm_end = TASK_SIZE;
-               mpnt->vm_page_prot = PAGE_COPY;
-               mpnt->vm_flags = VM_STACK_FLAGS;
-               mpnt->vm_pte = 0;
-               mpnt->vm_inode = NULL;
-               mpnt->vm_offset = 0;
-               mpnt->vm_ops = NULL;
-               insert_vm_struct(current, mpnt);
-               current->mm->total_vm += (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-       }
+
        sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
        sp -= exec ? DLINFO_ITEMS*2 : 2;
        dlinfo = sp;
@@ -537,7 +522,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        /* Do this so that we can load the interpreter, if need be.  We will
           change some of these later */
        current->mm->rss = 0;
-       bprm->p += setup_arg_pages(0, bprm->page);
+       bprm->p = setup_arg_pages(bprm->p, bprm);
        current->mm->start_stack = bprm->p;
        
        /* Now we do a little grungy work by mmaping the ELF image into
@@ -639,7 +624,6 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 #endif
        current->suid = current->euid = current->fsuid = bprm->e_uid;
        current->sgid = current->egid = current->fsgid = bprm->e_gid;
-       bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
        bprm->p = (unsigned long) 
          create_elf_tables((char *)bprm->p,
                        bprm->argc,
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
new file mode 100644 (file)
index 0000000..57ecef5
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ *  linux/fs/binfmt_script.c
+ *
+ *  Copyright (C) 1996  Martin von Löwis
+ *  original #!-checking implemented by tytso.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/binfmts.h>
+
+static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+       char *cp, *interp, *i_name, *i_arg, *page;
+       int retval, offset;
+       if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) 
+               return -ENOEXEC;
+       /*
+        * This section does the #! interpretation.
+        * Sorta complicated, but hopefully it will work.  -TYT
+        */
+
+       bprm->sh_bang++;
+       iput(bprm->inode);
+       bprm->dont_iput=1;
+
+       bprm->buf[127] = '\0';
+       if ((cp = strchr(bprm->buf, '\n')) == NULL)
+               cp = bprm->buf+127;
+       *cp = '\0';
+       while (cp > bprm->buf) {
+               cp--;
+               if ((*cp == ' ') || (*cp == '\t'))
+                       *cp = '\0';
+               else
+                       break;
+       }
+       for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
+       if (!cp || *cp == '\0') 
+               return -ENOEXEC; /* No interpreter name found */
+       interp = i_name = cp;
+       i_arg = 0;
+       for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
+               if (*cp == '/')
+                       i_name = cp+1;
+       }
+       while ((*cp == ' ') || (*cp == '\t'))
+               *cp++ = '\0';
+       if (*cp)
+               i_arg = cp;
+       /*
+        * OK, we've parsed out the interpreter name and
+        * (optional) argument.
+        * Splice in (1) the interpreter's name for argv[0]
+        *           (2) (optional) argument to interpreter
+        *           (3) filename of shell script (replace argv[0])
+        *
+        * This is done in reverse order, because of how the
+        * user environment and arguments are stored.
+        */
+       if (bprm->argc) {
+               offset = bprm->p % PAGE_SIZE;
+               page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+               while(bprm->p++,*(page+offset++))
+                       if(offset==PAGE_SIZE){
+                               offset=0;
+                               page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+                       }
+               bprm->argc--;
+       }
+       bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
+       bprm->argc++;
+       if (i_arg) {
+               bprm->p = copy_strings(1, &i_arg, bprm->page, bprm->p, 2);
+               bprm->argc++;
+       }
+       bprm->p = copy_strings(1, &i_name, bprm->page, bprm->p, 2);
+       bprm->argc++;
+       if (!bprm->p) 
+               return -E2BIG;
+       /*
+        * OK, now restart the process with the interpreter's inode.
+        * Note that we use open_namei() as the name is now in kernel
+        * space, and we don't need to copy it.
+        */
+       retval = open_namei(interp, 0, 0, &bprm->inode, NULL);
+       if (retval)
+               return retval;
+       bprm->dont_iput=0;
+       retval=prepare_binprm(bprm);
+       if(retval<0)
+               return retval;
+       return search_binary_handler(bprm,regs);
+}
+
+static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+       int retval;
+       MOD_INC_USE_COUNT;
+       retval = do_load_script(bprm,regs);
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+struct linux_binfmt script_format = {
+#ifndef MODULE
+       NULL, 0, load_script, NULL, NULL
+#else
+       NULL, &mod_use_count_, load_script, NULL, NULL
+#endif
+};
+
+int init_script_binfmt(void) {
+       return register_binfmt(&script_format);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+       return init_script_binfmt();
+}
+
+void cleanup_module( void) {
+       unregister_binfmt(&script_format);
+}
+#endif
index e3e81d95e2018510c378cdd5381b945d2cf1242e..e57e17ca84874fbecca3e3fccebfec06e00c6413 100644 (file)
@@ -61,11 +61,8 @@ int block_write(struct inode * inode, struct file * filp, const char * buf, int
        else
                size = INT_MAX;
        while (count>0) {
-               if (block >= size) {
-                       if (!written)
-                               written = -ENOSPC;
-                       return written;
-               }
+               if (block >= size)
+                       return written ? written : -ENOSPC;
                chars = blocksize - offset;
                if (chars > count)
                        chars=count;
@@ -105,7 +102,7 @@ int block_write(struct inode * inode, struct file * filp, const char * buf, int
                      bhlist[i] = getblk (dev, block+i, blocksize);
                      if(!bhlist[i]){
                        while(i >= 0) brelse(bhlist[i--]);
-                       return written? written: -EIO;
+                       return written ? written : -EIO;
                      };
                    };
                    ll_rw_block(READ, blocks, bhlist);
@@ -117,7 +114,7 @@ int block_write(struct inode * inode, struct file * filp, const char * buf, int
 #endif
                block++;
                if (!bh)
-                       return written?written:-EIO;
+                       return written ? written : -EIO;
                p = offset + bh->b_data;
                offset = 0;
                filp->f_pos += chars;
index 01330fd739ebda98d985f33ee93c0953d6b1afc4..4762b76a0d0b1f35ec2756f5740112eceb8b31f8 100644 (file)
@@ -363,7 +363,7 @@ static inline void remove_from_free_list(struct buffer_head * bh)
                bh->b_next_free->b_prev_free = bh->b_prev_free;
                if (free_list[isize] == bh)
                         free_list[isize] = bh->b_next_free;
-       };
+       }
        bh->b_next_free = bh->b_prev_free = NULL;
 }
 
@@ -398,7 +398,7 @@ static inline void put_last_lru(struct buffer_head * bh)
        if(!lru_list[bh->b_list]) {
                lru_list[bh->b_list] = bh;
                lru_list[bh->b_list]->b_prev_free = bh;
-       };
+       }
        if (!next_to_age[bh->b_list])
                next_to_age[bh->b_list] = bh;
 
@@ -1571,14 +1571,16 @@ void show_buffers(void)
                        protected++;
                if (buffer_dirty(bh))
                        dirty++;
-               if(mem_map[MAP_NR(((unsigned long) bh->b_data))].count !=1) shared++;
+               if (mem_map[MAP_NR(((unsigned long) bh->b_data))].count != 1)
+                       shared++;
                if (bh->b_count)
                        used++, lastused = found;
                bh = bh->b_next_free;
-             } while (bh != lru_list[nlist]);
-       printk("Buffer[%d] mem: %d buffers, %d used (last=%d), %d locked, "
-              "%d protected, %d dirty %d shrd\n",
-               nlist, found, used, lastused, locked, protected, dirty, shared);
+         } while (bh != lru_list[nlist]);
+         printk("Buffer[%d] mem: %d buffers, %d used (last=%d), "
+                "%d locked, %d protected, %d dirty %d shrd\n",
+                nlist, found, used, lastused,
+                locked, protected, dirty, shared);
        };
        printk("Size    [LAV]     Free  Clean  Unshar     Lck    Lck1   Dirty  Shared \n");
        for(isize = 0; isize<NR_SIZES; isize++){
index f94d5fb69e550d7d3c8248413d2d0326a154510d..3e1208196c029ebd071cb2cf96efaa33e01a1072 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -70,6 +70,8 @@ void binfmt_setup(void)
 #ifdef CONFIG_BINFMT_AOUT
        init_aout_binfmt();
 #endif
+       /* This cannot be configured out of the kernel */
+       init_script_binfmt();
 }
 
 int register_binfmt(struct linux_binfmt * fmt)
@@ -104,6 +106,11 @@ int unregister_binfmt(struct linux_binfmt * fmt)
        }
        return -EINVAL;
 }
+
+struct linux_binfmt * get_binfmt_list()
+{
+       return formats;
+}
 #endif /* CONFIG_MODULES */
 
 int open_inode(struct inode * inode, int mode)
@@ -177,74 +184,6 @@ asmlinkage int sys_uselib(const char * library)
        return retval;
 }
 
-/*
- * create_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.
- */
-unsigned long * create_tables(char * p, struct linux_binprm * bprm, int ibcs)
-{
-       unsigned long *argv,*envp;
-       unsigned long * sp;
-       struct vm_area_struct *mpnt;
-       int argc = bprm->argc;
-       int envc = bprm->envc;
-
-       mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
-       if (mpnt) {
-               mpnt->vm_mm = current->mm;
-               mpnt->vm_start = PAGE_MASK & (unsigned long) p;
-               mpnt->vm_end = STACK_TOP;
-               mpnt->vm_page_prot = PAGE_COPY;
-               mpnt->vm_flags = VM_STACK_FLAGS;
-               mpnt->vm_ops = NULL;
-               mpnt->vm_offset = 0;
-               mpnt->vm_inode = NULL;
-               mpnt->vm_pte = 0;
-               insert_vm_struct(current, mpnt);
-               current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-       }
-       sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
-#ifdef __alpha__
-/* whee.. test-programs are so much fun. */
-       put_user(0, --sp);
-       put_user(0, --sp);
-       if (bprm->loader) {
-               put_user(0, --sp);
-               put_user(0x3eb, --sp);
-               put_user(bprm->loader, --sp);
-               put_user(0x3ea, --sp);
-       }
-       put_user(bprm->exec, --sp);
-       put_user(0x3e9, --sp);
-#endif
-       sp -= envc+1;
-       envp = sp;
-       sp -= argc+1;
-       argv = sp;
-#ifdef __i386__
-       if (!ibcs) {
-               put_user(envp,--sp);
-               put_user(argv,--sp);
-       }
-#endif
-       put_user(argc,--sp);
-       current->mm->arg_start = (unsigned long) p;
-       while (argc-->0) {
-               put_user(p,argv++);
-               while (get_user(p++)) /* nothing */ ;
-       }
-       put_user(NULL,argv);
-       current->mm->arg_end = current->mm->env_start = (unsigned long) p;
-       while (envc-->0) {
-               put_user(p,envp++);
-               while (get_user(p++)) /* nothing */ ;
-       }
-       put_user(NULL,envp);
-       current->mm->env_end = (unsigned long) p;
-       return sp;
-}
-
 /*
  * count() counts the number of arguments/envelopes
  *
@@ -344,20 +283,42 @@ unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
        return p;
 }
 
-unsigned long setup_arg_pages(unsigned long text_size, unsigned long * page)
+unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm)
 {
-       unsigned long data_base;
+       unsigned long stack_base;
+       struct vm_area_struct *mpnt;
        int i;
 
-       data_base = STACK_TOP;
-       for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
-               data_base -= PAGE_SIZE;
-               if (page[i]) {
+       stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
+
+       p += stack_base;
+       if (bprm->loader)
+               bprm->loader += stack_base;
+       bprm->exec += stack_base;
+
+       mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+       if (mpnt) {
+               mpnt->vm_mm = current->mm;
+               mpnt->vm_start = PAGE_MASK & (unsigned long) p;
+               mpnt->vm_end = STACK_TOP;
+               mpnt->vm_page_prot = PAGE_COPY;
+               mpnt->vm_flags = VM_STACK_FLAGS;
+               mpnt->vm_ops = NULL;
+               mpnt->vm_offset = 0;
+               mpnt->vm_inode = NULL;
+               mpnt->vm_pte = 0;
+               insert_vm_struct(current, mpnt);
+               current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+       }
+
+       for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+               if (bprm->page[i]) {
                        current->mm->rss++;
-                       put_dirty_page(current,page[i],data_base);
+                       put_dirty_page(current,bprm->page[i],stack_base);
                }
+               stack_base += PAGE_SIZE;
        }
-       return STACK_TOP;
+       return p;
 }
 
 /*
@@ -485,195 +446,111 @@ void flush_old_exec(struct linux_binprm * bprm)
        current->used_math = 0;
 }
 
-/*
- * sys_execve() executes a new program.
+/* 
+ * Fill the binprm structure from the inode. 
+ * Check permissions, then read the first 512 bytes
  */
-int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
+int prepare_binprm(struct linux_binprm *bprm)
 {
-       struct linux_binprm bprm;
-       struct linux_binfmt * fmt;
-       int i;
-       int retval;
-       int sh_bang = 0;
-       int try;
-#ifdef __alpha__
-       int loader = 0;
-#endif
-
-       bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-       for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
-               bprm.page[i] = 0;
-       retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
-       if (retval)
-               return retval;
-       bprm.filename = filename;
-       bprm.loader = 0;
-       bprm.exec = 0;
-       if ((bprm.argc = count(argv)) < 0)
-               return bprm.argc;
-       if ((bprm.envc = count(envp)) < 0)
-               return bprm.envc;
-       
-restart_interp:
-       if (!S_ISREG(bprm.inode->i_mode)) {     /* must be regular file */
-               retval = -EACCES;
-               goto exec_error2;
-       }
-       if (IS_NOEXEC(bprm.inode)) {            /* FS mustn't be mounted noexec */
-               retval = -EPERM;
-               goto exec_error2;
-       }
-       if (!bprm.inode->i_sb) {
-               retval = -EACCES;
-               goto exec_error2;
-       }
-       i = bprm.inode->i_mode;
-       if (IS_NOSUID(bprm.inode) && (((i & S_ISUID) && bprm.inode->i_uid != current->
-           euid) || ((i & S_ISGID) && !in_group_p(bprm.inode->i_gid))) && !suser()) {
-               retval = -EPERM;
-               goto exec_error2;
-       }
+       int retval,i;
+       if (!S_ISREG(bprm->inode->i_mode))  /* must be regular file */
+               return -EACCES;
+       if (IS_NOEXEC(bprm->inode))         /* FS mustn't be mounted noexec */
+               return -EACCES;
+       if (!bprm->inode->i_sb)
+               return -EACCES;
+       i = bprm->inode->i_mode;
+       if (IS_NOSUID(bprm->inode) && 
+               (((i & S_ISUID) && bprm->inode->i_uid != current->euid) 
+                       || ((i & S_ISGID) && !in_group_p(bprm->inode->i_gid))) && !suser())
+               return -EPERM;
        /* make sure we don't let suid, sgid files be ptraced. */
        if (current->flags & PF_PTRACED) {
-               bprm.e_uid = current->euid;
-               bprm.e_gid = current->egid;
+               bprm->e_uid = current->euid;
+               bprm->e_gid = current->egid;
        } else {
-               bprm.e_uid = (i & S_ISUID) ? bprm.inode->i_uid : current->euid;
-               bprm.e_gid = (i & S_ISGID) ? bprm.inode->i_gid : current->egid;
-       }
-       if ((retval = permission(bprm.inode, MAY_EXEC)) != 0)
-               goto exec_error2;
-       if (!(bprm.inode->i_mode & 0111) && fsuser()) {
-               retval = -EACCES;
-               goto exec_error2;
+               bprm->e_uid = (i & S_ISUID) ? bprm->inode->i_uid : current->euid;
+               bprm->e_gid = (i & S_ISGID) ? bprm->inode->i_gid : current->egid;
        }
+       if ((retval = permission(bprm->inode, MAY_EXEC)) != 0)
+               return retval;
+       if (!(bprm->inode->i_mode & 0111) && fsuser())
+               return -EACCES;
        /* better not execute files which are being written to */
-       if (bprm.inode->i_writecount > 0) {
-               retval = -ETXTBSY;
-               goto exec_error2;
-       }
-       memset(bprm.buf,0,sizeof(bprm.buf));
-       retval = read_exec(bprm.inode,0,bprm.buf,128,1);
-       if (retval < 0)
-               goto exec_error2;
-       if ((bprm.buf[0] == '#') && (bprm.buf[1] == '!') && (!sh_bang)) {
-               /*
-                * This section does the #! interpretation.
-                * Sorta complicated, but hopefully it will work.  -TYT
-                */
-
-               char *cp, *interp, *i_name, *i_arg;
+       if (bprm->inode->i_writecount > 0)
+               return -ETXTBSY;
 
-               iput(bprm.inode);
-               bprm.buf[127] = '\0';
-               if ((cp = strchr(bprm.buf, '\n')) == NULL)
-                       cp = bprm.buf+127;
-               *cp = '\0';
-               while (cp > bprm.buf) {
-                       cp--;
-                       if ((*cp == ' ') || (*cp == '\t'))
-                               *cp = '\0';
-                       else
-                               break;
-               }
-               for (cp = bprm.buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
-               if (!cp || *cp == '\0') {
-                       retval = -ENOEXEC; /* No interpreter name found */
-                       goto exec_error1;
-               }
-               interp = i_name = cp;
-               i_arg = 0;
-               for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
-                       if (*cp == '/')
-                               i_name = cp+1;
-               }
-               while ((*cp == ' ') || (*cp == '\t'))
-                       *cp++ = '\0';
-               if (*cp)
-                       i_arg = cp;
-               /*
-                * OK, we've parsed out the interpreter name and
-                * (optional) argument.
-                */
-               if (sh_bang++ == 0) {
-                       bprm.p = copy_strings(bprm.envc, envp, bprm.page, bprm.p, 0);
-                       bprm.p = copy_strings(--bprm.argc, argv+1, bprm.page, bprm.p, 0);
-               }
-               /*
-                * Splice in (1) the interpreter's name for argv[0]
-                *           (2) (optional) argument to interpreter
-                *           (3) filename of shell script
-                *
-                * This is done in reverse order, because of how the
-                * user environment and arguments are stored.
-                */
-               bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
-               bprm.argc++;
-               if (i_arg) {
-                       bprm.p = copy_strings(1, &i_arg, bprm.page, bprm.p, 2);
-                       bprm.argc++;
-               }
-               bprm.p = copy_strings(1, &i_name, bprm.page, bprm.p, 2);
-               bprm.argc++;
-               if (!bprm.p) {
-                       retval = -E2BIG;
-                       goto exec_error1;
-               }
-               /*
-                * OK, now restart the process with the interpreter's inode.
-                * Note that we use open_namei() as the name is now in kernel
-                * space, and we don't need to copy it.
-                */
-               retval = open_namei(interp, 0, 0, &bprm.inode, NULL);
-               if (retval)
-                       goto exec_error1;
-               goto restart_interp;
+       memset(bprm->buf,0,sizeof(bprm->buf));
+       return read_exec(bprm->inode,0,bprm->buf,128,1);
+}
+
+void remove_arg_zero(struct linux_binprm *bprm)
+{
+       if (bprm->argc) {
+               unsigned long offset;
+               char * page;
+               offset = bprm->p % PAGE_SIZE;
+               page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+               while(bprm->p++,*(page+offset++))
+                       if(offset==PAGE_SIZE){
+                               offset=0;
+                               page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+                       }
+               bprm->argc--;
        }
+}
+
+/*
+ * cycle the list of binary formats handler, until one recognizes the image
+ */
+int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+       int try,retval=0;
+       struct linux_binfmt *fmt;
 #ifdef __alpha__
        /* handle /sbin/loader.. */
        {
-           struct exec * eh = (struct exec *) bprm.buf;
+           struct exec * eh = (struct exec *) bprm->buf;
 
-           if (!loader && eh->fh.f_magic == 0x183 &&
+           if (!bprm->loader && eh->fh.f_magic == 0x183 &&
                (eh->fh.f_flags & 0x3000) == 0x3000)
            {
                char * dynloader[] = { "/sbin/loader" };
-               iput(bprm.inode);
-               loader = 1;
-               bprm.p = copy_strings(1, dynloader, bprm.page, bprm.p, 2);
-               bprm.loader = bprm.p;
-               retval = open_namei(dynloader[0], 0, 0, &bprm.inode, NULL);
+               iput(bprm->inode);
+               bprm->dont_iput = 1;
+               remove_arg_zero(bprm);
+               bprm->p = copy_strings(1, dynloader, bprm->page, bprm->p, 2);
+               bprm->argc++;
+               bprm->loader = bprm->p;
+               retval = open_namei(dynloader[0], 0, 0, &bprm->inode, NULL);
                if (retval)
-                       goto exec_error1;
-               goto restart_interp;
+                       return retval;
+               bprm->dont_iput = 0;
+               retval = prepare_binprm(bprm);
+               if (retval<0)
+                       return retval;
+               /* should call search_binary_handler recursively here,
+                  but it does not matter */
            }
        }
 #endif
-       if (!sh_bang) {
-               bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
-               bprm.exec = bprm.p;
-               bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0);
-               bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p,0);
-               if (!bprm.p) {
-                       retval = -E2BIG;
-                       goto exec_error2;
-               }
-       }
-
-       bprm.sh_bang = sh_bang;
        for (try=0; try<2; try++) {
-               for (fmt = formats ; fmt ; fmt = fmt->next) {
+               for (fmt = get_binfmt_list() ; fmt ; fmt = fmt->next) {
                        int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
                        if (!fn)
                                continue;
-                       retval = fn(&bprm, regs);
+                       retval = fn(bprm, regs);
                        if (retval >= 0) {
-                               iput(bprm.inode);
+                               if(!bprm->dont_iput)
+                                       iput(bprm->inode);
+                               bprm->dont_iput=1;
                                current->did_exec = 1;
                                return retval;
                        }
                        if (retval != -ENOEXEC)
                                break;
+                       if (bprm->dont_iput) /* We don't have the inode anymore*/
+                               return retval;
                }
                if (retval != -ENOEXEC) {
                        break;
@@ -681,19 +558,65 @@ restart_interp:
                }else{
 #define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
                        char modname[20];
-                       if (printable(bprm.buf[0]) &&
-                           printable(bprm.buf[1]) &&
-                           printable(bprm.buf[2]) &&
-                           printable(bprm.buf[3]))
+                       if (printable(bprm->buf[0]) &&
+                           printable(bprm->buf[1]) &&
+                           printable(bprm->buf[2]) &&
+                           printable(bprm->buf[3]))
                                break; /* -ENOEXEC */
-                       sprintf(modname, "binfmt-%hd", *(short*)(&bprm.buf));
+                       sprintf(modname, "binfmt-%hd", *(short*)(&bprm->buf));
                        request_module(modname);
 #endif
                }
        }
-exec_error2:
-       iput(bprm.inode);
-exec_error1:
+       return retval;
+}
+
+
+/*
+ * sys_execve() executes a new program.
+ */
+int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
+{
+       struct linux_binprm bprm;
+       int retval;
+       int i;
+
+       bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+       for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
+               bprm.page[i] = 0;
+       retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
+       if (retval)
+               return retval;
+       bprm.filename = filename;
+       bprm.sh_bang = 0;
+       bprm.loader = 0;
+       bprm.exec = 0;
+       bprm.dont_iput = 0;
+       if ((bprm.argc = count(argv)) < 0)
+               return bprm.argc;
+       if ((bprm.envc = count(envp)) < 0)
+               return bprm.envc;
+
+       retval = prepare_binprm(&bprm);
+       
+       if(retval>=0) {
+               bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
+               bprm.exec = bprm.p;
+               bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0);
+               bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p,0);
+               if (!bprm.p)
+                       retval = -E2BIG;
+       }
+
+       if(retval>=0)
+               retval = search_binary_handler(&bprm,regs);
+       if(retval>=0)
+               /* execve success */
+               return retval;
+
+       /* Something went wrong, return the inode and free the argument pages*/
+       if(!bprm.dont_iput)
+               iput(bprm.inode);
        for (i=0 ; i<MAX_ARG_PAGES ; i++)
                free_page(bprm.page[i]);
        return(retval);
index 272afc31d8b56b07ae17e5dd06e4921bf50738c6..c3fd9793c9409fe7487dcfc5f47869df4ff07618 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  dir.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -41,7 +41,7 @@ static struct inode *
 ncp_iget(struct inode *dir, struct nw_file_info *finfo);
 
 static struct ncp_inode_info *
-ncp_find_inode(struct inode *dir, const char *name);
+ncp_find_dir_inode(struct inode *dir, const char *name);
 
 static int
 ncp_lookup(struct inode *dir, const char *__name,
@@ -123,6 +123,60 @@ struct inode_operations ncp_dir_inode_operations = {
 };
 
 
+/* Here we encapsulate the inode number handling that depends upon the
+ * mount mode: When we mount a complete server, the memory address of
+ * the npc_inode_info is used as an inode. When only a single volume
+ * is mounted, then the DosDirNum is used as the inode number. As this
+ * is unique for the complete volume, this should enable the NFS
+ * exportability of a ncpfs-mounted volume.
+ */
+
+static inline int
+ncp_single_volume(struct ncp_server *server)
+{
+       return (server->m.mounted_vol[0] != '\0');
+}
+
+inline ino_t
+ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
+{
+       return ncp_single_volume(server)
+               ? info->finfo.i.DosDirNum : (ino_t)info;
+}
+
+static inline int
+ncp_is_server_root(struct inode *inode)
+{
+       struct ncp_server *s = NCP_SERVER(inode);
+
+       return (   (!ncp_single_volume(s))
+               && (inode->i_ino == ncp_info_ino(s, &(s->root))));
+}
+
+struct ncp_inode_info *
+ncp_find_inode(struct inode *inode)
+{
+       struct ncp_server *server = NCP_SERVER(inode);
+        struct ncp_inode_info *root = &(server->root);
+        struct ncp_inode_info *this = root;
+
+       ino_t ino = inode->i_ino;
+
+        do
+       {
+                if (ino == ncp_info_ino(server, this))
+               {
+                       return this;
+               }
+               this = this->next;
+        }
+       while (this != root);
+
+       return NULL;
+}
+       
+
+
 static int 
 ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
 {
@@ -133,6 +187,7 @@ ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
    all inodes that are in memory. That's why it's enough to index the
    directory cache by the inode number. */
 
+static kdev_t             c_dev = 0;
 static unsigned long      c_ino = 0;
 static int                c_size;
 static int                c_seen_eof;
@@ -147,7 +202,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
         int index = 0;
        struct ncp_dirent *entry = NULL;
         struct ncp_server *server = NCP_SERVER(inode);
-       struct ncp_inode_info *dir = (struct ncp_inode_info *)(inode->i_ino);
+       struct ncp_inode_info *dir = NCP_INOP(inode);
 
        DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
        DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
@@ -159,7 +214,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
                return -EBADF;
        }
 
-       if (!ncp_conn_valid(NCP_SERVER(inode)))
+       if (!ncp_conn_valid(server))
        {
                return -EIO;
        }
@@ -177,8 +232,9 @@ ncp_readdir(struct inode *inode, struct file *filp,
 
         if (filp->f_pos == 0)
        {
-                ncp_invalid_dir_cache(inode->i_ino);
-               if (filldir(dirent,".",1, filp->f_pos, (int)dir) < 0)
+                ncp_invalid_dir_cache(inode);
+               if (filldir(dirent,".",1, filp->f_pos,
+                           ncp_info_ino(server, dir)) < 0)
                {
                        return 0;
                }
@@ -187,14 +243,15 @@ ncp_readdir(struct inode *inode, struct file *filp,
 
        if (filp->f_pos == 1)
        {
-               if (filldir(dirent,"..",2, filp->f_pos, (int)(dir->dir)) < 0)
+               if (filldir(dirent,"..",2, filp->f_pos,
+                           ncp_info_ino(server, dir->dir)) < 0)
                {
                        return 0;
                }
                filp->f_pos += 1;
        }
 
-       if (inode->i_ino == c_ino)
+       if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
        {
                for (i = 0; i < c_size; i++)
                {
@@ -216,7 +273,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
        {
                DDPRINTK("ncp_readdir: Not found in cache.\n");
 
-               if (inode->i_ino == (int)&(server->root))
+               if (ncp_is_server_root(inode))
                {
                        result = ncp_read_volume_list(server, filp->f_pos,
                                                      NCP_READDIR_CACHE_SIZE);
@@ -233,6 +290,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
 
                if (result < 0)
                {
+                       c_dev = 0;
                        c_ino = 0;
                        return result;
                }
@@ -240,6 +298,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
                if (result > 0)
                {
                         c_seen_eof = (result < NCP_READDIR_CACHE_SIZE);
+                       c_dev  = inode->i_dev;
                        c_ino  = inode->i_ino;
                        c_size = result;
                        entry = c_entry;
@@ -264,29 +323,41 @@ ncp_readdir(struct inode *inode, struct file *filp,
                 /* We found it.  For getwd(), we have to return the
                    correct inode in d_ino if the inode is currently in
                    use. Otherwise the inode number does not
-                   matter. (You can argue a lot about this..) */ 
+                   matter. (You can argue a lot about this..) */
 
-                struct ncp_inode_info *ino_info;
-                ino_info = ncp_find_inode(inode, entry->i.entryName);
+               ino_t ino;
 
-                /* Some programs seem to be confused about a zero
-                   inode number, so we set it to one.  Thanks to
-                   Gordon Chaffee for this one. */
-                if (ino_info == NULL)
+               if (ncp_single_volume(server))
                {
-                        ino_info = (struct ncp_inode_info *) 1;
-                }
+                       ino = (ino_t)(entry->i.DosDirNum);
+               }
+               else
+               {
+                       struct ncp_inode_info *ino_info;
+                       ino_info = ncp_find_dir_inode(inode,
+                                                     entry->i.entryName);
+
+                       /* Some programs seem to be confused about a
+                        * zero inode number, so we set it to one.
+                        * Thanks to Gordon Chaffee for this one. */
+                       if (ino_info == NULL)
+                       {
+                               ino_info = (struct ncp_inode_info *) 1;
+                       }
+                       ino = (ino_t)(ino_info);
+               }
 
                DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
                DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
 
                 if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
-                            entry->f_pos, (ino_t)ino_info) < 0)
+                            entry->f_pos, ino) < 0)
                {
                        break;
                 }
 
-               if (   (inode->i_ino != c_ino)
+               if (   (inode->i_dev != c_dev)
+                   || (inode->i_ino != c_ino)
                    || (entry->f_pos != filp->f_pos))
                {
                        /* Someone has destroyed the cache while we slept
@@ -341,9 +412,9 @@ ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
                                DPRINTK("ncp_read_volumes: found vol: %s\n",
                                        info.volume_name);
 
-                               if (ncp_do_lookup(server, NULL,
-                                                 info.volume_name,
-                                                 &(entry->i)) != 0)
+                               if (ncp_lookup_volume(server,
+                                                     info.volume_name,
+                                                     &(entry->i)) != 0)
                                {
                                        printk("ncpfs: could not lookup vol "
                                               "%s\n", info.volume_name);
@@ -426,15 +497,17 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
 void
 ncp_init_dir_cache(void)
 {
+       c_dev   = 0;
         c_ino   = 0;
         c_entry = NULL;
 }
 
 void
-ncp_invalid_dir_cache(unsigned long ino)
+ncp_invalid_dir_cache(struct inode *ino)
 {
-       if (ino == c_ino)
+       if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino))
        {
+               c_dev = 0;
                 c_ino = 0;
                 c_seen_eof = 0;
         }
@@ -505,7 +578,8 @@ ncp_iget(struct inode *dir, struct nw_file_info *finfo)
         root->next->prev = new_inode_info;
         root->next = new_inode_info;
         
-       if (!(inode = iget(dir->i_sb, (int)new_inode_info)))
+       if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
+                                                  new_inode_info))))
        {
                printk("ncp_iget: iget failed!");
                return NULL;
@@ -556,12 +630,13 @@ ncp_init_root(struct ncp_server *server)
         root->finfo.opened = 0;
        i->attributes  = aDIR;
        i->dataStreamSize = 1024;
+       i->DosDirNum = 0;
        i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
        ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
        ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
        ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
        i->nameLen = 0;
-        i->entryName[0] = '\0';
+       i->entryName[0] = '\0';
 
         root->state = NCP_INODE_LOOKED_UP;
         root->nused = 1;
@@ -570,6 +645,25 @@ ncp_init_root(struct ncp_server *server)
         return;
 }
 
+int
+ncp_conn_logged_in(struct ncp_server *server)
+{
+       if (server->m.mounted_vol[0] == '\0')
+       {
+               return 0;
+       }
+
+       str_upper(server->m.mounted_vol);
+       if (ncp_lookup_volume(server, server->m.mounted_vol,
+                             &(server->root.finfo.i)) != 0)
+       {
+               return -ENOENT;
+       }
+       str_lower(server->root.finfo.i.entryName);
+
+       return 0;
+}
+
 void
 ncp_free_all_inodes(struct ncp_server *server)
 {
@@ -600,7 +694,7 @@ ncp_free_all_inodes(struct ncp_server *server)
    complete linear search through the inodes belonging to this
    filesystem. This has to be fixed. */
 static struct ncp_inode_info *
-ncp_find_inode(struct inode *dir, const char *name)
+ncp_find_dir_inode(struct inode *dir, const char *name)
 {
        struct ncp_server *server = NCP_SERVER(dir);
        struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
@@ -645,15 +739,16 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
                iput(dir);
                return -ENOENT;
        }
-       if (!ncp_conn_valid(NCP_SERVER(dir)))
+
+       server = NCP_SERVER(dir);
+
+       if (!ncp_conn_valid(server))
        {
                iput(dir);
                return -EIO;
        }
 
-        DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
-
-       server = NCP_SERVER(dir);
+       DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
 
        /* Fast cheat for . */
        if (len == 0 || (len == 1 && __name[0] == '.'))
@@ -672,7 +767,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
                        parent->state = NCP_INODE_LOOKED_UP;
                }
 
-               *result = iget(dir->i_sb, (int)parent);
+               *result = iget(dir->i_sb, ncp_info_ino(server, parent));
                iput(dir);
                if (*result == 0)
                {
@@ -686,7 +781,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
 
        memcpy(name, __name, len);
        name[len] = 0;
-       result_info = ncp_find_inode(dir, name);
+       result_info = ncp_find_dir_inode(dir, name);
 
         if (result_info != 0)
        {
@@ -698,7 +793,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
                 /* Here we convert the inode_info address into an
                    inode number */
 
-                *result = iget(dir->i_sb, (int)result_info);
+                *result = iget(dir->i_sb, ncp_info_ino(server, result_info));
                 iput(dir);
 
                 if (*result == NULL)
@@ -713,8 +808,8 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
            server. */
 
         found_in_cache = 0;
-        
-        if (dir->i_ino == c_ino)
+
+        if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
        {
                 int first = c_last_returned_index;
                 int i;
@@ -723,7 +818,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
                 do
                {
                         DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
-                                i, c_entry[i].i.entryName);
+                                i, c_entry[i].i.entryName);
 
                         if (strcmp(c_entry[i].i.entryName, name) == 0)
                        {
@@ -739,15 +834,24 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
 
         if (found_in_cache == 0)
        {
+               int res;
                str_upper(name);
 
                DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
                         NCP_ISTRUCT(dir)->entryName, name);
 
-               if (ncp_do_lookup(server,
-                                 dir->i_ino == (int)&(NCP_SERVER(dir)->root)
-                                 ? NULL : NCP_ISTRUCT(dir),
-                                 name, &(finfo.i)) != 0)
+               if (ncp_is_server_root(dir))
+               {
+                       res = ncp_lookup_volume(server, name, &(finfo.i));
+               }
+               else
+               {
+                       res = ncp_obtain_info(server,
+                                             NCP_ISTRUCT(dir)->volNumber,
+                                             NCP_ISTRUCT(dir)->DosDirNum,
+                                             name, &(finfo.i));
+               }
+               if (res != 0)
                {
                         iput(dir);
                         return -ENOENT;
@@ -803,7 +907,7 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
                return -EACCES;
        }
 
-        ncp_invalid_dir_cache(dir->i_ino);
+       ncp_invalid_dir_cache(dir);
 
        str_lower(finfo.i.entryName);
        finfo.access = O_RDWR;
@@ -860,7 +964,7 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
        else
        {
                error = 0;
-                ncp_invalid_dir_cache(dir->i_ino);
+                ncp_invalid_dir_cache(dir);
         }
 
        iput(dir);
@@ -884,7 +988,7 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
                iput(dir);
                return -EIO;
        }
-        if (ncp_find_inode(dir, name) != NULL)
+        if (ncp_find_dir_inode(dir, name) != NULL)
        {
                iput(dir);
                 error = -EBUSY;
@@ -900,7 +1004,7 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
                                                    NCP_ISTRUCT(dir),
                                                    _name)) == 0)
                {
-                        ncp_invalid_dir_cache(dir->i_ino);
+                        ncp_invalid_dir_cache(dir);
                }
                else
                {
@@ -928,7 +1032,7 @@ ncp_unlink(struct inode *dir, const char *name, int len)
                iput(dir);
                return -EIO;
        }
-        if (ncp_find_inode(dir, name) != NULL)
+        if (ncp_find_dir_inode(dir, name) != NULL)
        {
                iput(dir);
                 error = -EBUSY;
@@ -943,7 +1047,7 @@ ncp_unlink(struct inode *dir, const char *name, int len)
                                                    NCP_ISTRUCT(dir),
                                                    _name)) == 0)
                {
-                        ncp_invalid_dir_cache(dir->i_ino);
+                        ncp_invalid_dir_cache(dir);
                }
                else
                {
@@ -982,8 +1086,8 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
                 goto finished;
        }
 
-        if (   (ncp_find_inode(old_dir, old_name) != NULL)
-            || (ncp_find_inode(new_dir, new_name) != NULL))
+        if (   (ncp_find_dir_inode(old_dir, old_name) != NULL)
+            || (ncp_find_dir_inode(new_dir, new_name) != NULL))
        {
                 res = -EBUSY;
                 goto finished;
@@ -1003,8 +1107,8 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
 
         if (res == 0)
        {
-                ncp_invalid_dir_cache(old_dir->i_ino);
-                ncp_invalid_dir_cache(new_dir->i_ino);
+                ncp_invalid_dir_cache(old_dir);
+                ncp_invalid_dir_cache(new_dir);
         }
        else
        {
index e036b16518ccd555b19fbdd8fe8e3c7b5bed6f90..0a54daf5f5f2cd93f15793fd6f1a70eddda33dd8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  file.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -241,6 +241,7 @@ ncp_file_write(struct inode *inode, struct file *file, const char *buf,
         if (pos > inode->i_size)
        {
                 inode->i_size = pos;
+               ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
         }
 
         DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName);
index 9a86eec057f043becc0e40afdbedc37e12ffb142..f70173b4b4afe05f6164779bac2fb374fa17e68e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  inode.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -58,50 +58,25 @@ ncp_read_inode(struct inode *inode)
            inode->i_ino. Just to make sure everything went well, we
            check it's there. */
 
-        struct ncp_inode_info *inode_info
-                = (struct ncp_inode_info *)(inode->i_ino);
+        struct ncp_inode_info *inode_info = ncp_find_inode(inode);
 
-#if 1
-        struct ncp_inode_info *root = &(NCP_SERVER(inode)->root);
-        struct ncp_inode_info *check_info = root;
-
-        do
+       if (inode_info == NULL)
        {
-                if (inode_info == check_info)
-               {
-                        if (check_info->state == NCP_INODE_LOOKED_UP)
-                       {
-                                DDPRINTK("ncp_read_inode: found it!\n");
-                                goto good;
-                        }
-                        else
-                       {
-                                printk("ncp_read_inode: "
-                                       "state != NCP_INODE_LOOKED_UP\n");
-                               goto good;
-                        }
-                }
-                check_info = check_info->next;
-        }
-       while (check_info != root);
-
-        /* Ok, now we're in trouble. The inode info is not there. What
-           should we do now??? */
-        printk("ncp_read_inode: inode info not found\n");
-        return;
+               /* Ok, now we're in trouble. The inode info is not there. What
+                  should we do now??? */
+               printk("ncp_read_inode: inode info not found\n");
+               return;
+       }
 
- good:
-       DDPRINTK("ncp_read_inode: read entry %s\n",
-                inode_info->finfo.i.entryName);
-#endif
         inode_info->state = NCP_INODE_VALID;
 
         NCP_INOP(inode) = inode_info;
+       inode_info->inode = inode;
 
         if (NCP_ISTRUCT(inode)->attributes & aDIR)
        {
                 inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
-               /* for directories in dataStreamSize seems to be some
+               /* for directories dataStreamSize seems to be some
                   Object ID ??? */
                inode->i_size = 512;
        }
@@ -173,7 +148,7 @@ ncp_put_inode(struct inode *inode)
        {
                 DDPRINTK("ncp_put_inode: put directory %ld\n",
                         inode->i_ino);
-                ncp_invalid_dir_cache(inode->i_ino);
+                ncp_invalid_dir_cache(inode);
         }                
 
        clear_inode(inode);
@@ -286,8 +261,6 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
                goto fail;
        }
    
-        ncp_init_root(server);
-
         /*
          * Make the connection to the server
          */
@@ -326,7 +299,9 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
 
         DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb));
 
-       if (!(sb->s_mounted = iget(sb, (int)&(server->root))))
+       ncp_init_root(server);
+
+       if (!(sb->s_mounted = iget(sb, ncp_info_ino(server, &(server->root)))))
        {
                sb->s_dev = 0;
                printk("ncp_read_super: get root inode failed\n");
@@ -537,7 +512,7 @@ ncp_notify_change(struct inode *inode, struct iattr *attr)
                result = 0;
        }
 
-        ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir));
+        ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
 
        return result;
 }
index 6d5523bf3f051c7718862666ab8008353e7a8881..eb1c4b394fd3e9e82c7165871ad92b4961f4fc97 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  ioctl.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -73,6 +73,16 @@ ncp_ioctl (struct inode * inode, struct file * filp,
 
                return server->reply_size;
 
+       case NCP_IOC_CONN_LOGGED_IN:
+
+               if (   (permission(inode, MAY_WRITE) != 0)
+                   && (current->uid != server->m.mounted_uid))
+               {
+                       return -EACCES;
+               }
+
+               return ncp_conn_logged_in(server);
+               
        case NCP_IOC_GET_FS_INFO:
 
                if (   (permission(inode, MAY_WRITE) != 0)
index 3e8e08fba51f908a7bf1d573ea3271a996274d33..798c706f6a182f6af371612100e2b18631d86d95 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  mmap.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
index fe779b92f610a97725be3d0742e26a64c85742ae..5dcf153c1e0a3c3cb53e2c6f9875c01286be6195 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ *  ncplib_kernel.c
+ *
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
+ *
+ */
+
 #include "ncplib_kernel.h"
 
 typedef __u8  byte;
@@ -260,56 +267,19 @@ ncp_extract_file_info(void *structure, struct nw_info_struct *target)
        target->entryName[*name_len] = '\0';
        return;
 }
-               
 
 int
-ncp_do_lookup(struct ncp_server *server,
-             struct nw_info_struct *dir,
-             char *path,       /* may only be one component */
-             struct nw_info_struct *target)
+ncp_obtain_info(struct ncp_server *server,
+               __u8 vol_num, __u32 dir_base,
+               char *path, /* At most 1 component */
+               struct nw_info_struct *target)
 {
-       __u8  vol_num;
-       __u32 dir_base;
        int result;
-       char *volname = NULL;
 
        if (target == NULL)
        {
                return -EINVAL;
        }
-       if (dir == NULL)
-       {
-
-               DDPRINTK("ncp_do_lookup: looking up vol %s\n", path);
-
-               /* Access a volume's root directory */
-               ncp_init_request(server);
-               ncp_add_byte(server, 22); /* subfunction */
-               ncp_add_byte(server, 0); /* dos name space */
-               ncp_add_byte(server, 0); /* reserved */
-               ncp_add_byte(server, 0); /* reserved */
-               ncp_add_byte(server, 0); /* reserved */
-               ncp_add_handle_path(server, 0, 0, 0, /* no handle */
-                                   path);
-
-               if ((result = ncp_request(server, 87)) != 0)
-               {
-                       ncp_unlock_server(server);
-                       return result;
-               }
-
-               dir_base = ncp_reply_dword(server, 4);
-               vol_num  = ncp_reply_byte (server, 8);
-               ncp_unlock_server(server);
-               volname = path;
-               path = NULL;
-       }
-       else
-       {
-               vol_num = dir->volNumber;
-               dir_base = dir->DosDirNum;
-       }
 
        ncp_init_request(server);
        ncp_add_byte(server, 6); /* subfunction */
@@ -317,8 +287,7 @@ ncp_do_lookup(struct ncp_server *server,
        ncp_add_byte(server, 0); /* dos name space as dest */
        ncp_add_word(server, 0xff); /* get all */
        ncp_add_dword(server, RIM_ALL);
-       ncp_add_handle_path(server, vol_num, dir_base, 1,
-                           path);
+       ncp_add_handle_path(server, vol_num, dir_base, 1, path);
 
        if ((result = ncp_request(server, 87)) != 0)
        {
@@ -327,14 +296,54 @@ ncp_do_lookup(struct ncp_server *server,
        }
 
        ncp_extract_file_info(ncp_reply_data(server, 0), target);
+       ncp_unlock_server(server);
+       return 0;
+}
 
-       if (volname != NULL)
+int
+ncp_lookup_volume(struct ncp_server *server,
+                 char *volname,
+                 struct nw_info_struct *target)
+{
+       int result;
+       __u8  vol_num;
+       __u32 dir_base;
+
+       DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname);
+
+       ncp_init_request(server);
+       ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */
+       ncp_add_byte(server, 0); /* DOS name space */
+       ncp_add_byte(server, 0); /* reserved */
+       ncp_add_byte(server, 0); /* reserved */
+       ncp_add_byte(server, 0); /* reserved */
+
+       ncp_add_byte(server, 0); /* faked volume number */
+       ncp_add_dword(server, 0); /* faked dir_base */
+       ncp_add_byte(server, 0xff); /* Don't have a dir_base */
+       ncp_add_byte(server, 1); /* 1 path component */
+       ncp_add_pstring(server, volname);
+
+       if ((result = ncp_request(server, 87)) != 0)
        {
-               target->nameLen = strlen(volname);
-               strcpy(target->entryName, volname);
+               ncp_unlock_server(server);
+               return result;
        }
 
+       dir_base = ncp_reply_dword(server, 4);
+       vol_num  = ncp_reply_byte(server, 8);
        ncp_unlock_server(server);
+
+       if ((result = ncp_obtain_info(server, vol_num, dir_base, NULL,
+                                     target)) != 0)
+       {
+               return result;
+       }
+
+       DPRINTK("ncp_lookup_volume: attribs = %X\n", target->attributes);
+
+       target->nameLen = strlen(volname);
+       strcpy(target->entryName, volname);
        return 0;
 }
 
index 3278cdf40314c0b25d049748887aa1801df54621..d564bf31528bf36ec3d92ec018b92b6998121201 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ *  ncplib_kernel.h
+ *
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
+ *
+ */
+
 #ifndef _NCPLIB_H
 #define _NCPLIB_H
 
@@ -114,10 +121,16 @@ ncp_write(struct ncp_server *server, const char *file_id,
          const char *source, int *bytes_written);
 
 int
-ncp_do_lookup(struct ncp_server *server,
-             struct nw_info_struct *dir,
-             char *path,       /* may only be one component */
-             struct nw_info_struct *target);
+ncp_obtain_info(struct ncp_server *server,
+               __u8 vol_num, __u32 dir_base,
+               char *path, /* At most 1 component */
+               struct nw_info_struct *target);
+
+int
+ncp_lookup_volume(struct ncp_server *server,
+                 char *volname,
+                 struct nw_info_struct *target);
+
 
 int
 ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
index 14bf0a241f396f94cece61a67b48d49726311845..1f60c9ca5449bec4114b4da10a55ed7f6977bb68 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 1992, 1993  Rick Sladkey
  *
- *  Modified 1995 by Volker Lendecke to be usable for ncp
+ *  Modified 1995, 1996 by Volker Lendecke to be usable for ncp
  *
  */
 
@@ -619,7 +619,7 @@ ncp_request(struct ncp_server *server, int function)
 
        if (result != 0)
        {
-               DPRINTK("ncp_completion_code: %d\n", result);
+               DPRINTK("ncp_completion_code: %x\n", result);
        }
        return result;  
 }
index aecfb5ea9397f4d9523d5c1ff8d85c79a1fc5873..66c7afd0bb884f959af9fd60e570076bca3016f6 100644 (file)
@@ -498,7 +498,7 @@ static int do_umount(kdev_t dev)
                        /*
                         * Make sure all quotas are turned off on this device we need to mount
                         * it readonly so no more writes by the quotasystem.
-                        * If later on the remount fails to bad there are no quotas running
+                        * If later on the remount fails too bad there are no quotas running
                         * anymore. Turn them on again by hand.
                         */
                        quota_off(dev, -1);
@@ -517,7 +517,7 @@ static int do_umount(kdev_t dev)
        /*
         * Before checking if the filesystem is still busy make sure the kernel
         * doesn't hold any quotafiles open on that device. If the umount fails
-        * to bad there are no quotas running anymore. Turn them on again by hand.
+        * 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))
index 2da5189572b1ba42b4770e23b29c158654bf81e1..b2d3018fe17b7ea4c82c325de6a0399b58d80308 100644 (file)
@@ -52,9 +52,9 @@ extern void wrmces (unsigned long);
 
 #define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory")
 
-#define switch_to(p) do { \
-       current_set[0] = p; \
-       alpha_switch_to((unsigned long) &(p)->tss - 0xfffffc0000000000); \
+#define switch_to(prev,next) do { \
+       current_set[0] = next; \
+       alpha_switch_to((unsigned long) &(next)->tss - 0xfffffc0000000000); \
 } while (0)
 
 extern void alpha_switch_to(unsigned long pctxp);
index 8396dd46764cbc764dd3e4176f7fb12cf37d1f4e..4764b187997f8f7757c500bf491e332b30321ca4 100644 (file)
@@ -70,6 +70,8 @@
 #define __NR_setsockopt                105
 #define __NR_listen            106
 #define __NR_sigsuspend                111
+#define __NR_recvmsg           113
+#define __NR_sendmsg           114
 #define __NR_gettimeofday      116
 #define __NR_getrusage         117
 #define __NR_getsockopt                118
 #define __NR_sched_rr_get_interval     337
 #define __NR_afs_syscall               338
 #define __NR_uname                     339
+#define __NR_nanosleep                 340
 
 #ifdef __LIBRARY__
 
index e89dae7626a15657dca1fbdf85de2c99a5f14a7d..9e98deb36280679e18fc26345129706d2a230e03 100644 (file)
@@ -186,7 +186,7 @@ extern void smp_invalidate(void);
 extern volatile unsigned long kernel_flag, kernel_counter;
 extern volatile unsigned char active_kernel_processor;
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
-extern void smp_reschedule_irq(int cpl, void *dev_id, struct pt_regs *regs);
+extern void smp_reschedule_irq(int cpl, struct pt_regs *regs);
 extern unsigned long ipi_count;
 extern void smp_invalidate_rcv(void);          /* Process an NMI */
 extern volatile unsigned long kernel_counter;
index e272faea5198f4ca4d99866f9743ee721ea1289c..0059e121d2086b70fce877888de96416c2000abe 100644 (file)
@@ -31,11 +31,11 @@ __asm__("str %%ax\n\t" \
 
 /* This special macro can be used to load a debugging register */
 
-#define loaddebug(register) \
+#define loaddebug(tsk,register) \
                __asm__("movl %0,%%edx\n\t" \
                        "movl %%edx,%%db" #register "\n\t" \
                        : /* no output */ \
-                       :"m" (current->debugreg[register]) \
+                       :"m" (tsk->debugreg[register]) \
                        :"dx");
 
 
@@ -65,61 +65,57 @@ __asm__("str %%ax\n\t" \
         *      the wrong process.
         */
 
-#define switch_to(tsk) do { \
+#define switch_to(prev,next) do { \
        cli();\
-       if(current->flags&PF_USEDFPU) \
+       if(prev->flags&PF_USEDFPU) \
        { \
-               __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard)); \
+               __asm__ __volatile__("fnsave %0":"=m" (prev->tss.i387.hard)); \
                __asm__ __volatile__("fwait"); \
-               current->flags&=~PF_USEDFPU;     \
+               prev->flags&=~PF_USEDFPU;        \
        } \
-       current->lock_depth=syscall_count; \
-       kernel_counter+=next->lock_depth-current->lock_depth; \
+       prev->lock_depth=syscall_count; \
+       kernel_counter+=next->lock_depth-prev->lock_depth; \
        syscall_count=next->lock_depth; \
 __asm__("pushl %%edx\n\t" \
        "movl "SYMBOL_NAME_STR(apic_reg)",%%edx\n\t" \
        "movl 0x20(%%edx), %%edx\n\t" \
        "shrl $22,%%edx\n\t" \
        "and  $0x3C,%%edx\n\t" \
-       "xchgl %%ecx,"SYMBOL_NAME_STR(current_set)"(,%%edx)\n\t" \
+       "movl %%ecx,"SYMBOL_NAME_STR(current_set)"(,%%edx)\n\t" \
        "popl %%edx\n\t" \
        "ljmp %0\n\t" \
        "sti\n\t" \
        : /* no output */ \
-       :"m" (*(((char *)&tsk->tss.tr)-4)), \
-        "c" (tsk) \
-       :"cx"); \
+       :"m" (*(((char *)&next->tss.tr)-4)), \
+        "c" (next)); \
        /* Now maybe reload the debug registers */ \
-       if(current->debugreg[7]){ \
-               loaddebug(0); \
-               loaddebug(1); \
-               loaddebug(2); \
-               loaddebug(3); \
-               loaddebug(6); \
+       if(prev->debugreg[7]){ \
+               loaddebug(prev,0); \
+               loaddebug(prev,1); \
+               loaddebug(prev,2); \
+               loaddebug(prev,3); \
+               loaddebug(prev,6); \
        } \
 } while (0)
 
 #else
-#define switch_to(tsk) do { \
-__asm__("cli\n\t" \
-       "xchgl %%ecx,"SYMBOL_NAME_STR(current_set)"\n\t" \
+#define switch_to(prev,next) do { \
+__asm__("movl %2,"SYMBOL_NAME_STR(current_set)"\n\t" \
        "ljmp %0\n\t" \
-       "sti\n\t" \
-       "cmpl %%ecx,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \
+       "cmpl %1,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \
        "jne 1f\n\t" \
        "clts\n" \
        "1:" \
-       : /* no output */ \
-       :"m" (*(((char *)&tsk->tss.tr)-4)), \
-        "c" (tsk) \
-       :"cx"); \
+       : /* no outputs */ \
+       :"m" (*(((char *)&next->tss.tr)-4)), \
+        "r" (prev), "r" (next)); \
        /* Now maybe reload the debug registers */ \
-       if(current->debugreg[7]){ \
-               loaddebug(0); \
-               loaddebug(1); \
-               loaddebug(2); \
-               loaddebug(3); \
-               loaddebug(6); \
+       if(prev->debugreg[7]){ \
+               loaddebug(prev,0); \
+               loaddebug(prev,1); \
+               loaddebug(prev,2); \
+               loaddebug(prev,3); \
+               loaddebug(prev,6); \
        } \
 } while (0)
 #endif
index baac4fb8721a9a6644e15ac0f54fbeb0143e3fd7..7083331e76da3fa5ac1f7ff7de48a1c6a416d202 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: asi.h,v 1.11 1995/11/25 02:31:11 davem Exp $ */
+/* $Id: asi.h,v 1.13 1996/03/01 07:20:51 davem Exp $ */
 #ifndef _SPARC_ASI_H
 #define _SPARC_ASI_H
 
 /* This is ROSS HyperSparc only. */
 #define ASI_M_FLUSH_IWHOLE 0x31   /* Flush entire ICACHE; wo, ss */
 
+/* Tsunami/Viking i/d cache flash clear. */
+#define ASI_M_IC_FLCLEAR   0x36
+#define ASI_M_DC_FLCLEAR   0x37
+
 #define ASI_M_DCDR         0x39   /* Data Cache Diagnostics Registerl rw, ss */
 
 /* Sparc V9 TI UltraSparc ASI's (V8 ploos ploos) */
index a52369449152fbd3f25bd77527edb52940bfc762..4578cd20329c786dcf02b89acee7d627a80dd819 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: auxio.h,v 1.8 1995/11/25 02:31:13 davem Exp $
+/* $Id: auxio.h,v 1.10 1996/01/03 03:52:58 davem Exp $
  * auxio.h:  Definitons and code for the Auxiliary I/O register.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -9,12 +9,13 @@
 #include <asm/system.h>
 #include <asm/vaddrs.h>
 
+extern unsigned char *auxio_register;
+
 /* This register is an unsigned char in IO space.  It does two things.
  * First, it is used to control the front panel LED light on machines
  * that have it (good for testing entry points to trap handlers and irq's)
  * Secondly, it controls various floppy drive parameters.
  */
-
 #define AUXIO_ORMEIN      0xf0    /* All writes must set these bits. */
 #define AUXIO_ORMEIN4M    0xc0    /* sun4m - All writes must set these bits. */
 #define AUXIO_FLPY_DENS   0x20    /* Floppy density, high if set. Read only. */
@@ -29,8 +30,7 @@
 #define AUXIO_FLPY_EJCT   0x02    /* Eject floppy disk.  Write only. */
 #define AUXIO_LED         0x01    /* On if set, off if unset. Read/Write */
 
-#define AUXREG   ((volatile unsigned char *)(AUXIO_VADDR + 3))
-#define AUXREG4M ((volatile unsigned char *)(AUXIO_VADDR))
+#define AUXREG   ((volatile unsigned char *)(auxio_register))
 
 #define TURN_ON_LED   *AUXREG = (*AUXREG | AUXIO_ORMEIN | AUXIO_LED)
 #define TURN_OFF_LED  *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_LED))
@@ -44,8 +44,9 @@
 extern inline void set_auxio(unsigned char bits_on, unsigned char bits_off)
 {
        unsigned char regval;
+       unsigned long flags;
 
-       cli();
+       save_flags(flags); cli();
 
        switch(sparc_cpu_model) {
        case sun4c:
@@ -53,16 +54,14 @@ extern inline void set_auxio(unsigned char bits_on, unsigned char bits_off)
                *AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN;
                break;
        case sun4m:
-               regval = *AUXREG4M;
-               *AUXREG4M = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M;
+               regval = *AUXREG;
+               *AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M;
                break;
        default:
                panic("Can't set AUXIO register on this machine.");
        };
 
-       sti();
-
-       return;
+       restore_flags(flags);
 }
 #endif /* !(__ASSEMBLY__) */
 
index b7a9a578003f19d8d0729c2c3efd0b00f62fa2ba..36148bcc57874ede6864781b96e0d0535cef23da 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.17 1995/11/25 02:31:15 davem Exp $
+/* $Id: bitops.h,v 1.18 1996/01/03 03:53:00 davem Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995, David S. Miller (davem@caip.rutgers.edu).
@@ -67,7 +67,7 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
 /* The following routine need not be atomic. */
 extern __inline__ unsigned long test_bit(int nr, const void *addr)
 {
-       return 1UL & (((int *) addr)[nr >> 5] >> (nr & 31));
+       return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31));
 }
 
 /* The easy/cheese version for now. */
index c24316433db78ba71d313da114e4d88d08eb7c23..f8ebf4aba3f13c29903b022d410fe4496e6103c9 100644 (file)
  * ME: MmuEnable -- Is the MMU doing translations? 0=no 1=yes
  */
 
-/* NEEDS TO BE FIXED */
-#define CYPRESS_MCABITS   0x01800000
-#define CYPRESS_MCMBITS   0x00600000
-#define CYPRESS_MVALID    0x00040000
-#define CYPRESS_MIDMASK   0x0003c000   /* Only on 605 */
-#define CYPRESS_BMODE     0x00002000
-#define CYPRESS_ACENABLE  0x00001000
+#define CYPRESS_MCA       0x00c00000
+#define CYPRESS_MCM       0x00300000
+#define CYPRESS_MVALID    0x00080000
+#define CYPRESS_MIDMASK   0x00078000   /* Only on 605 */
+#define CYPRESS_BMODE     0x00004000
+#define CYPRESS_ACENABLE  0x00002000
 #define CYPRESS_MRFLCT    0x00000800   /* Only on 605 */
 #define CYPRESS_CMODE     0x00000400
 #define CYPRESS_CLOCK     0x00000200   /* Only on 604 */
 #define CYPRESS_NFAULT    0x00000002
 #define CYPRESS_MENABLE   0x00000001
 
+extern inline void cypress_flush_page(unsigned long page)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (page), "i" (ASI_M_FLUSH_PAGE));
+}
+
+extern inline void cypress_flush_segment(unsigned long addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_FLUSH_SEG));
+}
+
+extern inline void cypress_flush_region(unsigned long addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_FLUSH_REGION));
+}
+
+extern inline void cypress_flush_context(void)
+{
+       __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+                            "i" (ASI_M_FLUSH_CTX));
+}
+
 #endif /* !(_SPARC_CYPRESS_H) */
index ecdb0e1cb5481d5263d0efc9a106dbf6887910aa..71e1154a02b9079ebb96efa41b5946a00d54fbd0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.7 1995/11/25 02:31:32 davem Exp $
+/* $Id: delay.h,v 1.8 1996/01/28 02:09:21 davem Exp $
  * delay.h: Linux delay routines on the Sparc.
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu).
@@ -7,6 +7,8 @@
 #ifndef __SPARC_DELAY_H
 #define __SPARC_DELAY_H
 
+extern unsigned long loops_per_sec;
+
 extern __inline__ void __delay(unsigned long loops)
 {
        __asm__ __volatile__("cmp %0, 0\n\t"
@@ -16,23 +18,8 @@ extern __inline__ void __delay(unsigned long loops)
                             "0" (loops));
 }
 
-/* udelay(usecs) is used for very short delays up to 1 millisecond. On
- * the Sparc (both sun4c and sun4m) we have a free running usec counter
- * available to us already.
- */
-extern volatile unsigned int *master_l10_counter;
-
-extern __inline__ void udelay(unsigned int usecs)
-{
-       unsigned int ccnt;
-
-       if(!master_l10_counter)
-               return;
-       ccnt=*master_l10_counter;
-       for(usecs+=1; usecs; usecs--, ccnt=*master_l10_counter)
-               while(*master_l10_counter == ccnt)
-                       __asm__("": : :"memory");
-}
+/* This is too messy with inline asm on the Sparc. */
+extern void udelay(unsigned long usecs);
 
 /* calibrate_delay() wants this... */
 #define muldiv(a, b, c)    (((a)*(b))/(c))
index 8dd3ecbfd731ebd2bd8c6663e6bc62f6658df851..b8c576318a12aa995ea3adad9e1f47554c19acbf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.12 1995/11/25 02:31:34 davem Exp $
+/* $Id: dma.h,v 1.13 1996/02/17 17:32:33 miguel Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -93,6 +93,7 @@ extern unsigned long dvma_init(struct linux_sbus *, unsigned long);
 #define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
 #define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
 #define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
 #define DMA_ST_WRITE     0x00000100        /* write from device to memory */
 #define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
 #define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pendind Read */
diff --git a/include/asm-sparc/fbio.h b/include/asm-sparc/fbio.h
new file mode 100644 (file)
index 0000000..0ab7fbe
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef __LINUX_FBIO_H
+#define __LINUX_FBIO_H
+
+/* Constants used for fbio SunOS compatibility -miguel */
+
+/* Frame buffer types */
+#define FBTYPE_NOTYPE           -1
+#define FBTYPE_SUN1BW           0   /* mono */
+#define FBTYPE_SUN1COLOR        1 
+#define FBTYPE_SUN2BW           2 
+#define FBTYPE_SUN2COLOR        3 
+#define FBTYPE_SUN2GP           4 
+#define FBTYPE_SUN5COLOR        5 
+#define FBTYPE_SUN3COLOR        6 
+#define FBTYPE_MEMCOLOR         7 
+#define FBTYPE_SUN4COLOR        8 
+#define FBTYPE_NOTSUN1          9 
+#define FBTYPE_NOTSUN2          10
+#define FBTYPE_NOTSUN3          11
+#define FBTYPE_SUNFAST_COLOR    12  /* cg6 */
+#define FBTYPE_SUNROP_COLOR     13
+#define FBTYPE_SUNFB_VIDEO      14
+#define FBTYPE_SUNGIFB          15
+#define FBTYPE_SUNGPLAS         16
+#define FBTYPE_SUNGP3           17
+#define FBTYPE_SUNGT            18
+#define FBTYPE_SUNLEO           19      /* zx Leo card */
+#define FBTYPE_MDICOLOR         20      /* cg14 */
+#define FBTYPE_LASTPLUSONE      21
+
+/* fbio ioctls */
+/* Returned by FBIOGTYPE */
+struct  fbtype {
+        int     fb_type;        /* fb type, see above */
+        int     fb_height;      /* pixels */
+        int     fb_width;       /* pixels */
+        int     fb_depth;
+        int     fb_cmsize;      /* color map entries */
+        int     fb_size;        /* fb size in bytes */
+};
+#define FBIOGTYPE _IOR('F', 0, struct fbtype)
+
+/* Used by FBIOPUTCMAP */
+struct  fbcmap {
+        int             index;          /* first element (0 origin) */
+        int             count;
+        unsigned char   *red;
+        unsigned char   *green;
+        unsigned char   *blue;
+};
+
+#define FBIOPUTCMAP _IOW('F', 3, struct fbcmap)
+
+/* # of device specific values */
+#define FB_ATTR_NDEVSPECIFIC    8
+/* # of possible emulations */
+#define FB_ATTR_NEMUTYPES       4
+struct fbsattr {
+        int     flags;
+        int     emu_type;      /* -1 if none */
+        int     dev_specific[FB_ATTR_NDEVSPECIFIC];
+};
+struct fbgattr {
+        int     real_type;     /* real frame buffer type */
+        int     owner;         /* unknown */
+        struct fbtype fbtype;  /* real frame buffer fbtype */
+        struct fbsattr sattr;   
+        int     emu_types[FB_ATTR_NEMUTYPES]; /* supported emulations */
+};
+#define FBIOSATTR  _IOW('F', 5, struct fbgattr) /* Unsupported: */
+#define FBIOGATTR  _IOR('F', 6, struct fbgattr)        /* supporoted */
+
+#define FBIOSVIDEO _IOW('F', 7, int)
+#define FBIOGVIDEO _IOR('F', 8, int)
+
+/* Cursor position */
+struct fbcurpos {
+#ifdef __KERNEL__
+       short fbx, fby;
+#else
+        short x, y;
+#endif
+};
+
+/* Cursor operations */
+#define FB_CUR_SETCUR   0x01   /* Enable/disable cursor display */
+#define FB_CUR_SETPOS   0x02   /* set cursor position */
+#define FB_CUR_SETHOT   0x04   /* set cursor hotspot */
+#define FB_CUR_SETCMAP  0x08   /* set color map for the cursor */
+#define FB_CUR_SETSHAPE 0x10   /* set shape */
+#define FB_CUR_SETALL   0x1F   /* all of the above */
+
+struct fbcursor {
+        short set;              /* what to set, choose from the list above */
+        short enable;           /* cursor on/off */
+        struct fbcurpos pos;    /* cursor position */
+        struct fbcurpos hot;    /* cursor hot spot */
+        struct fbcmap cmap;     /* color map info */
+        struct fbcurpos size;   /* cursor bit map size */
+        char *image;            /* cursor image bits */
+        char *mask;             /* cursor mask bits */
+};
+
+/* set/get cursor attributes/shape */
+#define FBIOSCURSOR     _IOW('F', 24, struct fbcursor)
+#define FBIOGCURSOR     _IOWR('F', 25, struct fbcursor)
+/* set/get cursor position */
+#define FBIOSCURPOS     _IOW('F', 26, struct fbcurpos)
+#define FBIOGCURPOS     _IOW('F', 27, struct fbcurpos)
+/* get max cursor size */
+#define FBIOGCURMAX     _IOR('F', 28, struct fbcurpos)
+#ifdef __KERNEL__
+/* Addresses on the fd of a cgsix that are mappable */
+#define CG6_FBC    0x70000000
+#define CG6_TEC    0x70001000
+#define CG6_BTREGS 0x70002000
+#define CG6_FHC    0x70004000
+#define CG6_THC    0x70005000
+#define CG6_ROM    0x70006000
+#define CG6_RAM    0x70016000
+#define CG6_DHC    0x80000000
+
+#define CG3_MMAP_OFFSET 0x4000000
+#endif /* KERNEL */
+
+#endif /* __LINUX_FBIO_H */
index f5653f18f0c2566b75a8f0c915037f44e7eb7baf..22ea2ae9ad8697fd1162babf4ad3c52a6a88ba67 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fcntl.h,v 1.5 1995/11/25 02:31:43 davem Exp $ */
+/* $Id: fcntl.h,v 1.6 1996/01/28 02:09:23 davem Exp $ */
 #ifndef _SPARC_FCNTL_H
 #define _SPARC_FCNTL_H
 
 #define O_APPEND       0x0008
 #define FASYNC         0x0040  /* fcntl, for BSD compatibility */
 #define O_CREAT                0x0200  /* not fcntl */
-#define O_EXCL         0x0800  /* not fcntl */
-#define O_NOCTTY       0x8000  /* not fcntl */
 #define O_TRUNC                0x0400  /* not fcntl */
+#define O_EXCL         0x0800  /* not fcntl */
 #define O_SYNC         0x2000
 #define O_NONBLOCK     0x4000
+#define O_NOCTTY       0x8000  /* not fcntl */
 
 #define F_DUPFD                0       /* dup */
 #define F_GETFD                1       /* get f_flags */
index 3b59621a27f1bcd88f3fd48cf6b11fd933c6a64a..3358037c76c9dc1ec6a7a536afd69e9515cc725b 100644 (file)
@@ -250,7 +250,7 @@ static inline void sun_fd_enable_dma(void)
 }
 
 /* Our low-level entry point in arch/sparc/kernel/entry.S */
-extern void floppy_hardint(int irq, void *dev_id, struct pt_regs *regs);
+extern void floppy_hardint(int irq, void *unused, struct pt_regs *regs);
 
 static int sun_fd_request_irq(void)
 {
@@ -259,7 +259,7 @@ static int sun_fd_request_irq(void)
 
        if(!once) {
                once = 1;
-               error = request_fast_irq(FLOPPY_IRQ, floppy_hardint, SA_INTERRUPT, "floppy", NULL);
+               error = request_fast_irq(FLOPPY_IRQ, floppy_hardint, SA_INTERRUPT, "floppy");
                return ((error == 0) ? 0 : -1);
        } else return 0;
 }
index ae1ff73ae8ceab4cab2b120d5574dfb920340c08..53a4c63a27c50f7fa8830deec098f49ee4e5bf72 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.19 1995/11/25 02:31:47 davem Exp $ */
+/* $Id: head.h,v 1.23 1996/02/15 09:12:55 davem Exp $ */
 #ifndef __SPARC_HEAD_H
 #define __SPARC_HEAD_H
 
 #define TRAP_ENTRY(type, label) \
        rd %psr, %l0; b label; rd %wim, %l3; nop;
 
+/* Data/text faults. Defaults to sun4c version at boot time. */
+#define SPARC_TFAULT rd %psr, %l0; rd %wim, %l3; b sun4c_fault; mov 1, %l7;
+#define SPARC_DFAULT rd %psr, %l0; rd %wim, %l3; b sun4c_fault; mov 0, %l7;
+
 /* This is for traps we should NEVER get. */
 #define BAD_TRAP(num) \
         rd %psr, %l0; mov num, %l7; b bad_trap_handler; rd %wim, %l3;
 
 /* Software trap for SunOS4.1.x system calls. */
 #define SUNOS_SYSCALL_TRAP \
+        rd %psr, %l0; \
         sethi %hi(C_LABEL(sunos_sys_table)), %l7; \
-        or %l7, %lo(C_LABEL(sunos_sys_table)), %l7; \
         b linux_sparc_syscall; \
-        rd %psr, %l0;
+        or %l7, %lo(C_LABEL(sunos_sys_table)), %l7;
 
 /* Software trap for Slowaris system calls. */
 #define SOLARIS_SYSCALL_TRAP \
 #define TRAP_ENTRY_INTERRUPT(int_level) \
         mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3;
 
-/* This is for software interrupts, which currently (atleast on the sun4c)
- * correspond to IRQ levels 1, 4, and 6.
- */
-#define TRAP_ENTRY_SOFTINT(int_level) \
-        mov int_level, %l7; rd %psr, %l0; b soft_irq_entry; rd %wim, %l3;
-
 /* NMI's (Non Maskable Interrupts) are special, you can't keep them
  * from coming in, and basically if you get one, the shows over. ;(
  * On the sun4c they are usually asyncronous memory errors, on the
@@ -88,7 +86,7 @@
  * command you to do CPU tricks, read your mailbox for more info."
  */
 #define NMI_TRAP \
-        rd %wim, %l3; b linux_trap_nmi; mov %psr, %l0; nop;
+        rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop;
 
 /* Window overflows/underflows are special and we need to try and be as
  * efficient as possible here....
diff --git a/include/asm-sparc/iommu.h b/include/asm-sparc/iommu.h
new file mode 100644 (file)
index 0000000..702e489
--- /dev/null
@@ -0,0 +1,117 @@
+/* iommu.h: Definitions for the sun4m IOMMU.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_IOMMU_H
+#define _SPARC_IOMMU_H
+
+#include <asm/page.h>
+
+/* The iommu handles all virtual to physical address translations
+ * that occur between the SBUS and physical memory.  Access by
+ * the cpu to IO registers and similar go over the mbus so are
+ * translated by the on chip SRMMU.  The iommu and the srmmu do
+ * not need to have the same translations at all, in fact most
+ * of the time the translations they handle are a disjunct set.
+ * Basically the iommu handles all dvma sbus activity.
+ */
+
+/* The IOMMU registers occupy three pages in IO space. */
+struct iommu_regs {
+       /* First page */
+       volatile unsigned long control;    /* IOMMU control */
+       volatile unsigned long base;       /* Physical base of iopte page table */
+       volatile unsigned long _unused1[3];
+       volatile unsigned long tlbflush;   /* write only */
+       volatile unsigned long pageflush;  /* write only */
+       volatile unsigned long _unused2[1017];
+       /* Second page */
+       volatile unsigned long afsr;       /* Async-fault status register */
+       volatile unsigned long afar;       /* Async-fault physical address */
+       volatile unsigned long _unused3[2];
+       volatile unsigned long sbuscfg0;   /* SBUS configuration registers, per-slot */
+       volatile unsigned long sbuscfg1;
+       volatile unsigned long sbuscfg2;
+       volatile unsigned long sbuscfg3;
+       volatile unsigned long mfsr;       /* Memory-fault status register */
+       volatile unsigned long mfar;       /* Memory-fault physical address */
+       volatile unsigned long _unused4[1014];
+       /* Third page */
+       volatile unsigned long mid;        /* IOMMU module-id */
+};
+
+#define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
+#define IOMMU_CTRL_VERS     0x0f000000 /* Version */
+#define IOMMU_CTRL_RNGE     0x0000001c /* Mapping RANGE */
+#define IOMMU_RNGE_16MB     0x00000000 /* 0xff000000 -> 0xffffffff */
+#define IOMMU_RNGE_32MB     0x00000004 /* 0xfe000000 -> 0xffffffff */
+#define IOMMU_RNGE_64MB     0x00000008 /* 0xfc000000 -> 0xffffffff */
+#define IOMMU_RNGE_128MB    0x0000000c /* 0xf8000000 -> 0xffffffff */
+#define IOMMU_RNGE_256MB    0x00000010 /* 0xf0000000 -> 0xffffffff */
+#define IOMMU_RNGE_512MB    0x00000014 /* 0xe0000000 -> 0xffffffff */
+#define IOMMU_RNGE_1GB      0x00000018 /* 0xc0000000 -> 0xffffffff */
+#define IOMMU_RNGE_2GB      0x0000001c /* 0x80000000 -> 0xffffffff */
+#define IOMMU_CTRL_ENAB     0x00000001 /* IOMMU Enable */
+
+#define IOMMU_AFSR_ERR      0x80000000 /* LE, TO, or BE asserted */
+#define IOMMU_AFSR_LE       0x40000000 /* SBUS reports error after transaction */
+#define IOMMU_AFSR_TO       0x20000000 /* Write access took more than 12.8 us. */
+#define IOMMU_AFSR_BE       0x10000000 /* Write access received error acknowledge */
+#define IOMMU_AFSR_SIZE     0x0e000000 /* Size of transaction causing error */
+#define IOMMU_AFSR_S        0x01000000 /* Sparc was in supervisor mode */
+#define IOMMU_AFSR_RESV     0x00f00000 /* Reserver, forced to 0x8 by hardware */
+#define IOMMU_AFSR_ME       0x00080000 /* Multiple errors occurred */
+#define IOMMU_AFSR_RD       0x00040000 /* A read operation was in progress */
+#define IOMMU_AFSR_FAV      0x00020000 /* IOMMU afar has valid contents */
+
+#define IOMMU_SBCFG_SAB30   0x00010000 /* Phys-address bit 30 when bypass enabled */
+#define IOMMU_SBCFG_BA16    0x00000004 /* Slave supports 16 byte bursts */
+#define IOMMU_SBCFG_BA8     0x00000002 /* Slave supports 8 byte bursts */
+#define IOMMU_SBCFG_BYPASS  0x00000001 /* Bypass IOMMU, treat all addresses
+                                         produced by this device as pure
+                                         physical. */
+
+#define IOMMU_MFSR_ERR      0x80000000 /* One or more of PERR1 or PERR0 */
+#define IOMMU_MFSR_S        0x01000000 /* Sparc was in supervisor mode */
+#define IOMMU_MFSR_CPU      0x00800000 /* CPU transaction caused parity error */
+#define IOMMU_MFSR_ME       0x00080000 /* Multiple parity errors occurred */
+#define IOMMU_MFSR_PERR     0x00006000 /* high bit indicates parity error occurred
+                                         on the even word of the access, low bit
+                                         indicated odd word caused the parity error */
+#define IOMMU_MFSR_BM       0x00001000 /* Error occurred while in boot mode */
+#define IOMMU_MFSR_C        0x00000800 /* Address causing error was marked cacheable */
+#define IOMMU_MFSR_RTYP     0x000000f0 /* Memory request transaction type */
+
+#define IOMMU_MID_SBAE      0x001f0000 /* SBus arbitration enable */
+#define IOMMU_MID_SE        0x00100000 /* Enables SCSI/ETHERNET arbitration */
+#define IOMMU_MID_SB3       0x00080000 /* Enable SBUS device 3 arbitration */
+#define IOMMU_MID_SB2       0x00040000 /* Enable SBUS device 2 arbitration */
+#define IOMMU_MID_SB1       0x00020000 /* Enable SBUS device 1 arbitration */
+#define IOMMU_MID_SB0       0x00010000 /* Enable SBUS device 0 arbitration */
+#define IOMMU_MID_MID       0x0000000f /* Module-id, hardcoded to 0x8 */
+
+/* The format of an iopte in the page tables */
+#define IOPTE_PAGE          0x07ffff00 /* Physical page number (PA[30:12]) */
+#define IOPTE_WRITE         0x00000004 /* Writeable */
+#define IOPTE_VALID         0x00000002 /* IOPTE is valid */
+#define IOPTE_WAZ           0x00000001 /* Write as zeros */
+
+struct iommu_struct {
+       struct iommu_regs *regs;
+       iopte_t *page_table;
+       /* For convenience */
+       unsigned long start; /* First managed virtual address */
+       unsigned long end;   /* Last managed virtual address */
+};
+
+extern inline void iommu_invalidate(struct iommu_regs *regs)
+{
+       regs->tlbflush = 0;
+}
+
+extern inline void iommu_invalidate_page(struct iommu_regs *regs, unsigned long page)
+{
+       regs->pageflush = (page & PAGE_MASK);
+}
+
+#endif /* !(_SPARC_IOMMU_H) */
index b6b68ec791b452575e37911057d96745518bfc39..b6d7639af6a6063badbc24cf8839501f5a576eb0 100644 (file)
@@ -16,7 +16,7 @@
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
-extern int request_fast_irq(unsigned int irq, void (*handler)(int, struct pt_regs *), unsigned long flags, const char *devname);
+extern int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname);
 
 /* On the sun4m, just like the timers, we have both per-cpu and master
  * interrupt registers.
@@ -69,4 +69,6 @@ extern struct sun4m_intregs *sun4m_interrupts;
 #define SUN4M_INT_E14     0x00000080
 #define SUN4M_INT_E10     0x00080000
 
+/* XXX add cross-cpu ipi functions XXX */
+
 #endif
diff --git a/include/asm-sparc/kbio.h b/include/asm-sparc/kbio.h
new file mode 100644 (file)
index 0000000..0f8fb5a
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __LINUX_KBIO_H
+#define __LINUX_KBIO_H
+
+/* Return keyboard type */
+#define KIOCTYPE    _IOR('k', 9, int)
+/* Return Keyboard layout */
+#define KIOCLAYOUT  _IOR('k', 20, int)
+
+enum {
+    TR_NONE,
+    TR_ASCII,                  /* keyboard is in regular state */
+    TR_EVENT,                  /* keystrokes sent as firm events */
+    TR_UNTRANS_EVENT           /* EVENT+up and down+no translation */
+};
+
+/* Return the current keyboard translation */
+#define KIOCGTRANS  _IOR('k', 5, int)
+/* Set the keyboard translation */
+#define KIOCTRANS   _IOW('k', 0, int)
+
+/* Send a keyboard command */
+#define KIOCCMD     _IOW('k', 8, int)
+
+/* Return if keystrokes are being sent to /dev/kbd */
+
+/* Set routing of keystrokes to /dev/kbd */
+#define KIOCSDIRECT _IOW('k', 10, int)
+
+/* Top bit records if the key is up or down */
+#define KBD_UP      0x80
+
+/* Usable information */
+#define KBD_KEYMASK 0x7f
+
+/* All keys up */
+#define KBD_IDLE    0x75
+#endif /* __LINUX_KBIO_H */
index 318356abba2fad0168c56342d873ba9b36031293..ba71156665a4c07bd4858afa29b09f3d12771067 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: kdebug.h,v 1.7 1995/11/25 02:31:55 davem Exp $
+/* $Id: kdebug.h,v 1.8 1995/12/25 23:31:38 davem Exp $
  * kdebug.h:  Defines and definitions for debugging the Linux kernel
  *            under various kernel debuggers.
  *
@@ -72,4 +72,8 @@ extern __inline__ void sp_enter_debugger(void)
 #define KDEBUG_DUNNO2_OFF   0x8
 #define KDEBUG_TEACH_OFF    0xc
 
+/* ugh... */
+#define TRAP_TRACE(reg1, reg2) \
+     
+
 #endif /* !(_SPARC_KDEBUG_H) */
index 1d6217436689b754a99cbe5b0ce827c76daa3904..79534dac8d18356eb060cb819b91d844128866ec 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: kgdb.h,v 1.6 1995/11/25 02:31:57 davem Exp $
+/* $Id: kgdb.h,v 1.7 1995/11/27 02:43:18 davem Exp $
  * kgdb.h: Defines and declarations for serial line source level
  *         remote debugging of the Linux kernel using gdb.
  *
@@ -52,39 +52,39 @@ struct kgdb_frame {
 #define KGDB_NPC    0x114
 
 #define SAVE_KGDB_GLOBALS(reg) \
-        std     %g0, [%reg + STACKFRAME_SZ + KGDB_G0]; \
-        std     %g2, [%reg + STACKFRAME_SZ + KGDB_G2]; \
-        std     %g4, [%reg + STACKFRAME_SZ + KGDB_G4]; \
-        std     %g6, [%reg + STACKFRAME_SZ + KGDB_G6];
+        std     %g0, [%reg + REGWIN_SZ + KGDB_G0]; \
+        std     %g2, [%reg + REGWIN_SZ + KGDB_G2]; \
+        std     %g4, [%reg + REGWIN_SZ + KGDB_G4]; \
+        std     %g6, [%reg + REGWIN_SZ + KGDB_G6];
 
 #define SAVE_KGDB_INS(reg) \
-        std     %i0, [%reg + STACKFRAME_SZ + KGDB_I0]; \
-        std     %i2, [%reg + STACKFRAME_SZ + KGDB_I2]; \
-        std     %i4, [%reg + STACKFRAME_SZ + KGDB_I4]; \
-        std     %i6, [%reg + STACKFRAME_SZ + KGDB_I6];
+        std     %i0, [%reg + REGWIN_SZ + KGDB_I0]; \
+        std     %i2, [%reg + REGWIN_SZ + KGDB_I2]; \
+        std     %i4, [%reg + REGWIN_SZ + KGDB_I4]; \
+        std     %i6, [%reg + REGWIN_SZ + KGDB_I6];
 
 #define SAVE_KGDB_SREGS(reg, reg_y, reg_psr, reg_wim, reg_tbr, reg_pc, reg_npc) \
-        st      %reg_y, [%reg + STACKFRAME_SZ + KGDB_Y]; \
-        st      %reg_psr, [%reg + STACKFRAME_SZ + KGDB_PSR]; \
-        st      %reg_wim, [%reg + STACKFRAME_SZ + KGDB_WIM]; \
-        st      %reg_tbr, [%reg + STACKFRAME_SZ + KGDB_TBR]; \
-        st      %reg_pc, [%reg + STACKFRAME_SZ + KGDB_PC]; \
-        st      %reg_npc, [%reg + STACKFRAME_SZ + KGDB_NPC];
+        st      %reg_y, [%reg + REGWIN_SZ + KGDB_Y]; \
+        st      %reg_psr, [%reg + REGWIN_SZ + KGDB_PSR]; \
+        st      %reg_wim, [%reg + REGWIN_SZ + KGDB_WIM]; \
+        st      %reg_tbr, [%reg + REGWIN_SZ + KGDB_TBR]; \
+        st      %reg_pc, [%reg + REGWIN_SZ + KGDB_PC]; \
+        st      %reg_npc, [%reg + REGWIN_SZ + KGDB_NPC];
 
 #define LOAD_KGDB_GLOBALS(reg) \
-        ld      [%reg + STACKFRAME_SZ + KGDB_G1], %g1; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_G2], %g2; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_G4], %g4; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_G6], %g6;
+        ld      [%reg + REGWIN_SZ + KGDB_G1], %g1; \
+        ldd     [%reg + REGWIN_SZ + KGDB_G2], %g2; \
+        ldd     [%reg + REGWIN_SZ + KGDB_G4], %g4; \
+        ldd     [%reg + REGWIN_SZ + KGDB_G6], %g6;
 
 #define LOAD_KGDB_INS(reg) \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_I0], %i0; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_I2], %i2; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_I4], %i4; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_I6], %i6;
+        ldd     [%reg + REGWIN_SZ + KGDB_I0], %i0; \
+        ldd     [%reg + REGWIN_SZ + KGDB_I2], %i2; \
+        ldd     [%reg + REGWIN_SZ + KGDB_I4], %i4; \
+        ldd     [%reg + REGWIN_SZ + KGDB_I6], %i6;
 
 #define LOAD_KGDB_SREGS(reg, reg_y_and_psr, reg_pc_and_npc) \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_Y], %reg_y_and_psr; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_PC], %reg_pc_and_npc;
+        ldd     [%reg + REGWIN_SZ + KGDB_Y], %reg_y_and_psr; \
+        ldd     [%reg + REGWIN_SZ + KGDB_PC], %reg_pc_and_npc;
 
 #endif /* !(_SPARC_KGDB_H) */
index a5027611061400a2e1deec9a39a5cb7178ed7950..71442dd24bd479c23da1500a326f369cc7be701c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: memreg.h,v 1.4 1995/11/25 02:32:02 davem Exp $ */
+/* $Id: memreg.h,v 1.5 1995/12/02 20:05:25 davem Exp $ */
 #ifndef _SPARC_MEMREG_H
 #define _SPARC_MEMREG_H
 /* memreg.h:  Definitions of the values found in the synchronous
@@ -22,7 +22,8 @@
 #define SUN4C_SYNC_BADWRITE  0x8000  /* while writing something went bogus */
 
 #define SUN4C_SYNC_BOLIXED  \
-        (SUN4C_SYNC_WDRESET|SUN4C_SYNC_SIZE|SUN4C_SYNC_SBUS|SUN4C_SYNC_NOMEM)
+        (SUN4C_SYNC_WDRESET | SUN4C_SYNC_SIZE | SUN4C_SYNC_SBUS | \
+         SUN4C_SYNC_NOMEM | SUN4C_SYNC_PARITY)
 
 /* Now the asynchronous error codes, these are almost always produced
  * by the cache writing things back to memory and getting a bad translation.
index 3cbd080e864fd96095ceea4a660642a6147f78d9..b4968bdaf079c2d5ee87bab5e3cd4ce23770d673 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mman.h,v 1.5 1995/11/25 02:32:03 davem Exp $ */
+/* $Id: mman.h,v 1.6 1996/01/03 03:53:05 davem Exp $ */
 #ifndef __SPARC_MMAN_H__
 #define __SPARC_MMAN_H__
 
@@ -42,4 +42,8 @@
 #define MC_LOCKAS       5  /* Lock an entire address space of the calling process */
 #define MC_UNLOCKAS     6  /* Unlock entire address space of calling process */
 
+/* compatibility flags */
+#define MAP_ANON       MAP_ANONYMOUS
+#define MAP_FILE       0
+
 #endif /* __SPARC_MMAN_H__ */
diff --git a/include/asm-sparc/mmu_context.h b/include/asm-sparc/mmu_context.h
new file mode 100644 (file)
index 0000000..f9074df
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __SPARC_MMU_CONTEXT_H
+#define __SPARC_MMU_CONTEXT_H
+
+/* For now I still leave the context handling in the
+ * switch_to() macro, I'll do it right soon enough.
+ */
+#define get_mmu_context(x) do { } while (0)
+
+/* Initialize the context related info for a new mm_struct
+ * instance.
+ */
+#define init_new_context(mm) ((mm)->context = NO_CONTEXT)
+
+#endif /* !(__SPARC_MMU_CONTEXT_H) */
index c9344f28779b1010ca28332a471c57a66e82bf61..15acacd834302ed51eccc55d71e7f3774c3e58d8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.5 1995/11/25 02:32:14 davem Exp $
+/* $Id: oplib.h,v 1.6 1996/01/01 02:47:19 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -258,6 +258,9 @@ extern char *prom_firstprop(int node);
  */
 extern char *prom_nextprop(int node, char *prev_property);
 
+/* Returns 1 if the specified node has given property. */
+extern int prom_node_has_property(int node, char *property);
+
 /* Set the indicated property at the given node with the passed value.
  * Returns the number of bytes of your value that the prom took.
  */
index 1a8dee26ff9f3b141b88eaffdcb81544ca5f5017..626088fff3136d62c7059b2a586f1602c9109afd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.22 1995/11/25 02:32:16 davem Exp $
+/* $Id: page.h,v 1.26 1996/01/03 03:53:07 davem Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -8,22 +8,16 @@
 #ifndef _SPARC_PAGE_H
 #define _SPARC_PAGE_H
 
-#include <asm/asi.h>        /* for get/set segmap/pte routines */
-#include <asm/contregs.h>   /* for switch_to_context */
 #include <asm/head.h>       /* for KERNBASE */
 
-#define PAGE_SHIFT   12             /* This is the virtual page... */
+#define PAGE_SHIFT   12
 #define PAGE_OFFSET  KERNBASE
 #define PAGE_SIZE    (1 << PAGE_SHIFT)
-
-/* to mask away the intra-page address bits */
 #define PAGE_MASK    (~(PAGE_SIZE-1))
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
-#include <asm/processor.h>
-
 /* The following structure is used to hold the physical
  * memory configuration of the machine.  This is filled in
  * probe_memory() and is later used by mem_init() to set up
@@ -41,6 +35,14 @@ struct sparc_phys_banks {
 
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 
+/* Cache alias structure.  Entry is valid if context != -1. */
+struct cache_palias {
+       unsigned long vaddr;
+       int context;
+};
+
+extern struct cache_palias *sparc_aliases;
+
 #define STRICT_MM_TYPECHECKS
 
 #ifdef STRICT_MM_TYPECHECKS
@@ -48,54 +50,59 @@ extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
  * These are used to make use of C type-checking..
  */
 typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long iopte; } iopte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long ctxd; } ctxd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct { unsigned long iopgprot; } iopgprot_t;
 
 #define pte_val(x)     ((x).pte)
+#define iopte_val(x)   ((x).iopte)
 #define pmd_val(x)      ((x).pmd)
 #define pgd_val(x)     ((x).pgd)
+#define ctxd_val(x)    ((x).ctxd)
 #define pgprot_val(x)  ((x).pgprot)
+#define iopgprot_val(x)        ((x).iopgprot)
 
 #define __pte(x)       ((pte_t) { (x) } )
+#define __iopte(x)     ((iopte_t) { (x) } )
 #define __pmd(x)        ((pmd_t) { (x) } )
 #define __pgd(x)       ((pgd_t) { (x) } )
+#define __ctxd(x)      ((ctxd_t) { (x) } )
 #define __pgprot(x)    ((pgprot_t) { (x) } )
+#define __iopgprot(x)  ((iopgprot_t) { (x) } )
 
 #else
 /*
  * .. while these make it easier on the compiler
  */
 typedef unsigned long pte_t;
+typedef unsigned long iopte_t;
 typedef unsigned long pmd_t;
 typedef unsigned long pgd_t;
+typedef unsigned long ctxd_t;
 typedef unsigned long pgprot_t;
+typedef unsigned long iopgprot_t;
 
 #define pte_val(x)     (x)
+#define iopte_val(x)   (x)
 #define pmd_val(x)      (x)
 #define pgd_val(x)     (x)
+#define ctxd_val(x)    (x)
 #define pgprot_val(x)  (x)
+#define iopgprot_val(x)        (x)
 
 #define __pte(x)       (x)
+#define __iopte(x)     (x)
 #define __pmd(x)        (x)
 #define __pgd(x)       (x)
+#define __ctxd(x)      (x)
 #define __pgprot(x)    (x)
+#define __iopgprot(x)  (x)
 
 #endif
 
-/* The current va context is global and known, so all that is needed to
- * do an invalidate is flush the VAC on a sun4c or call the ASI flushing
- * routines on a SRMMU.
- */
-
-extern void (*invalidate)(void);
-
-/* Certain architectures need to do special things when pte's
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-extern void (*set_pte)(pte_t *pteptr, pte_t pteval);
-
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)  (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
@@ -106,214 +113,6 @@ extern void (*set_pte)(pte_t *pteptr, pte_t pteval);
 
 #endif /* !(__ASSEMBLY__) */
 
-/* The rest is kind of funky because on the sparc, the offsets into the mmu 
- * entries are encoded in magic alternate address space tables. I will 
- * probably find some nifty inline assembly routines to do the equivalent. 
- * Much thought must go into this code.   (davem@caip.rutgers.edu)
- */
-
-/* Bitfields within a Sparc sun4c PTE (page table entry). */
-
-#define PTE_V     0x80000000   /* valid bit */
-#define PTE_ACC   0x60000000   /* access bits */
-#define PTE_W     0x40000000   /* writable bit */
-#define PTE_P     0x20000000   /* privileged page */
-#define PTE_NC    0x10000000   /* page is non-cacheable */
-#define PTE_TYP   0x0c000000   /* page type field */
-#define PTE_RMEM  0x00000000   /* type == on board real memory */
-#define PTE_IO    0x04000000   /* type == i/o area */
-#define PTE_VME16 0x08000000   /* type == 16-bit VME area */
-#define PTE_VME32 0x0c000000   /* type == 32-bit VME area */
-#define PTE_R     0x02000000   /* page has been referenced */
-#define PTE_M     0x01000000   /* page has been modified */
-#define PTE_RESV  0x00f80000   /* reserved bits */
-#define PTE_PHYPG 0x0007ffff   /* phys pg number, sun4c only uses 16bits */
-
-/* SRMMU defines */
-/* The fields in an srmmu virtual address when it gets translated.
- *
- *  -------------------------------------------------------------
- *  |   INDEX 1   |   INDEX 2   |   INDEX 3   |   PAGE OFFSET   |
- *  -------------------------------------------------------------
- *  31          24 23        18  17         12  11              0
- */
-#define SRMMU_IDX1_SHIFT      24
-#define SRMMU_IDX1_MASK       0xff000000
-#define SRMMU_IDX2_SHIFT      18
-#define SRMMU_IDX2_MASK       0x00fc0000
-#define SRMMU_IDX3_SHIFT      12
-#define SRMMU_IDX3_MASK       0x0003f000
-
-#define SRMMU_PGOFFSET_MASK   0x00000fff
-/* The page table sizes for the various levels in bytes. */
-#define SRMMU_LV1_PTSIZE      1024
-#define SRMMU_LV2_PTSIZE      256
-#define SRMMU_LV3_PTSIZE      256
-
-/* Definition of the values in the ET field of PTD's and PTE's */
-#define SRMMU_ET_INVALID      0x0
-#define SRMMU_ET_PTD          0x1
-#define SRMMU_ET_PTE          0x2
-#define SRMMU_ET_RESV         0x3
-#define SRMMU_ET_PTDBAD       0x3   /* Upward compatability my butt. */
-
-/* Page table directory bits.
- *
- * ----------------
- * |  PTP    | ET |
- * ----------------
- * 31       2 1  0
- *
- * PTP:  The physical page table pointer.  This value appears on
- *       bits 35->6 on the physical address bus during translation.
- *
- * ET:   Entry type field.  Must be 1 for a PTD.
- */
-
-#define SRMMU_PTD_PTP_SHIFT         0x2
-#define SRMMU_PTD_PTP_MASK          0xfffffffc
-#define SRMMU_PTD_PTP_PADDR_SHIFT   0x4
-#define SRMMU_PTD_ET_SHIFT          0x0
-#define SRMMU_PTD_ET_MASK           0x00000003
-
-/* Page table entry bits.
- *
- * -------------------------------------------------
- * |  Physical Page Number  | C | M | R | ACC | ET |
- * -------------------------------------------------
- * 31                     8   7   6   5  4   2  1  0
- *
- * PPN: Physical page number, high order 24 bits of the 36-bit
- *      physical address, thus is you mask off all the non
- *      PPN bits you have the physical address of your page.
- *      No shifting necessary.
- *
- * C:   Whether the page is cacheable in the mmu TLB or not.  If
- *      not set the CPU cannot cache values to these addresses. For
- *      IO space translations this bit should be clear.
- *
- * M:   Modified.  This tells whether the page has been written to
- *      since the bit was last cleared.  NOTE: this does not include
- *      accesses via the ASI physical page pass through since that does
- *      not use the MMU.
- *
- * R:   References.  This tells whether the page has been referenced
- *      in any way shape or form since the last clearing of the bit.
- *      NOTE: this does not include accesses via the ASI physical page
- *      pass through since that does not use the MMU.
- *
- * ACC: Access permissions for this page.  This is further explained below
- *      with appropriate macros.
- */
-
-#define SRMMU_PTE_PPN_SHIFT         0x8
-#define SRMMU_PTE_PPN_MASK          0xffffff00
-#define SRMMU_PTE_PPN_PADDR_SHIFT   0x4
-#define SRMMU_PTE_C_SHIFT           0x7
-#define SRMMU_PTE_C_MASK            0x00000080
-#define SRMMU_PTE_M_SHIFT           0x6
-#define SRMMU_PTE_M_MASK            0x00000040
-#define SRMMU_PTE_R_SHIFT           0x5
-#define SRMMU_PTE_R_MASK            0x00000020
-#define SRMMU_PTE_ACC_SHIFT         0x2
-#define SRMMU_PTE_ACC_MASK          0x0000001c
-#define SRMMU_PTE_ET_SHIFT          0x0
-#define SRMMU_PTE_ET_MASK           0x00000003
-
-/* SRMMU pte access bits.
- *
- * BIT    USER ACCESS          SUPERVISOR ACCESS
- * ---    --------------       -----------------
- * 0x0    read only            read only
- * 0x1    read&write           read&write
- * 0x2    read&execute         read&execute
- * 0x3    read&write&execute   read&write&execute
- * 0x4    execute only         execute only
- * 0x5    read only            read&write
- * 0x6    ACCESS DENIED        read&execute
- * 0x7    ACCESS DENIED        read&write&execute
- *
- * All these values are shifted left two bits.
- */
-
-#define SRMMU_ACC_US_RDONLY      0x00
-#define SRMMU_ACC_US_RDWR        0x04
-#define SRMMU_ACC_US_RDEXEC      0x08
-#define SRMMU_ACC_US_RDWREXEC    0x0c
-#define SRMMU_ACC_US_EXECONLY    0x10
-#define SRMMU_ACC_U_RDONLY       0x14
-#define SRMMU_ACC_S_RDWR         0x14
-#define SRMMU_ACC_U_ACCDENIED    0x18
-#define SRMMU_ACC_S_RDEXEC       0x18
-#define SRMMU_ACC_U_ACCDENIED2   0x1c
-#define SRMMU_ACC_S_RDWREXEC     0x1c
-
-#ifndef __ASSEMBLY__
-
-/* SUN4C pte, segmap, and context manipulation */
-extern __inline__ unsigned long get_segmap(unsigned long addr)
-{
-  register unsigned long entry;
-
-  __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : 
-                      "=r" (entry) :
-                      "r" (addr), "i" (ASI_SEGMAP));
-
-  return entry;
-}
-
-extern __inline__ void put_segmap(unsigned long addr, unsigned long entry)
-{
-
-  __asm__ __volatile__("\n\tstba %1, [%0] %2\n\t" : :
-                      "r" (addr), "r" (entry),
-                      "i" (ASI_SEGMAP));
-
-  return;
-}
-
-extern __inline__ unsigned long get_pte(unsigned long addr)
-{
-  register unsigned long entry;
-
-  __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : 
-                      "=r" (entry) :
-                      "r" (addr), "i" (ASI_PTE));
-  return entry;
-}
-
-extern __inline__ void put_pte(unsigned long addr, unsigned long entry)
-{
-  __asm__ __volatile__("\n\tsta %1, [%0] %2\n\t" : :
-                      "r" (addr), 
-                      "r" (entry), "i" (ASI_PTE));
-
-  return;
-}
-
-extern void (*switch_to_context)(void *tsk);
-
-extern __inline__ int get_context(void)
-{
-  register int ctx;
-
-  __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" :
-                      "=r" (ctx) :
-                      "r" (AC_CONTEXT), "i" (ASI_CONTROL));
-
-  return ctx;
-}
-
-extern __inline__ int set_context(int ctx)
-{
-  __asm__ __volatile__("\n\tstba %0, [%1] %2\n\t" : :
-                      "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL));
-
-  return ctx;
-}
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC_PAGE_H */
index 8679fea9e8fbd89393404e9b160a03f8d60f820a..1f93306bb173a3f5ae7ffc7db9e1b0c5ff8418f1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.25 1995/11/25 02:32:22 davem Exp $ */
+/* $Id: pgtable.h,v 1.35 1996/02/21 17:57:30 miguel Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
 #include <asm/pgtsrmmu.h>
 #include <asm/vac-ops.h>
 #include <asm/oplib.h>
+#include <asm/sbus.h>
 
 extern void load_mmu(void);
 
+extern void (*quick_kernel_fault)(unsigned long);
+
 /* mmu-specific process creation/cloning/etc hooks. */
-extern void (*mmu_exit_hook)(void *);
-extern void (*mmu_fork_hook)(void *, unsigned long);
-extern void (*mmu_release_hook)(void *);
-extern void (*mmu_flush_hook)(void *);
-extern void (*mmu_task_cacheflush)(void *);
+extern void (*mmu_exit_hook)(void);
+extern void (*mmu_flush_hook)(void);
 
 /* Routines for data transfer buffers. */
 extern char *(*mmu_lockarea)(char *, unsigned long);
 extern void  (*mmu_unlockarea)(char *, unsigned long);
 
 /* Routines for getting a dvma scsi buffer. */
-extern char *(*mmu_get_scsi_buffer)(char *, unsigned long);
-extern void  (*mmu_release_scsi_buffer)(char *, unsigned long);
+extern char *(*mmu_get_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus);
+extern void  (*mmu_release_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus);
 
 extern unsigned int pmd_shift;
 extern unsigned int pmd_size;
@@ -58,7 +58,6 @@ extern pgprot_t page_shared;
 extern pgprot_t page_copy;
 extern pgprot_t page_readonly;
 extern pgprot_t page_kernel;
-extern pgprot_t page_invalid;
 
 #define PMD_SHIFT      (pmd_shift)
 #define PMD_SIZE       (pmd_size)
@@ -127,11 +126,11 @@ extern int num_contexts;
 extern pte_t __bad_page(void);
 extern pte_t * __bad_pagetable(void);
 
-extern unsigned long __zero_page(void);
+extern unsigned long empty_zero_page;
 
 #define BAD_PAGETABLE __bad_pagetable()
 #define BAD_PAGE __bad_page()
-#define ZERO_PAGE __zero_page()
+#define ZERO_PAGE (&empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR      (8*sizeof(unsigned long))
@@ -145,17 +144,6 @@ extern unsigned long (*pte_page)(pte_t);
 extern unsigned long (*pmd_page)(pmd_t);
 extern unsigned long (*pgd_page)(pgd_t);
 
-/* to set the page-dir
- *
- * On the Sparc the page segments hold 64 pte's which means 256k/segment.
- * Therefore there is no global idea of 'the' page directory, although we
- * make a virtual one in kernel memory so that we can keep the stats on
- * all the pages since not all can be loaded at once in the mmu.
- *
- * Actually on the SRMMU things do work exactly like the i386, the
- * page tables live in real physical ram, no funky TLB buisness.
- */
-
 extern void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
 
 #define SET_PAGE_DIR(tsk,pgdir) sparc_update_rootmmu_dir(tsk, pgdir)
@@ -190,31 +178,23 @@ extern void (*pgd_reuse)(pgd_t *);
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern int (*pte_read)(pte_t);
 extern int (*pte_write)(pte_t);
-extern int (*pte_exec)(pte_t);
 extern int (*pte_dirty)(pte_t);
 extern int (*pte_young)(pte_t);
-extern int (*pte_cow)(pte_t);
 
 extern pte_t (*pte_wrprotect)(pte_t);
-extern pte_t (*pte_rdprotect)(pte_t);
-extern pte_t (*pte_exprotect)(pte_t);
 extern pte_t (*pte_mkclean)(pte_t);
 extern pte_t (*pte_mkold)(pte_t);
-extern pte_t (*pte_uncow)(pte_t);
 extern pte_t (*pte_mkwrite)(pte_t);
-extern pte_t (*pte_mkread)(pte_t);
-extern pte_t (*pte_mkexec)(pte_t);
 extern pte_t (*pte_mkdirty)(pte_t);
 extern pte_t (*pte_mkyoung)(pte_t);
-extern pte_t (*pte_mkcow)(pte_t);
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
 extern pte_t (*mk_pte)(unsigned long, pgprot_t);
+extern pte_t (*mk_pte_io)(unsigned long, pgprot_t);
 
 extern void (*pgd_set)(pgd_t *, pmd_t *);
 
@@ -262,30 +242,51 @@ extern void (*pgd_free)(pgd_t *);
 
 extern pgd_t * (*pgd_alloc)(void);
 
+/* Fine grained invalidation. */
+extern void (*invalidate_all)(void);
+extern void (*invalidate_mm)(struct mm_struct *);
+extern void (*invalidate_range)(struct mm_struct *, unsigned long start, unsigned long end);
+extern void (*invalidate_page)(struct vm_area_struct *, unsigned long address);
+
+/* The permissions for pgprot_val to make a page mapped on the obio space */
+extern unsigned int pg_iobits;
+
+/* MMU context switching. */
+extern void (*switch_to_context)(struct task_struct *tsk);
+
+/* Certain architectures need to do special things when pte's
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+extern void (*set_pte)(pte_t *pteptr, pte_t pteval);
+
+extern char *(*mmu_info)(void);
+
 /* Fault handler stuff... */
 #define FAULT_CODE_PROT     0x1
 #define FAULT_CODE_WRITE    0x2
 #define FAULT_CODE_USER     0x4
-extern int (*get_fault_info)(unsigned long *, unsigned long *, unsigned long);
 extern void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long address, pte_t pte);
 
 extern int invalid_segment;
 
-#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
-#define SWP_OFFSET(entry) ((entry) >> 8)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
+#define SWP_TYPE(entry) (((entry)>>2) & 0x7f)
+#define SWP_OFFSET(entry) ((entry) >> 9)
+#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
 
 struct ctx_list {
        struct ctx_list *next;
        struct ctx_list *prev;
        unsigned char ctx_number;
-       struct task_struct *ctx_task; /* Who has it now, if not free */
+       struct mm_struct *ctx_mm;
 };
 
 extern struct ctx_list *ctx_list_pool;  /* Dynamically allocated */
 extern struct ctx_list ctx_free;        /* Head of free list */
 extern struct ctx_list ctx_used;        /* Head of used contexts list */
 
+#define NO_CONTEXT     -1
+
 extern inline void remove_from_ctx_list(struct ctx_list *entry)
 {
        entry->next->prev = entry->prev;
index 1a277c1e94d7451c4abe7609fe8b474d1f401dc2..a3c86e7c76618ff73f9a153f4dc80aea31e0613c 100644 (file)
@@ -1,23 +1,19 @@
-/* $Id: pgtsrmmu.h,v 1.9 1995/11/25 02:32:24 davem Exp $
+/* $Id: pgtsrmmu.h,v 1.13 1996/03/01 07:20:54 davem Exp $
  * pgtsrmmu.h:  SRMMU page table defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <asm/page.h>  /* just in case */
-
 #ifndef _SPARC_PGTSRMMU_H
 #define _SPARC_PGTSRMMU_H
 
-#define SRMMU_PAGE_TABLE_SIZE 0x100 /* 64 entries, 4 bytes a piece */
-#define SRMMU_PMD_TABLE_SIZE  0x100 /* 64 entries, 4 bytes a piece */
-#define SRMMU_PGD_TABLE_SIZE  0x400 /* 256 entries, 4 bytes a piece */
+#include <asm/page.h>
 
 /* PMD_SHIFT determines the size of the area a second-level page table can map */
-#define SRMMU_PMD_SHIFT       18
-#define SRMMU_PMD_SIZE        (1UL << SRMMU_PMD_SHIFT)
-#define SRMMU_PMD_MASK        (~(SRMMU_PMD_SIZE-1))
-#define SRMMU_PMD_ALIGN(addr) (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK)
+#define SRMMU_PMD_SHIFT         18
+#define SRMMU_PMD_SIZE          (1UL << SRMMU_PMD_SHIFT)
+#define SRMMU_PMD_MASK          (~(SRMMU_PMD_SIZE-1))
+#define SRMMU_PMD_ALIGN(addr)   (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK)
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
 #define SRMMU_PGDIR_SHIFT       24
 #define SRMMU_PGDIR_MASK        (~(SRMMU_PGDIR_SIZE-1))
 #define SRMMU_PGDIR_ALIGN(addr) (((addr)+SRMMU_PGDIR_SIZE-1)&SRMMU_PGDIR_MASK)
 
-/*
- * Three-level on SRMMU.
- */
-
-#define SRMMU_PTRS_PER_PTE    64
-#define SRMMU_PTRS_PER_PMD    64
-#define SRMMU_PTRS_PER_PGD    256
-
-/* Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
+#define SRMMU_PTRS_PER_PTE      64
+#define SRMMU_PTRS_PER_PMD      64
+#define SRMMU_PTRS_PER_PGD      256
+
+#define SRMMU_PTE_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */
+#define SRMMU_PMD_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */
+#define SRMMU_PGD_TABLE_SIZE    0x400 /* 256 entries, 4 bytes a piece */
+
+#define SRMMU_VMALLOC_START   (0xfe100000)
+
+/* Definition of the values in the ET field of PTD's and PTE's */
+#define SRMMU_ET_MASK         0x3
+#define SRMMU_ET_INVALID      0x0
+#define SRMMU_ET_PTD          0x1
+#define SRMMU_ET_PTE          0x2
+#define SRMMU_ET_REPTE        0x3 /* AIEEE, SuperSparc II reverse endian page! */
+
+/* Physical page extraction from PTP's and PTE's. */
+#define SRMMU_CTX_PMASK    0xfffffff0
+#define SRMMU_PTD_PMASK    0xfffffff0
+#define SRMMU_PTE_PMASK    0xffffff00
+
+/* The pte non-page bits.  Some notes:
+ * 1) cache, dirty, valid, and ref are frobbable
+ *    for both supervisor and user pages.
+ * 2) exec and write will only give the desired effect
+ *    on user pages
+ * 3) use priv and priv_readonly for changing the
+ *    characteristics of supervisor ptes
  */
-#define SRMMU_VMALLOC_OFFSET  (8*1024*1024)
-#define SRMMU_VMALLOC_START ((high_memory + SRMMU_VMALLOC_OFFSET) & ~(SRMMU_VMALLOC_OFFSET-1))
-
-/*
- * Sparc SRMMU page table fields.
+#define SRMMU_CACHE        0x80
+#define SRMMU_DIRTY        0x40
+#define SRMMU_REF          0x20
+#define SRMMU_EXEC         0x08
+#define SRMMU_WRITE        0x04
+#define SRMMU_VALID        0x02 /* SRMMU_ET_PTE */
+#define SRMMU_PRIV         0x1c
+#define SRMMU_PRIV_RDONLY  0x18
+
+#define SRMMU_CHG_MASK    (SRMMU_REF | SRMMU_DIRTY | SRMMU_ET_PTE)
+
+/* Some day I will implement true fine grained access bits for
+ * user pages because the SRMMU gives us the capabilities to
+ * enforce all the protection levels that vma's can have.
+ * XXX But for now...
  */
-
-#define _SRMMU_PAGE_VALID      (SRMMU_ET_PTE)
-#define _SRMMU_PMD_VALID       (SRMMU_ET_PTD)
-#define _SRMMU_PGD_VALID       (SRMMU_ET_PTD)
-#define _SRMMU_PAGE_WRITE_USR  (SRMMU_ACC_US_RDWR)
-#define _SRMMU_PAGE_WRITE_KERN (SRMMU_ACC_S_RDWR)
-#define _SRMMU_PAGE_EXEC       (SRMMU_ACC_US_RDEXEC)
-#define _SRMMU_PAGE_RDONLY     (SRMMU_ACC_US_RDONLY)
-#define _SRMMU_PAGE_NOREAD     (SRMMU_ACC_U_ACCDENIED)
-#define _SRMMU_PAGE_NOCACHE    (~SRMMU_PTE_C_MASK)
-#define _SRMMU_PAGE_PRIV       (SRMMU_ACC_S_RDWREXEC)
-#define _SRMMU_PAGE_REF        (SRMMU_PTE_R_MASK)
-#define _SRMMU_PAGE_DIRTY      (SRMMU_PTE_M_MASK)
-#define _SRMMU_PAGE_COW        (SRMMU_ACC_U_RDONLY)
-#define _SRMMU_PAGE_UNCOW      (SRMMU_ACC_US_RDWR)
-
-/* We want the swapper not to swap out page tables, thus dirty and writable
- * so that the kernel can change the entries as needed. Also valid for
- * obvious reasons.
+#define SRMMU_PAGE_NONE    __pgprot(SRMMU_VALID | SRMMU_CACHE | \
+                                   SRMMU_PRIV | SRMMU_REF)
+#define SRMMU_PAGE_SHARED  __pgprot(SRMMU_VALID | SRMMU_CACHE | \
+                                   SRMMU_EXEC | SRMMU_WRITE | SRMMU_REF)
+#define SRMMU_PAGE_COPY    __pgprot(SRMMU_VALID | SRMMU_CACHE | \
+                                   SRMMU_EXEC | SRMMU_REF)
+#define SRMMU_PAGE_RDONLY  __pgprot(SRMMU_VALID | SRMMU_CACHE | \
+                                   SRMMU_EXEC | SRMMU_REF)
+#define SRMMU_PAGE_KERNEL  __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_PRIV)
+
+/* SRMMU Register addresses in ASI 0x4.  These are valid for all
+ * current SRMMU implementations that exist.
  */
-#define _SRMMU_PAGE_TABLE     (_SRMMU_PAGE_VALID | _SRMMU_PAGE_WRITE_KERN | _SRMMU_PAGE_REF | _SRMMU_PAGE_DIRTY)
-#define _SRMMU_PAGE_CHG_MASK  (_SRMMU_PAGE_REF | _SRMMU_PAGE_DIRTY | SRMMU_ET_PTE)
-#define _SRMMU_PMD_CHG_MASK   (SRMMU_ET_PTD)
-#define _SRMMU_PGD_CHG_MASK   (SRMMU_ET_PTD)
-
-#define SRMMU_PAGE_NONE       __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF)
-#define SRMMU_PAGE_SHARED     __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_WRITE_USR | _SRMMU_PAGE_REF)
-#define SRMMU_PAGE_COPY       __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | _SRMMU_PAGE_COW)
-#define SRMMU_PAGE_READONLY   __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | SRMMU_ACC_US_RDONLY)
-#define SRMMU_PAGE_KERNEL     __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_PRIV | SRMMU_PTE_C_MASK)
-#define SRMMU_PAGE_INVALID    __pgprot(SRMMU_ET_INVALID)
-
-#define _SRMMU_PAGE_NORMAL(x) __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | (x))
-
-/* SRMMU Register addresses */
 #define SRMMU_CTRL_REG           0x00000000
 #define SRMMU_CTXTBL_PTR         0x00000100
 #define SRMMU_CTX_REG            0x00000200
 #define SRMMU_FAULT_STATUS       0x00000300
 #define SRMMU_FAULT_ADDR         0x00000400
-#define SRMMU_AFAULT_STATUS      0x00000500
-#define SRMMU_AFAULT_ADDR        0x00000600
-
-/* The SRMMU control register fields:
- * -------------------------------------------------------------------
- * | IMPL  |  VERS  |    SysControl | PSO | Resv | No Fault | Enable |
- * -------------------------------------------------------------------
- * 31    28 27    24 23            8   7    6   2      1        0
- *
- * IMPL:  Indicates the implementation of this SRMMU, read-only.
- * VERS:  The version of this implementation, again read-only.
- * SysControl:  This is an implementation specific field, the SRMMU
- *              specification does not define anything for this field.
- * PSO: This determines whether the memory model as seen by the CPU
- *      is Partial Store Order (PSO=1) or Total Store Ordering (PSO=0).
- * Resv: Don't touch these bits ;)
- * No Fault: If zero, any fault acts as expected where the fault status
- *           and address registers are updated and a trap hits the CPU.
- *           When this bit is one, on any fault other than in ASI 9, the
- *           MMU updates the status and address fault registers but does
- *           not signal the CPU with a trap.  This is useful to beat
- *           race conditions in low-level code when we have to throw
- *           a register window onto the stack in a spill/fill handler
- *           on multiprocessors.
- * Enable: If one the MMU is doing translations, if zero the addresses
- *         given to the bus are pure physical.
- */
 
-#define SRMMU_CTREG_IMPL_MASK        0xf0000000
-#define SRMMU_CTREG_IMPL_SHIFT       28
-#define SRMMU_CTREG_VERS_MASK        0x0f000000
-#define SRMMU_CTREG_VERS_SHIFT       24
-#define SRMMU_CTREG_SYSCNTRL_MASK    0x00ffff00
-#define SRMMU_CTREG_SYSCNTRL_SHIFT   8
-#define SRMMU_CTREG_PSO_MASK         0x00000080
-#define SRMMU_CTREG_PSO_SHIFT        7
-#define SRMMU_CTREG_RESV_MASK        0x0000007c
-#define SRMMU_CTREG_RESV_SHIFT       2
-#define SRMMU_CTREG_NOFAULT_MASK     0x00000002
-#define SRMMU_CTREG_NOFAULT_SHIFT    1
-#define SRMMU_CTREG_ENABLE_MASK      0x00000001
-#define SRMMU_CTREG_ENABLE_SHIFT     0
-
-/* Get the MMU control register */
+/* Accessing the MMU control register. */
 extern inline unsigned int srmmu_get_mmureg(void)
 {
-        register unsigned int retval;
+        unsigned int retval;
        __asm__ __volatile__("lda [%%g0] %1, %0\n\t" :
                             "=r" (retval) :
                             "i" (ASI_M_MMUREGS));
        return retval;
 }
 
-/* Set the MMU control register */
 extern inline void srmmu_set_mmureg(unsigned long regval)
 {
        __asm__ __volatile__("sta %0, [%%g0] %1\n\t" : :
                             "r" (regval), "i" (ASI_M_MMUREGS) : "memory");
 
-       return;
 }
 
-/* The SRMMU Context Table Pointer Register:
- * ---------------------------------
- * |  Context Table Pointer | Resv |
- * ---------------------------------
- * 31                      2 1    0
- *
- * This is where the MMU goes to in physical RAM to fetch the
- * elements in the context table.  The non-Resv bits of this
- * address appear in bits 6-35 of the physical bus during miss
- * processing, then indexed by the value in the Context Register.
- * This table must be aligned on a boundary equal to the size of
- * the table, we provide a nice macro for doing this based upon
- * the significant bits in the context register.
- */
-#define SRMMU_CTP_ADDR_MASK          0xfffffffc
-#define SRMMU_CTP_ADDR_PADDR_SHIFT   0x4
-#define SRMMU_CTP_RESV_MASK          0x00000003
-
-#define SRMMU_SIGBITS_TO_ALIGNMENT(numbits)  ((1 << (numbits + 2)))
-
-
-/* Set the address of the context table.  You pass this routine
- * the physical address, we do the magic shifting for you.
- */
 extern inline void srmmu_set_ctable_ptr(unsigned long paddr)
 {
-       unsigned long ctp;
-
-       ctp = (paddr >> SRMMU_CTP_ADDR_PADDR_SHIFT);
-       ctp &= SRMMU_CTP_ADDR_MASK;
-
+       paddr = ((paddr >> 4) & SRMMU_CTX_PMASK);
        __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
-                            "r" (ctp), "r" (SRMMU_CTXTBL_PTR),
+                            "r" (paddr), "r" (SRMMU_CTXTBL_PTR),
                             "i" (ASI_M_MMUREGS) :
                             "memory");
-       return;
 }
 
-
-/* Get the address of the context table.  We return the physical
- * address of the table, again we do the shifting here.
- */
 extern inline unsigned long srmmu_get_ctable_ptr(void)
 {
-       register unsigned int retval;
+       unsigned int retval;
 
        __asm__ __volatile__("lda [%1] %2, %0\n\t" :
                             "=r" (retval) :
                             "r" (SRMMU_CTXTBL_PTR),
                             "i" (ASI_M_MMUREGS));
-
-       retval &= SRMMU_CTP_ADDR_MASK;
-       retval = (retval << SRMMU_CTP_ADDR_PADDR_SHIFT);
-       return retval;
+       return (retval & SRMMU_CTX_PMASK) << 4;
 }
 
-/* Set the context on an SRMMU */
 extern inline void srmmu_set_context(int context)
 {
        __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
                             "r" (context), "r" (SRMMU_CTX_REG),
                             "i" (ASI_M_MMUREGS) : "memory");
-       return;
 }
 
-/* Get the context on an SRMMU */
 extern inline int srmmu_get_context(void)
 {
        register int retval;
@@ -224,122 +140,9 @@ extern inline int srmmu_get_context(void)
        return retval;
 }
 
-/* SRMMU diagnostic register:
- * --------------------------------------------------------
- * |   Virtual Address   |   PDC entry   | DiagReg | Resv |
- * --------------------------------------------------------
- * 31                  12 11            4 3       2 1    0
- *
- * An SRMMU implementation has the choice of providing this register
- * and I don't know much about it.
- */
-
-#define SRMMU_DIAG_VADDR_MASK        0xfffff000
-#define SRMMU_DIAG_PDC_MASK          0x00000ff0
-#define SRMMU_DIAG_REG_MASK          0x0000000c
-#define SRMMU_DIAG_RESV_MASK         0x00000003
-
-/* SRMMU Fault Status Register:
- * -----------------------------------------------------------
- * | Reserved          | EBE  |  L  |  AT  |  FT  | FAV | OW |
- * -----------------------------------------------------------
- *  31               18 17  10  9  8 7    5  4   2   1     0
- *
- * WARNING!!! On certain VERY BROKEN Viking Sun4d modules this register
- * is complete TOAST!  During a fault you cannot trust the values
- * contained in this register, you must calculate them yourself
- * by first using the trap program counter to decode the
- * instruction the code tried to execute (ie. load or store) and
- * the address they tried to access.  I think the Fault Virtual
- * Address register may be ok on these chips, but who knows. Grrr.
- *
- * Reserved:  These bits must be zero.
- * EBE: External bus error bits, implementation dependant (at least
- *      we know what the bits mean on sun4d Viking modules) ;)
- * L: The level in tree traversal at which the fault occured. The
- *    values are... 0 = context table
- *                  1 = level-1 page table
- *                  2 = level-2 page table
- *                  3 = level-3 page table
- * AT: Access type field. This is decoded as follows...
- *     0 -- Load from user data space
- *     1 -- Load from supervisor data space
- *     2 -- Read/Execute from user instruction space
- *     3 -- Read/Execute from supervisor instruction space
- *     4 -- Store to user data space
- *     5 -- Store to supervisor data space
- *     6 -- Store to user instruction space
- *     7 -- Store to supervisor instruction space (emacs does this)
- *     On the Viking --  TOAST!
- * FT:  This is the fault type field.  It is used to determine what was
- *      wrong in the attempted translation. It can be one of...
- *     0 -- None
- *     1 -- Invalid address error
- *     2 -- Protection violation error
- *     3 -- Priviledge violation error
- *     4 -- Translation error (your tables are fucked up)
- *     5 -- Bus access error (you lose)
- *     6 -- Internal error (might as well have a Viking)
- *     7 -- Reserved (don't touch)
- * FAV: Fault Address Valid bit.  When set to one the fault address
- *      register contents are valid.  It need not be valid for text
- *      faults as the trapped PC tells us this anyway.
- * OW: The Overwrite Bit, if set to one, this register has been
- *     written to more than once by the hardware since software did
- *     a read.  This mean multiple faults have occurred and you have
- *     to a manual page table tree traversal to continue the handling
- *     of the first fault. And on the Viking module....
- *
- * The Fault Address Register is just a 32-bit register representing the
- * virtual address which caused the fault.  It's validity is determined
- * by the following equation:
- * if(module==VIKING || FSR.FAV==0) forget_it();
- * It's ok for the FAV to be invalid for a text fault because we can
- * use the trapped program counter, however for a data fault we are SOL.
- * I'll probably have to write a workaround for this situation too ;-(
- */
-
-#define SRMMU_FSR_RESV_MASK      0xfffc0000  /* Reserved bits */
-#define SRMMU_FSR_EBE_MASK       0x0003fc00  /* External Bus Error bits */
-#define SRMMU_FSR_EBE_BERR       0x00000400  /* Bus Error */
-#define SRMMU_FSR_EBE_BTIMEO     0x00000800  /* Bus Time Out */
-#define SRMMU_FSR_EBE_UNCOR      0x00001000  /* Uncorrectable Error */
-#define SRMMU_FSR_EBE_UNDEF      0x00002000  /* Undefined Error */
-#define SRMMU_FSR_EBE_PARITY     0x00004000  /* Parity error */
-#define SRMMU_FSR_EBE_TPARITY    0x00006000  /* Tsunami parity error */
-#define SRMMU_FSR_EBE_SBUF       0x00008000  /* Store Buffer error */
-#define SRMMU_FSR_EBE_CSA        0x00010000  /* Control space access error (bad ASI) */
-#define SRMMU_FSR_EBE_EMRT       0x00020000  /* Viking Emergency Response Team */
-#define SRMMU_FSR_L_MASK         0x00000300  /* Fault level bits */
-#define SRMMU_FSR_L_CTABLE       0x00000000  /* Context table level flt/err */
-#define SRMMU_FSR_L_ONE          0x00000100  /* Level1 ptable flt/err */
-#define SRMMU_FSR_L_TWO          0x00000200  /* Level2 ptable flt/err */
-#define SRMMU_FSR_L_THREE        0x00000300  /* Level3 ptable flt/err */
-#define SRMMU_FSR_AT_MASK        0x000000e0  /* Access Type bits */
-#define SRMMU_FSR_AT_LUD         0x00000000  /* Load from User Data space */
-#define SRMMU_FSR_AT_LSD         0x00000020  /* What I'll need after writing this code */
-#define SRMMU_FSR_AT_RXUI        0x00000040  /* Read/Execute from user text */
-#define SRMMU_FSR_AT_RXSI        0x00000060  /* Read/Execute from supv text */
-#define SRMMU_FSR_AT_SUD         0x00000080  /* Store to user data space */
-#define SRMMU_FSR_AT_SSD         0x000000a0  /* Store to supv data space */
-#define SRMMU_FSR_AT_SUI         0x000000c0  /* Store to user text */
-#define SRMMU_FSR_AT_SSI         0x000000e0  /* Store to supv text */
-#define SRMMU_FSR_FT_MASK        0x0000001c  /* Fault Type bits */
-#define SRMMU_FSR_FT_NONE        0x00000000  /* No fault occurred */
-#define SRMMU_FSR_FT_IADDR       0x00000002  /* Invalid address */
-#define SRMMU_FSR_FT_PROT        0x00000004  /* Protection violation */
-#define SRMMU_FSR_FT_PRIV        0x00000008  /* Privilege violation */
-#define SRMMU_FSR_FT_TRANS       0x0000000a  /* Translation error */
-#define SRMMU_FSR_FT_BACC        0x0000000c  /* Bus Access error */
-#define SRMMU_FSR_FT_IACC        0x0000000e  /* Internal error */
-#define SRMMU_FSR_FT_RESV        0x00000010  /* Reserved, should not get this */
-#define SRMMU_FSR_FAV_MASK       0x00000002  /* Fault Address Valid bits */
-#define SRMMU_FSR_OW_MASK        0x00000001  /* SFSR OverWritten bits */
-
-/* Read the Fault Status Register on the SRMMU */
 extern inline unsigned int srmmu_get_fstatus(void)
 {
-       register unsigned int retval;
+       unsigned int retval;
 
        __asm__ __volatile__("lda [%1] %2, %0\n\t" :
                             "=r" (retval) :
@@ -347,10 +150,9 @@ extern inline unsigned int srmmu_get_fstatus(void)
        return retval;
 }
 
-/* Read the Fault Address Register on the SRMMU */
 extern inline unsigned int srmmu_get_faddr(void)
 {
-       register unsigned int retval;
+       unsigned int retval;
 
        __asm__ __volatile__("lda [%1] %2, %0\n\t" :
                             "=r" (retval) :
@@ -358,59 +160,52 @@ extern inline unsigned int srmmu_get_faddr(void)
        return retval;
 }
 
-/* SRMMU Asynchronous Fault Status Register:
- * -----------------------------------------
- * |  RESERVED |UCE|BTO|BERR|RSV|HFADDR|AFO|
- * -----------------------------------------
- *  31       13  12  11  10  9-8  7-4     0
- *
- * UCE: UnCorrectable Error
- * BTO: Bus TimeOut
- * BERR: Genreic Bus Error
- * HFADDR: High 4 bits of the faulting address
- * AFO: Asynchronous Fault Occurred
- */
-#define SRMMU_AFSR_RESVMASK  0xffffe000
-#define SRMMU_AFSR_UCE       0x00001000
-#define SRMMU_AFSR_BTO       0x00000800
-#define SRMMU_AFSR_BERR      0x00000400
-#define SRMMU_AFSR_HFADDR    0x000000f0
-#define SRMMU_AFSR_AFO       0x00000001
-
-/* Read the asynchronous fault register */
-extern inline unsigned int srmmu_get_afstatus(void)
+/* This is guarenteed on all SRMMU's. */
+extern inline void srmmu_flush_whole_tlb(void)
 {
-       register unsigned int retval;
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+                            "r" (0x400),        /* Flush entire TLB!! */
+                            "i" (ASI_M_FLUSH_PROBE) : "memory");
 
-       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
-                            "=r" (retval) :
-                            "r" (SRMMU_AFAULT_STATUS), "i" (ASI_M_MMUREGS));
-       return retval;
 }
 
-/* Read the Asynchronous Fault Address Register on the SRMMU */
-extern inline unsigned int srmmu_get_afaddr(void)
+/* These flush types are not available on all chips... */
+extern inline void srmmu_flush_tlb_ctx(void)
 {
-       register unsigned int retval;
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+                            "r" (0x300),        /* Flush TLB ctx.. */
+                            "i" (ASI_M_FLUSH_PROBE) : "memory");
 
-       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
-                            "=r" (retval) :
-                            "r" (SRMMU_AFAULT_ADDR), "i" (ASI_M_MMUREGS));
-       return retval;
 }
 
+extern inline void srmmu_flush_tlb_region(unsigned long addr)
+{
+       addr &= SRMMU_PGDIR_MASK;
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+                            "r" (addr | 0x200), /* Flush TLB region.. */
+                            "i" (ASI_M_FLUSH_PROBE) : "memory");
 
-/* Flush the entire TLB cache on the SRMMU. */
-extern inline void srmmu_flush_whole_tlb(void)
+}
+
+
+extern inline void srmmu_flush_tlb_segment(unsigned long addr)
 {
+       addr &= SRMMU_PMD_MASK;
        __asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
-                            "r" (0x400),        /* Flush entire TLB!! */
+                            "r" (addr | 0x100), /* Flush TLB segment.. */
+                            "i" (ASI_M_FLUSH_PROBE) : "memory");
+
+}
+
+extern inline void srmmu_flush_tlb_page(unsigned long page)
+{
+       page &= PAGE_MASK;
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+                            "r" (page),        /* Flush TLB page.. */
                             "i" (ASI_M_FLUSH_PROBE) : "memory");
 
-       return;
 }
 
-/* Probe for an entry in the page-tables of the SRMMU. */
 extern inline unsigned long srmmu_hwprobe(unsigned long vaddr)
 {
        unsigned long retval;
@@ -422,4 +217,7 @@ extern inline unsigned long srmmu_hwprobe(unsigned long vaddr)
        return retval;
 }
 
+extern unsigned long (*srmmu_read_physical)(unsigned long paddr);
+extern void (*srmmu_write_physical)(unsigned long paddr, unsigned long word);
+
 #endif /* !(_SPARC_PGTSRMMU_H) */
index 408f512df4ece7ed278ac3c5c2c0ecdf88e29c10..d9e001ca1289f1fb0e7458ba49ce9c0221907ccf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtsun4c.h,v 1.16 1995/11/25 02:32:28 davem Exp $
+/* $Id: pgtsun4c.h,v 1.22 1996/01/24 02:33:45 davem Exp $
  * pgtsun4c.h:  Sun4c specific pgtable.h defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -19,7 +19,7 @@
 #define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK)
 
 /* To represent how the sun4c mmu really lays things out. */
-#define SUN4C_REAL_PGDIR_SHIFT  18
+#define SUN4C_REAL_PGDIR_SHIFT       18
 #define SUN4C_REAL_PGDIR_SIZE        (1UL << SUN4C_REAL_PGDIR_SHIFT)
 #define SUN4C_REAL_PGDIR_MASK        (~(SUN4C_REAL_PGDIR_SIZE-1))
 #define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK)
 #define _SUN4C_PAGE_IO        0x04000000   /* I/O page */
 #define _SUN4C_PAGE_REF       0x02000000   /* Page has been accessed/referenced */
 #define _SUN4C_PAGE_DIRTY     0x01000000   /* Page has been modified, is dirty */
-#define _SUN4C_PAGE_COW       0x00800000   /* COW page */
 
-/* Note that the 'non-cacheable' bit is not set in any of these settings,
- * you may want to turn it on for debugging the flushing of the virtual
- * cache on the SUN4C MMU.
- */
 #define _SUN4C_PAGE_CHG_MASK  (0xffff | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY)
 
 #define SUN4C_PAGE_NONE     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_PRIV | \
 #define SUN4C_PAGE_SHARED   __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | \
                                     _SUN4C_PAGE_USER | _SUN4C_PAGE_REF)
 #define SUN4C_PAGE_COPY     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_USER | \
-                                    _SUN4C_PAGE_REF | _SUN4C_PAGE_COW)
+                                    _SUN4C_PAGE_REF)
 #define SUN4C_PAGE_READONLY __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_USER | \
                                     _SUN4C_PAGE_REF)
 #define SUN4C_PAGE_KERNEL   __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | \
                                     _SUN4C_PAGE_PRIV | _SUN4C_PAGE_DIRTY | \
-                                    _SUN4C_PAGE_REF)
-#define SUN4C_PAGE_INVALID  __pgprot(0)
-
-struct pseg_list {
-       struct pseg_list *next;
-       struct pseg_list *prev;
-       struct pseg_list *ctx_next;
-       struct pseg_list *ctx_prev;
-       unsigned long vaddr;    /* Where the pseg is mapped. */
-       unsigned char context;  /* The context in which it is mapped. */
-       unsigned char pseg;     /* The pseg itself. */
-        unsigned ref_cnt:21,
-                 hardlock:1;
-};
+                                    _SUN4C_PAGE_REF | _SUN4C_PAGE_NOCACHE)
 
 extern char *sun4c_lockarea(char *vaddr, unsigned long size);
 extern void sun4c_unlockarea(char *vaddr, unsigned long size);
@@ -106,4 +88,64 @@ extern __inline__ unsigned long sun4c_get_synchronous_address(void)
        return sync_addr;
 }
 
+/* SUN4C pte, segmap, and context manipulation */
+extern __inline__ unsigned long sun4c_get_segmap(unsigned long addr)
+{
+  register unsigned long entry;
+
+  __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : 
+                      "=r" (entry) :
+                      "r" (addr), "i" (ASI_SEGMAP));
+
+  return entry;
+}
+
+extern __inline__ void sun4c_put_segmap(unsigned long addr, unsigned long entry)
+{
+
+  __asm__ __volatile__("\n\tstba %1, [%0] %2\n\t" : :
+                      "r" (addr), "r" (entry),
+                      "i" (ASI_SEGMAP));
+
+  return;
+}
+
+extern __inline__ unsigned long sun4c_get_pte(unsigned long addr)
+{
+  register unsigned long entry;
+
+  __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : 
+                      "=r" (entry) :
+                      "r" (addr), "i" (ASI_PTE));
+  return entry;
+}
+
+extern __inline__ void sun4c_put_pte(unsigned long addr, unsigned long entry)
+{
+  __asm__ __volatile__("\n\tsta %1, [%0] %2\n\t" : :
+                      "r" (addr), 
+                      "r" (entry), "i" (ASI_PTE));
+
+  return;
+}
+
+extern __inline__ int sun4c_get_context(void)
+{
+  register int ctx;
+
+  __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" :
+                      "=r" (ctx) :
+                      "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+  return ctx;
+}
+
+extern __inline__ int sun4c_set_context(int ctx)
+{
+  __asm__ __volatile__("\n\tstba %0, [%1] %2\n\t" : :
+                      "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+  return ctx;
+}
+
 #endif /* !(_SPARC_PGTSUN4C_H) */
index 8d9ad774a67c749c3d4f59db3e9d9c1f51e2d36a..81f6df3a725efdae99af0b89ef631990fd50ed66 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.29 1995/11/26 05:01:29 davem Exp $
+/* $Id: processor.h,v 1.40 1996/02/03 10:06:01 davem Exp $
  * include/asm-sparc/processor.h
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
@@ -7,12 +7,13 @@
 #ifndef __ASM_SPARC_PROCESSOR_H
 #define __ASM_SPARC_PROCESSOR_H
 
-#include <linux/string.h>
+#include <linux/a.out.h>
 
 #include <asm/psr.h>
 #include <asm/ptrace.h>
 #include <asm/head.h>
 #include <asm/signal.h>
+#include <asm/segment.h>
 
 /*
  * Bus types
@@ -34,6 +35,7 @@ extern char wp_works_ok;
 /* The Sparc processor specific thread struct. */
 struct thread_struct {
        unsigned long uwinmask __attribute__ ((aligned (8)));
+       struct pt_regs *kregs;
 
        /* For signal handling */
        unsigned long sig_address __attribute__ ((aligned (8)));
@@ -45,6 +47,10 @@ struct thread_struct {
        unsigned long kpsr;
        unsigned long kwim;
 
+       /* Special child fork kpsr/kwim values. */
+       unsigned long fork_kpsr __attribute__ ((aligned (8)));
+       unsigned long fork_kwim;
+
        /* A place to store user windows and stack pointers
         * when the stack needs inspection.
         */
@@ -53,15 +59,6 @@ struct thread_struct {
        unsigned long rwbuf_stkptrs[NSWINS] __attribute__ ((aligned (8)));
        unsigned long w_saved;
 
-       /* Where our page table lives. */
-       unsigned long pgd_ptr;
-
-       /* The context currently allocated to this process
-        * or -1 if no context has been allocated to this
-        * task yet.
-        */
-       int context;
-
        /* Floating point regs */
        unsigned long   float_regs[64] __attribute__ ((aligned (8)));
        unsigned long   fsr;
@@ -71,20 +68,27 @@ struct thread_struct {
                unsigned long insn;
        } fpqueue[16];
        struct sigstack sstk_info;
+       unsigned long flags;
+       int current_ds;
+       struct exec core_exec;     /* just what it says. */
 };
 
-#define INIT_MMAP { &init_mm, (0xf0000000UL), (0xfe100000UL), \
+#define SPARC_FLAG_KTHREAD      0x1    /* task is a kernel thread */
+
+#define INIT_MMAP { &init_mm, (0), (0), \
                    __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC }
 
 #define INIT_TSS  { \
-/* uwinmask, sig_address, sig_desc, ksp, kpc, kpsr, kwim */ \
-   0,        0,           0,        0,   0,   0,    0, \
+/* uwinmask, kregs, sig_address, sig_desc, ksp, kpc, kpsr, kwim */ \
+   0,        0,     0,           0,        0,   0,   0,    0, \
+/* fork_kpsr, fork_kwim */ \
+   0,         0, \
 /* reg_window */  \
 { { { 0, }, { 0, } }, }, \
 /* rwbuf_stkptrs */  \
 { 0, 0, 0, 0, 0, 0, 0, 0, }, \
-/* w_saved, pgd_ptr,                context */  \
-   0,       (long) &swapper_pg_dir, -1, \
+/* w_saved */ \
+   0, \
 /* 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, \
@@ -93,19 +97,39 @@ struct thread_struct {
    0,          0,  { { 0, 0, }, }, \
 /* sstk_info */ \
 { 0, 0, }, \
+/* flags,              current_ds, */ \
+   SPARC_FLAG_KTHREAD, USER_DS, \
+/* core_exec */ \
+{ 0, }, \
 }
 
 /* Return saved PC of a blocked thread. */
 extern inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
-       return ((struct pt_regs *)
-               ((t->ksp&(~0xfff))+(0x1000-TRACEREG_SZ)))->pc;
+       return t->kregs->pc;
 }
 
 /*
  * Do necessary setup to start up a newly executed thread.
  */
-extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp);
+extern inline void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
+{
+       unsigned long saved_psr = (regs->psr & (PSR_CWP)) | PSR_S;
+       int i;
+
+       for(i = 0; i < 16; i++) regs->u_regs[i] = 0;
+       regs->y = 0;
+       regs->pc = ((pc & (~3)) - 4);
+       regs->npc = regs->pc + 4;
+       regs->psr = saved_psr;
+       regs->u_regs[UREG_G1] = sp; /* Base of arg/env stack area */
+       regs->u_regs[UREG_G2] = regs->u_regs[UREG_G7] = regs->npc;
+       regs->u_regs[UREG_FP] = (sp - REGWIN_SZ);
+}
 
-#endif /* __ASM_SPARC_PROCESSOR_H */
+extern unsigned long (*alloc_kernel_stack)(struct task_struct *tsk);
+extern void (*free_kernel_stack)(unsigned long stack);
+extern struct task_struct *(*alloc_task_struct)(void);
+extern void (*free_task_struct)(struct task_struct *tsk);
 
+#endif /* __ASM_SPARC_PROCESSOR_H */
index 4dbdf2f0d58c3b32e5bfef94ac620f735c3d7db2..849eb3c4548ae4aa59cf03a10d42061edee89892 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: psr.h,v 1.5 1995/11/25 02:32:31 davem Exp $
+/* $Id: psr.h,v 1.10 1996/03/01 07:20:57 davem Exp $
  * psr.h: This file holds the macros for masking off various parts of
  *        the processor status register on the Sparc. This is valid
  *        for Version 8. On the V9 this is renamed to the PSTATE
 #ifndef __LINUX_SPARC_PSR_H
 #define __LINUX_SPARC_PSR_H
 
-#define __LINUX_SPARC_V8  /* duh */
-
-#ifdef __LINUX_SPARC_V8
-
 /* The Sparc PSR fields are laid out as the following:
  *
  *  ------------------------------------------------------------------------
@@ -22,7 +18,6 @@
  *  | 31-28 | 27-24 | 23-20 | 19-14 | 13 | 12 | 11-8 | 7 | 6  | 5  |  4-0  |
  *  ------------------------------------------------------------------------
  */
-
 #define PSR_CWP     0x0000001f         /* current window pointer     */
 #define PSR_ET      0x00000020         /* enable traps field         */
 #define PSR_PS      0x00000040         /* previous privilege level   */
@@ -30,6 +25,7 @@
 #define PSR_PIL     0x00000f00         /* processor interrupt level  */
 #define PSR_EF      0x00001000         /* enable floating point      */
 #define PSR_EC      0x00002000         /* enable co-processor        */
+#define PSR_LE      0x00008000         /* SuperSparcII little-endian */
 #define PSR_ICC     0x00f00000         /* integer condition codes    */
 #define PSR_C       0x00100000         /* carry bit                  */
 #define PSR_V       0x00200000         /* overflow bit               */
@@ -38,6 +34,8 @@
 #define PSR_VERS    0x0f000000         /* cpu-version field          */
 #define PSR_IMPL    0xf0000000         /* cpu-implementation field   */
 
+#ifdef __KERNEL__
+
 #ifndef __ASSEMBLY__
 /* Get the %psr register. */
 extern inline unsigned int get_psr(void)
@@ -50,8 +48,9 @@ extern inline unsigned int get_psr(void)
 
 extern inline void put_psr(unsigned int new_psr)
 {
-  __asm__("wr %0, 0x0, %%psr\n\t" : :
-         "r" (new_psr));
+       __asm__ __volatile__("wr %0, 0x0, %%psr\n\t"
+                            "nop; nop; nop;\n\t" : :
+                            "r" (new_psr));
 }
 
 /* Get the %fsr register.  Be careful, make sure the floating point
@@ -74,101 +73,6 @@ extern inline unsigned int get_fsr(void)
 
 #endif /* !(__ASSEMBLY__) */
 
-#endif /* !(__LINUX_SPARC_V8) */
-
-#ifdef __LINUX_SPARC_V9
-
-/* The information available in the %psr on the V8 is spread amongst
- * a whole bunch of registers on the V9. The main one being PSTATE.
- *
- *   --------------------------------------------------------
- *   |  CLE  | TLE |  MM  | RED | PEF | AM | PRIV | IE | AG |
- *   |   9   |  8  |  7-6 |  5  |  4  |  3 |   2  |  1 |  0 |
- *   --------------------------------------------------------
- *
- * Writes and reads to PSTATE are done via 'wrpr' and 'rdpr' instructions.
- *
- * For example:  wrpr %o2, or'd_bit_pattern, %pstate
- *               rdpr %pstate, %o3
- */
-
-#define PSTATE_AG    0x001   /* Alternate Globals             */
-#define PSTATE_IE    0x002   /* Interrupt Enable              */
-#define PSTATE_PRIV  0x004   /* Current privilege level       */
-#define PSTATE_AM    0x008   /* Address mask (data reads can  */
-                            /* be chosen to be either big or */
-                            /* little endian on V9).         */
-#define PSTATE_PEF   0x010   /* enable floating point         */
-#define PSTATE_RED   0x020   /* RED trap state (set if trap   */
-                             /* trap_level == max_tl).        */
-#define PSTATE_MM    0x0c0   /* Memory model (Total Store     */
-                             /* Order=0, Partial Store Order  */
-                             /* =1 or Relaxed Memory Order=2) */
-#define PSTATE_TLE   0x100   /* Trap Little Endian            */
-#define PSTATE_CLE   0x200   /* Current Little Endian         */
-
-
-extern inline unsigned int get_v9_pstate(void)
-{
-       unsigned int pstate;
-       __asm__ __volatile__("rdpr %pstate, %0\n\t" :
-                            "=r" (pstate));
-       return pstate;
-}
-
-extern inline void put_v9_pstate(unsigned int pstate)
-{
-       __asm__ __volatile__("wrpr %0, 0x0, %pstate\n\t" : :
-                            "r" (pstate));
-       return;
-}
-
-/* The Version Register holds vendor information for the chip:
- *
- *  ---------------------------------------------------------------------------
- *  | manufacturer | implementation | mask | reserved | maxtl | resv | maxwin |
- *  |  63-48       |   47-32        | 31-24|   23-16  | 15-8  | 7-5  |  4-0   |
- *  ---------------------------------------------------------------------------
- *
- */
-
-#define VERS_MAXWIN  0x000000000000001f     /* 'nwindows' on this chip       */
-#define VERS_MAXTL   0x00000000000ff000     /* Maximum Trap-level supported  */
-#define VERS_MASK    0x0000000ff0000000     /* impl. dep. chip mask revision */
-#define VERS_MANUF   0xffff000000000000     /* Manufacturer ID code          */
-
-extern inline unsigned int get_v9_version(void)
-{
-       unsigned int vers;
-       __asm__ __volatile__("rdpr %ver, %0\n\t" :
-                            "=r" (vers));
-       return vers;
-}
-
-extern inline unsigned int get_v9_tstate(void)
-{
-       unsigned int tstate;
-       __asm__ __volatile__("rdpr %tstate, %0\n\t" :
-                            "=r" (pstate));
-       return tstate;
-}
-
-extern inline unsigned int get_v9_pil(void)
-{
-       unsigned int pil;
-       __asm__ __volatile__("rdpr %pil, %0\n\t" :
-                            "=r" (pstate));
-       return pil;
-}
-
-extern inline void put_v9_pil(unsigned int pil)
-{
-       __asm__ __volatile__("wrpr %0, 0x0, %pil\n\t" : :
-                            "r" (pil));
-       return;
-}
-
-
-#endif /* !(__LINUX_SPARC_V9) */
+#endif /* (__KERNEL__) */
 
 #endif /* !(__LINUX_SPARC_PSR_H) */
index 3dccdfcc9a9624ce96413a8d9d54a3213b889820..758fc39ca58410531f805d523e37895aeadfb13c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ptrace.h,v 1.14 1995/11/25 02:32:33 davem Exp $ */
+/* $Id: ptrace.h,v 1.19 1996/01/24 02:33:50 davem Exp $ */
 #ifndef _SPARC_PTRACE_H
 #define _SPARC_PTRACE_H
 
@@ -35,6 +35,7 @@ struct pt_regs {
 #define UREG_I6        14
 #define UREG_I7        15
 #define UREG_WIM       UREG_G0
+#define UREG_FADDR     UREG_G0
 #define UREG_FP        UREG_I6
 #define UREG_RETPC     UREG_I7
 
@@ -73,7 +74,7 @@ extern void show_regs(struct pt_regs *);
 #define REGWIN_SZ         0x40
 #endif
 
-/* First generic task_struct offsets. sizeof(task_struct)=1536 */
+/* First generic task_struct offsets. sizeof(task_struct)=1576 */
 #define TASK_STATE        0x000
 #define TASK_PRIORITY     0x008
 #define TASK_SIGNAL       0x00c
@@ -90,14 +91,16 @@ extern void show_regs(struct pt_regs *);
 #define THREAD_KPC        0x224
 #define THREAD_KPSR       0x228
 #define THREAD_KWIM       0x22c
-#define THREAD_REG_WINDOW 0x230
-#define THREAD_STACK_PTRS 0x430
-#define THREAD_W_SAVED    0x450
-#define THREAD_PGD_PTR    0x454
-#define THREAD_CONTEXT    0x458
+#define THREAD_FORK_KPSR  0x230
+#define THREAD_FORK_KWIM  0x234
+#define THREAD_REG_WINDOW 0x238
+#define THREAD_STACK_PTRS 0x438
+#define THREAD_W_SAVED    0x458
 #define THREAD_FLOAT_REGS 0x460
 #define THREAD_FSR        0x560
 #define THREAD_SIGSTK     0x5e8
+#define THREAD_MM     0x620
+#define THREAD_MM_CTX     0x008
 
 /* These are for pt_regs. */
 #define PT_PSR    0x0
@@ -167,4 +170,25 @@ extern void show_regs(struct pt_regs *);
 #define SF_XARG5  0x58
 #define SF_XXARG  0x5c
 
+/* Stuff for the ptrace system call */
+#if 0 /* Need to fix the header files a bit... */
+#undef PTRACE_ATTACH
+#undef PTRACE_DETACH
+#define PTRACE_ATTACH            10
+#define PTRACE_DETACH            11
+#endif
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+#define PTRACE_GETFPREGS          14
+#define PTRACE_SETFPREGS          15
+#define PTRACE_READDATA           16
+#define PTRACE_WRITEDATA          17
+#define PTRACE_READTEXT           18
+#define PTRACE_WRITETEXT          19
+#define PTRACE_GETFPAREGS         20
+#define PTRACE_SETFPAREGS         21
+
+#define PTRACE_GETUCODE           29  /* stupid bsd-ism */
+
+
 #endif /* !(_SPARC_PTRACE_H) */
index 751981c45361597821956b8ad6e8449cf0f8b84b..53050fdd2196ac43ffac46d7f840cfdde430e3cd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ross.h,v 1.3 1995/11/25 02:32:37 davem Exp $
+/* $Id: ross.h,v 1.4 1996/01/03 03:53:20 davem Exp $
  * ross.h: Ross module specific definitions and defines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,8 @@
 #ifndef _SPARC_ROSS_H
 #define _SPARC_ROSS_H
 
+#include <asm/asi.h>
+
 /* Ross made Hypersparcs have a %psr 'impl' field of '0001'.  The 'vers'
  * field has '1111'.
  */
@@ -51,7 +53,7 @@
 #define HYPERSPARC_MENABLE    0x00000001
 
 /* Flushes which clear out only the on-chip Ross HyperSparc ICACHE. */
-extern inline void flush_i_page(unsigned int addr)
+extern inline void hyper_flush_i_page(unsigned int addr)
 {
        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
                             "r" (addr), "i" (ASI_M_IFLUSH_PAGE) :
@@ -59,7 +61,7 @@ extern inline void flush_i_page(unsigned int addr)
        return;
 }
 
-extern inline void flush_i_seg(unsigned int addr)
+extern inline void hyper_flush_i_seg(unsigned int addr)
 {
        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
                             "r" (addr), "i" (ASI_M_IFLUSH_SEG) :
@@ -67,7 +69,7 @@ extern inline void flush_i_seg(unsigned int addr)
        return;
 }
 
-extern inline void flush_i_region(unsigned int addr)
+extern inline void hyper_flush_i_region(unsigned int addr)
 {
        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
                             "r" (addr), "i" (ASI_M_IFLUSH_REGION) :
@@ -75,7 +77,7 @@ extern inline void flush_i_region(unsigned int addr)
        return;
 }
 
-extern inline void flush_i_ctx(unsigned int addr)
+extern inline void hyper_flush_i_ctx(unsigned int addr)
 {
        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
                             "r" (addr), "i" (ASI_M_IFLUSH_CTX) :
@@ -83,7 +85,7 @@ extern inline void flush_i_ctx(unsigned int addr)
        return;
 }
 
-extern inline void flush_i_user(unsigned int addr)
+extern inline void hyper_flush_i_user(unsigned int addr)
 {
        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
                             "r" (addr), "i" (ASI_M_IFLUSH_USER) :
@@ -92,7 +94,7 @@ extern inline void flush_i_user(unsigned int addr)
 }
 
 /* Finally, flush the entire ICACHE. */
-extern inline void flush_whole_icache(void)
+extern inline void hyper_flush_whole_icache(void)
 {
        __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
                             "i" (ASI_M_FLUSH_IWHOLE));
@@ -149,4 +151,19 @@ extern inline void put_ross_icr(unsigned int icreg)
        return;
 }
 
+/* HyperSparc specific cache flushing. */
+
+extern int hyper_cache_size;
+
+extern inline void hyper_flush_all_combined(void)
+{
+       unsigned long addr;
+
+       for(addr = 0; addr < hyper_cache_size; addr += 32)
+               __asm__ __volatile__("sta %%g0, [%0] 0xe\n\t" : :
+                                    "r" (addr));
+}
+
+
+
 #endif /* !(_SPARC_ROSS_H) */
index 4e2c5fc57d825585b093993463b7bb184efd0c38..35ccd5296e85ae459c5091cad5c1c5a046a9ec74 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.8 1995/11/25 02:32:38 davem Exp $
+/* $Id: sbus.h,v 1.9 1996/02/15 09:13:03 davem Exp $
  * sbus.h:  Defines for the Sun SBus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
 #define _SPARC_SBUS_H
 
 #include <asm/oplib.h>
+#include <asm/iommu.h>
 
 /* We scan which devices are on the SBus using the PROM node device
  * tree.  SBus devices are described in two different ways.  You can
@@ -64,11 +65,12 @@ struct linux_sbus_device {
 
 /* This struct describes the SBus(s) found on this machine. */
 struct linux_sbus {
-  struct linux_sbus *next;             /* next SBus, if more than one SBus */
-  struct linux_sbus_device *devices;   /* Link to devices on this SBus */
-  int prom_node;                       /* PROM device tree node for this SBus */
-  char prom_name[64];                  /* Usually "sbus" */
-  int clock_freq;
+       struct linux_sbus *next;             /* next SBus, if more than one SBus */
+       struct linux_sbus_device *devices;   /* Link to devices on this SBus */
+       struct iommu_struct *iommu;          /* IOMMU for this sbus if applicable */
+       int prom_node;                       /* PROM device tree node for this SBus */
+       char prom_name[64];                  /* Usually "sbus" */
+       int clock_freq;
 };
 
 extern struct linux_sbus *SBus_chain;
index d61b0f76b3fa61ee1893e37488a1c7fc7737c27f..ab6279ff490b549df66618d3cfa8a50a06a0b1a9 100644 (file)
@@ -1,12 +1,7 @@
-/* $Id: segment.h,v 1.6 1995/11/25 02:32:40 davem Exp $ */
+/* $Id: segment.h,v 1.9 1996/01/14 00:05:33 davem Exp $ */
 #ifndef _ASM_SEGMENT_H
 #define _ASM_SEGMENT_H
 
-/* Sparc is not segmented, these are just place holders. */
-#define KERNEL_DS   0
-#define USER_DS     1
-
-#include <linux/string.h>
 #include <asm/vac-ops.h>
 
 #ifndef __ASSEMBLY__
@@ -109,21 +104,27 @@ static inline void put_user_long(unsigned long val,int * addr)
 
 #define memcpy_tofs(to, from, n) memcpy((to),(from),(n))
 
-extern int current_user_segment;
+/* Sparc is not segmented, however we need to be able to fool verify_area()
+ * when doing system calls from kernel mode legitimately.
+ */
+#define KERNEL_DS   0
+#define USER_DS     1
+
+extern int active_ds;
 
-static inline unsigned long get_fs(void)
+static inline int get_fs(void)
 {
-       return current_user_segment;
+       return active_ds;
 }
 
-static inline unsigned long get_ds(void)
+static inline int get_ds(void)
 {
        return KERNEL_DS;
 }
 
-static inline void set_fs(unsigned long val)
+static inline void set_fs(int val)
 {
-       current_user_segment = val;
+       active_ds = val;
 }
 
 #endif  /* __ASSEMBLY__ */
index 76cbe975828be5308552b5b3b80a5d0728d5555b..4942457004a6ce1df2ae201bce5804d47f648b10 100644 (file)
@@ -1,9 +1,13 @@
-/* $Id: sigcontext.h,v 1.7 1995/11/25 02:32:44 davem Exp $ */
+/* $Id: sigcontext.h,v 1.8 1996/03/01 07:20:59 davem Exp $ */
 #ifndef _ASMsparc_SIGCONTEXT_H
 #define _ASMsparc_SIGCONTEXT_H
 
 #include <asm/ptrace.h>
 
+#define SUNOS_MAXWIN   31
+
+#ifndef __ASSEMBLY__
+
 /* SunOS system call sigstack() uses this arg. */
 struct sunos_sigstack {
        unsigned long sig_sp;
@@ -11,7 +15,6 @@ struct sunos_sigstack {
 };
 
 /* This is what SunOS does, so shall I. */
-#define SUNOS_MAXWIN   31
 struct sigcontext_struct {
        int sigc_onstack;      /* state to restore */
        int sigc_mask;         /* sigmask to restore */
@@ -33,5 +36,7 @@ struct sigcontext_struct {
        /* Windows to restore after signal */
        struct reg_window sigc_wbuf[SUNOS_MAXWIN];
 };
+#endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_ASMsparc_SIGCONTEXT_H) */
+
index 16214ae72e4c9cc4a7aeaef7a5fd9c7b530f8af0..15ced3450887414860df63319f98c218e041f305 100644 (file)
@@ -1,7 +1,9 @@
-/* $Id: signal.h,v 1.14 1995/11/25 02:32:46 davem Exp $ */
+/* $Id: signal.h,v 1.17 1996/03/01 07:21:02 davem Exp $ */
 #ifndef _ASMSPARC_SIGNAL_H
 #define _ASMSPARC_SIGNAL_H
 
+#include <asm/sigcontext.h>
+
 /* On the Sparc the signal handlers get passed a 'sub-signal' code
  * for certain signal types, which we document here.
  */
@@ -15,7 +17,7 @@
 #define    SUBSIG_STACK       0
 #define    SUBSIG_ILLINST     2
 #define    SUBSIG_PRIVINST    3
-#define    SUBSIG_BADTRAP(t)  (0x80 + (n))
+#define    SUBSIG_BADTRAP(t)  (0x80 + (t))
 
 #define SIGTRAP                 5
 #define SIGABRT                 6
@@ -87,7 +89,7 @@ struct sigstack {
 
 /* Sigvec flags */
 #define SV_SSTACK    1     /* This signal handler should use sig-stack */
-#define SV_INTR      2     /* Sig return should not restart system ??? */
+#define SV_INTR      2     /* Sig return should not restart system call */
 #define SV_RESET     4     /* Set handler to SIG_DFL upon taken signal */
 #define SV_IGNCHILD  8     /* Do not send SIGCHLD */
 
@@ -102,15 +104,15 @@ struct sigstack {
  */
 #define SA_NOCLDSTOP   SV_IGNCHILD
 #define SA_STACK       SV_SSTACK
-#define SA_RESTART     SV_RESET
-#define SA_INTERRUPT   SV_INTR
-#define SA_NOMASK      0x10
-#define SA_ONESHOT     0x20
+#define SA_RESTART     SV_INTR
+#define SA_ONESHOT     SV_RESET
+#define SA_INTERRUPT   0x10
+#define SA_NOMASK      0x20
 #define SA_SHIRQ       0x40
 
-#define SIG_BLOCK          0x00        /* for blocking signals */
-#define SIG_UNBLOCK        0x40        /* for unblocking signals */
-#define SIG_SETMASK        0x80        /* for setting the signal mask */
+#define SIG_BLOCK          0x01        /* for blocking signals */
+#define SIG_UNBLOCK        0x02        /* for unblocking signals */
+#define SIG_SETMASK        0x04        /* for setting the signal mask */
 
 #ifdef __KERNEL__
 /*
diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h
new file mode 100644 (file)
index 0000000..a070021
--- /dev/null
@@ -0,0 +1,91 @@
+/* smp.h: Sparc specific SMP stuff.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_SMP_H
+#define _SPARC_SMP_H
+
+#include <asm/bitops.h>
+#include <asm/ptrace.h>
+
+/* Per processor Sparc parameters. */
+
+struct cpuinfo_sparc {
+       unsigned char impl;
+       unsigned char vers;
+       unsigned long udelay_val;
+};
+
+extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+
+typedef klock_t volatile unsigned char;
+extern klock_t kernel_lock;
+
+#define KLOCK_HELD       0xff
+#define KLOCK_CLEAR      0x00
+
+struct sparc_ipi_invalidate {
+       struct mm_struct *mm;
+       unsigned long addr;   /* page for inv_pg, start for inv_rnge */
+       unsigned long end;    /* Used for inv_rnge only. */
+};
+
+struct sparc_ipimsg {
+       union {
+               /* Add more here as we need them. */
+               struct sparc_ipi_invalidate invmsg;
+       };
+};
+
+extern void smp_scan_prom_for_cpus(unsigned long, unsigned long);
+extern unsigned long smp_alloc_memory(unsigned long mem_base);
+extern unsigned long *kernel_stacks[NR_CPUS];
+extern unsigned char boot_cpu_id;
+extern unsigned long cpu_present_map;
+extern volatile unsigned long smp_invalidate_needed;
+extern unsigned long kernel_counter;
+extern volatile unsigned char active_kernel_processor;
+extern void smp_message_irq(int cpl, struct pt_regs *regs);
+extern void smp_reschedule_irq(int cpl, struct pt_regs *regs);
+extern void smp_invalidate_rcv(void);
+extern volatils unsigned long syscall_count;
+
+extern void (*smp_invalidate_all)(void);
+extern void (*smp_invalidate_mm)(struct mm_struct *);
+extern void (*smp_invalidate_range)(struct mm_struct *, unsigned long, unsigned long);
+extern void (*smp_invalidate_page)(struct vm_area_struct *, unsigned long);
+
+extern void smp_callin(void);
+extern void smp_boot_cpus(void);
+extern void smp_store_cpu_info(int id);
+
+extern _inline_ int smp_processor_id(void)
+{
+       int cpuid;
+
+       __asm__ __volatile__("rd %%tbr, %0\n\t"
+                            "srl %0, 24, %0\n\t"
+                            "and %0, 3, %0\n\t" :
+                            "=&r" (cpuid) :
+                            "0" (cpuid));
+       return cpuid;
+}
+
+/* Imperical PROM processor mailbox constants.  If the per-cpu mailbox
+ * contains something other than one of these then the ipi is from
+ * Linux's active_kernel_processor.  This facility exists so that
+ * the boot monitor can capture all the other cpus when one catches
+ * a watchdog reset or the user enters the monitor using L1-A keys.
+ */
+#define MBOX_STOPCPU          0xFB
+#define MBOX_IDLECPU          0xFC
+#define MBOX_IDLECPU2         0xFD
+#define MBOX_STOPCPU2         0xFE
+
+
+#define NO_PROC_ID            0xFF
+
+#define PROC_CHANGE_PENALTY   0x23
+
+#endif /* !(_SPARC_SMP_H) */
diff --git a/include/asm-sparc/smp_lock.h b/include/asm-sparc/smp_lock.h
new file mode 100644 (file)
index 0000000..aeb4914
--- /dev/null
@@ -0,0 +1,57 @@
+/* smp_lock.h: Locking and unlocking the kernel on the Sparc.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_SMPLOCK_H
+#define __SPARC_SMPLOCK_H
+
+#ifdef __SMP__
+
+extern _inline_ unsigned char ldstub(klock_t *lock)
+{
+       klock_t retval;
+
+       __asm__ __volatile__("ldstub [%1], %0\n\t" :
+                            "=r" (retval) :
+                            "r" (lock));
+       return retval;
+}
+
+/* Knock knock... */
+extern _inline_ void lock_kernel(void)
+{
+       unsigned long flags;
+       int proc = smp_processor_id();
+
+       save_flags(flags); cli(); /* need this on sparc? */
+       while(ldstub(&kernel_lock)) {
+               if(proc == active_kernel_processor)
+                       break;
+               if(test_bit(proc, (unsigned long *)&smp_invalidate_needed))
+                       if(clear_bit(proc, (unsigned long *)&smp_invalidate_needed))
+                               local_invalidate();
+       }
+       active_kernel_processor = proc;
+       kernel_counter++;
+       restore_flags(flags);
+}
+
+/* I want out... */
+extern _inline_ void unlock_kernel(void)
+{
+       unsigned long flags;
+
+       save_flags(flags); cli(); /* need this on sparc? */
+       if(kernel_counter == 0)
+               panic("Bogus kernel counter.\n");
+       if(!--kernel_counter) {
+               active_kernel_processor = NO_PROC_ID;
+               kernel_lock = KLOCK_CLEAR;
+       }
+       restore_flag(flags);
+}
+
+#endif /* !(__SPARC_SMPLOCK_H) */
+
+#endif /* (__SMP__) */
index 9770d81896a879f544515e1c1ef2fb65bde73d82..d6dcb425733219b2a8e7b33ecf44d70ed8583443 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.15 1995/11/25 02:32:56 davem Exp $
+/* $Id: string.h,v 1.17 1995/12/10 06:25:48 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -8,6 +8,8 @@
 #ifndef __SPARC_STRING_H__
 #define __SPARC_STRING_H__
 
-/* Nothing yet... */
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMCPY
 
 #endif /* !(__SPARC_STRING_H__) */
diff --git a/include/asm-sparc/swift.h b/include/asm-sparc/swift.h
new file mode 100644 (file)
index 0000000..ff1e908
--- /dev/null
@@ -0,0 +1,65 @@
+/* swift.h: Specific definitions for the _broken_ Swift SRMMU
+ *          MMU.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_SWIFT_H
+#define _SPARC_SWIFT_H
+
+/* Swift is so brain damaged, here is the mmu control register. */
+#define SWIFT_ST       0x00800000   /* SW tablewalk enable */
+#define SWIFT_WP       0x00400000   /* Watchpoint enable   */
+
+/* Branch folding (buggy, disable on production systems!)  */
+#define SWIFT_BF       0x00200000
+#define SWIFT_PMC      0x00180000   /* Page mode control   */
+#define SWIFT_PE       0x00040000   /* Parity enable       */
+#define SWIFT_PC       0x00020000   /* Parity control      */
+#define SWIFT_AP       0x00010000   /* Graphics page mode control (TCX/SX) */
+#define SWIFT_AC       0x00008000   /* Alternate Cacheability (see viking.h) */
+#define SWIFT_BM       0x00004000   /* Boot mode */
+#define SWIFT_RC       0x00003c00   /* DRAM refresh control */
+#define SWIFT_IE       0x00000200   /* Instruction cache enable */
+#define SWIFT_DE       0x00000100   /* Data cache enable */
+#define SWIFT_SA       0x00000080   /* Store Allocate */
+#define SWIFT_NF       0x00000002   /* No fault mode */
+#define SWIFT_EN       0x00000001   /* MMU enable */
+
+extern inline void swift_inv_insn_tag(unsigned long addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_TXTC_TAG));
+}
+
+extern inline void swift_inv_data_tag(unsigned long addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_DATAC_TAG));
+}
+
+extern inline void swift_flush_page(unsigned long page)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (page), "i" (ASI_M_FLUSH_PAGE));
+}
+
+extern inline void swift_flush_segment(unsigned long addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_FLUSH_SEG));
+}
+
+extern inline void swift_flush_region(unsigned long addr)
+{
+       __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+                            "r" (addr), "i" (ASI_M_FLUSH_REGION));
+}
+
+extern inline void swift_flush_context(void)
+{
+       __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+                            "i" (ASI_M_FLUSH_CTX));
+}
+
+#endif /* !(_SPARC_SWIFT_H) */
index 4f1b2e0f545132b18d2f7410fd431ad25b54ac8d..5808615a1b43436b8e0644320eeb69b60b801125 100644 (file)
@@ -1,16 +1,16 @@
-/* $Id: system.h,v 1.19 1995/11/25 02:32:59 davem Exp $ */
+/* $Id: system.h,v 1.24 1996/02/11 00:42:39 davem Exp $ */
 #ifndef __SPARC_SYSTEM_H
 #define __SPARC_SYSTEM_H
 
-#include <asm/segment.h>
+#include <linux/kernel.h>
 
+#include <asm/segment.h>
 #include <asm/page.h>
-#include <asm/openprom.h>
+#include <asm/oplib.h>
 #include <asm/psr.h>
 
 #define EMPTY_PGT       (&empty_bad_page)
 #define EMPTY_PGE      (&empty_bad_page_table)
-#define ZERO_PGE       (&empty_zero_page)
 
 #ifndef __ASSEMBLY__
 
@@ -42,10 +42,13 @@ extern struct linux_romvec *romvec;
  * frames are up to date.
  */
 extern void flush_user_windows(void);
+extern void synchronize_user_stack(void);
 extern void sparc_switch_to(void *new_task);
 #define switch_to(p) do { \
                          flush_user_windows(); \
                          switch_to_context(p); \
+                         current->tss.current_ds = active_ds; \
+                          active_ds = p->tss.current_ds; \
                           sparc_switch_to(p); \
                      } while(0)
 
@@ -94,10 +97,13 @@ extern inline int swpipl(int __new_ipl)
        return retval;
 }
 
+extern char spdeb_buf[256];
+
 #define cli()                  setipl(15)  /* 15 = no int's except nmi's */
 #define sti()                  setipl(0)   /* I'm scared */
 #define save_flags(flags)      do { flags = getipl(); } while (0)
 #define restore_flags(flags)   setipl(flags)
+
 #define nop() __asm__ __volatile__ ("nop");
 
 extern inline unsigned long xchg_u32(volatile unsigned long *m, unsigned long val)
index 5cd4e8e01750d28eec4caf0d34d0e2e76279fc3d..bf95501bb002c34dd686b048bab5306c5c261a94 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.10 1995/11/25 02:33:01 davem Exp $ */
+/* $Id: termios.h,v 1.11 1996/02/10 04:31:03 davem Exp $ */
 #ifndef _SPARC_TERMIOS_H
 #define _SPARC_TERMIOS_H
 
@@ -193,12 +193,11 @@ struct termios {
 
 #ifdef __KERNEL__
 /*     intr=^C         quit=^|         erase=del       kill=^U
-       eof=^D          vtime=\0        vmin=\1         sxtc=\0
-       start=^Q        stop=^S         susp=^Z         eol=\0
+       eof/vmin=\1     eol/vtime=\0    eol2=\0         sxtc=\0
+       start=^Q        stop=^S         susp=^Z         dsusp=^Y
        reprint=^R      discard=^U      werase=^W       lnext=^V
-       eol2=\0
 */
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\001\000\000\000\021\023\032\031\022\025\027\026"
 #endif
 
 /* c_iflag bits */
index 622ad93d2f4eb791da6bd688a1c8af7dbfd57c65..a21fea1ad8fb4e645f7ff5a87f2bb77b95a08024 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: timer.h,v 1.10 1995/11/25 02:33:03 davem Exp $
+/* $Id: timer.h,v 1.11 1996/01/03 03:53:23 davem Exp $
  * timer.h:  Definitions for the timer chips on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -32,8 +32,7 @@ struct sun4c_timer_info {
 
 #define SUN4C_TIMER_PHYSADDR   0xf3000000
 
-/* All accesses to the sun4c timer registers should use this macro. */
-#define  SUN4C_TIMER_STRUCT  ((volatile struct sun4c_timer_info *) TIMER_VADDR)
+volatile struct sun4c_timer_info *sun4c_timers;
 
 /* A sun4m has two blocks of registers which are probably of the same
  * structure. LSI Logic's L64851 is told to _decrement_ from the limit
index c2bb11c4612929c236cf7139a9b3bab68630ad22..ab65b37a1a71d8d7bab5a0d5b52db4202e64c19c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tsunami.h,v 1.2 1995/11/25 02:33:06 davem Exp $
+/* $Id: tsunami.h,v 1.3 1996/01/10 21:00:12 davem Exp $
  * tsunami.h:  Module specific definitions for Tsunami V8 Sparcs
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,8 @@
 #ifndef _SPARC_TSUNAMI_H
 #define _SPARC_TSUNAMI_H
 
+#include <asm/asi.h>
+
 /* The MMU control register on the Tsunami:
  *
  * -----------------------------------------------------------------------
 #define TSUNAMI_NF        0x00000002
 #define TSUNAMI_ME        0x00000001
 
+extern inline void tsunami_invalidate_icache(void)
+{
+       __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+                            "i" (ASI_M_IC_FLCLEAR) : "memory");
+}
+
+extern inline void tsunami_invalidate_dcache(void)
+{
+       __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+                            "i" (ASI_M_DC_FLCLEAR) : "memory");
+}
+
 #endif /* !(_SPARC_TSUNAMI_H) */
index 8c85e0dfda3280009f454730748270ca4e031591..9a12399bc677f437f09839a9dfa45bf49132efd8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.15 1995/11/25 02:33:12 davem Exp $ */
+/* $Id: unistd.h,v 1.16 1995/12/29 23:14:26 miguel Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
 #define __NR_mlockall           239
 #define __NR_munlockall         240
 
-/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar.
- * XXX These need to be fixed to check the condition codes to see
- * XXX the return value is an errorno or success.
- */
 #define _syscall0(type,name) \
 type name(void) \
 { \
 long __res; \
 __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
                  "t 0x10\n\t" \
+                 "bcc 1f\n\t" \
                  "or %%g0, %%o0, %0\n\t" \
-                 : "=r" (__res) \
+                 "sub %%g0, %%o0, %0\n\t" \
+                 "1:\n\t" \
+                 : "=r" (__res)\
                  : "0" (__NR_##name) \
                  : "g1"); \
 if (__res >= 0) \
     return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
 
@@ -285,13 +284,16 @@ long __res; \
 __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
                  "or %%g0, %1, %%o0\n\t" \
                  "t 0x10\n\t" \
+                 "bcc 1f\n\t" \
                  "or %%g0, %%o0, %0\n\t" \
+                 "sub %%g0, %%o0, %0\n\t" \
+                 "1:\n\t" \
                  : "=r" (__res), "=r" ((long)(arg1)) \
                  : "0" (__NR_##name),"1" ((long)(arg1)) \
                  : "g1", "o0"); \
 if (__res >= 0) \
        return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
 
@@ -303,13 +305,16 @@ __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
                  "or %%g0, %1, %%o0\n\t" \
                  "or %%g0, %2, %%o1\n\t" \
                  "t 0x10\n\t" \
+                 "bcc 1f\n\t" \
                  "or %%g0, %%o0, %0\n\t" \
+                 "sub %%g0,%%o0,%0\n\t" \
+                 "1:\n\t" \
                  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \
                  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \
                  : "g1", "o0", "o1"); \
 if (__res >= 0) \
        return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
 
@@ -322,7 +327,10 @@ __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
                  "or %%g0, %2, %%o1\n\t" \
                  "or %%g0, %3, %%o2\n\t" \
                  "t 0x10\n\t" \
+                 "bcc 1f\n\t" \
                  "or %%g0, %%o0, %0\n\t" \
+                 "sub %%g0, %%o0, %0\n\t" \
+                 "1:\n\t" \
                  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
                    "=r" ((long)(arg3)) \
                  : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \
@@ -330,7 +338,7 @@ __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
                  : "g1", "o0", "o1", "o2"); \
 if (__res>=0) \
        return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
 
@@ -344,7 +352,10 @@ __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
                  "or %%g0, %3, %%o2\n\t" \
                  "or %%g0, %4, %%o3\n\t" \
                  "t 0x10\n\t" \
+                 "bcc 1f\n\t" \
                  "or %%g0, %%o0, %0\n\t" \
+                 "sub %%g0,%%o0, %0\n\t" \
+                 "1:\n\t" \
                  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
                    "=r" ((long)(arg3)), "=r" ((long)(arg4)) \
                  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
@@ -352,7 +363,7 @@ __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
                  : "g1", "o0", "o1", "o2", "o3"); \
 if (__res>=0) \
        return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 } 
 
@@ -376,10 +387,9 @@ __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
                  : "g1", "o0", "o1", "o2", "o3", "o4"); \
 if (__res>=0) \
        return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
-
 #ifdef __KERNEL_SYSCALLS__
 
 /*
@@ -466,4 +476,14 @@ static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long f
 
 #endif /* __KERNEL_SYSCALLS__ */
 
+/* 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
+
 #endif /* _SPARC_UNISTD_H */
index 59947a849f7e89751278bd1669e13e0406b4aef0..1aca1e1a666a5ad380fd4a4ac11850c26c6942b0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: user.h,v 1.2 1995/11/25 02:33:15 davem Exp $
+/* $Id: user.h,v 1.3 1995/12/29 21:48:03 davem Exp $
  * asm-sparc/user.h: Core file definitions for the Sparc.
  *
  * Copyright (C) 1995 (davem@caip.rutgers.edu)
@@ -6,18 +6,45 @@
 #ifndef _SPARC_USER_H
 #define _SPARC_USER_H
 
+struct sunos_regs {
+       unsigned long psr, pc, npc, y;
+       unsigned long regs[15];
+};
+
+struct sunos_fpqueue {
+       unsigned long *addr;
+       unsigned long inst;
+};
+
+struct sunos_fp {
+       union {
+               unsigned long regs[32];
+               double reg_dbls[16];
+       } fregs;
+       unsigned long fsr;
+       unsigned long flags;
+       unsigned long extra;
+       unsigned long fpq_count;
+       struct sunos_fpqueue fpq[16];
+};
+
+struct sunos_fpu {
+       struct sunos_fp fpstatus;
+};
+
+/* The SunOS core file header layout. */
 struct user {
-       unsigned long regs[24 + 32]; /* locals, ins, globals + fpu regs */
-       size_t        u_tsize;
+       unsigned long magic;
+       unsigned long len;
+       struct sunos_regs regs;
+       struct exec uexec;
+       int           signal;
+       size_t        u_tsize; /* all of these in bytes! */
        size_t        u_dsize;
        size_t        u_ssize;
-       unsigned long start_code;
-       unsigned long start_data;
-       unsigned long start_stack;
-       int           signal;
-       unsigned long *u_ar0;
-       unsigned long magic;
-       char          u_comm[32];
+       char          u_comm[17];
+       struct sunos_fpu fpu;
+       unsigned long sigcode;   /* Special sigcontext subcode, if any */
 };
 
 #define NBPG                   PAGE_SIZE
@@ -25,5 +52,6 @@ struct user {
 #define HOST_TEXT_START_ADDR   (u.start_code)
 #define HOST_DATA_START_ADDR   (u.start_data)
 #define HOST_STACK_END_ADDR    (u.start_stack + u.u_ssize * NBPG)
+#define SUNOS_CORE_MAGIC       0x080456
 
 #endif /* !(_SPARC_USER_H) */
index d62df915ed417977951dcea7f2e409a235610eb2..752779031caa0a9a4161a620919c59a8ff1ab27e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: vac-ops.h,v 1.7 1995/11/25 02:33:18 davem Exp $ */
+/* $Id: vac-ops.h,v 1.9 1995/12/17 09:02:00 davem Exp $ */
 #ifndef _SPARC_VAC_OPS_H
 #define _SPARC_VAC_OPS_H
 
@@ -122,50 +122,6 @@ extern __inline__ void sun4c_disable_vac(void)
   sun4c_vacinfo.on = 0;
 }
 
-extern unsigned long sun4c_ctxflush;
-extern unsigned long sun4c_segflush;
-extern unsigned long sun4c_pgflush;
-
-extern void sun4c_ctxflush_hw64KB16B(void);
-extern void sun4c_ctxflush_hw64KB32B(void);
-extern void sun4c_ctxflush_sw64KB16B(void);
-extern void sun4c_ctxflush_sw64KB32B(void);
-
-extern void sun4c_segflush_hw64KB16B(void);
-extern void sun4c_segflush_hw64KB32B(void);
-extern void sun4c_segflush_sw64KB16B(void);
-extern void sun4c_segflush_sw64KB32B(void);
-
-extern void sun4c_pgflush_hw64KB16B(void);
-extern void sun4c_pgflush_hw64KB32B(void);
-extern void sun4c_pgflush_sw64KB16B(void);
-extern void sun4c_pgflush_sw64KB32B(void);
-
-/* These do indirect calls to the in-line assembly routines
- * in s4ctlb.S, see that file for more answers.
- */
-extern inline void sun4c_flush_context(void)
-{
-       __asm__ __volatile__("jmpl %0, %%l4\n\t"
-                            "nop\n\t" : :
-                            "r" (sun4c_ctxflush) :
-                            "l4", "l6", "l7", "memory");
-}
-
-extern inline void sun4c_flush_segment(unsigned long segment)
-{
-       __asm__ __volatile__("jmpl %0, %%l4\n\t"
-                            "or %1, %%g0, %%l2\n\t" : :
-                            "r" (sun4c_segflush), "r" (segment) :
-                            "l2", "l4", "l6", "l7", "memory");
-}
-
-extern inline void sun4c_flush_page(unsigned long page)
-{
-       __asm__ __volatile__("jmpl %0, %%l4\n\t"
-                            "or %1, %%g0, %%l2\n\t" : :
-                            "r" (sun4c_pgflush), "r" (page) :
-                            "l2", "l4", "l6", "l7", "memory");
-}
+extern void sun4c_flush_context(void);
 
 #endif /* !(_SPARC_VAC_OPS_H) */
index 1696b11a8f20dabffb051e5779a13cddf7a39722..00ac06bfe125c58377c4a4ffa8395048c9576a9d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: vaddrs.h,v 1.15 1995/11/25 02:33:20 davem Exp $ */
+/* $Id: vaddrs.h,v 1.17 1996/01/10 21:00:16 davem Exp $ */
 #ifndef _SPARC_VADDRS_H
 #define _SPARC_VADDRS_H
 
  * mappings for devices and is the speedup improvements of not loading
  * a pointer and then the value in the assembly code
  */
-
-#define  AUXIO_VADDR  (KERNBASE+0x6000)    /* Auxiliary IO register */
-#define  TIMER_VADDR  (AUXIO_VADDR+0x1000) /* One page after AUXIO, length is
-                                           * 5 pages which is needed on sun4m.
-                                           */
-#define  INTREG_VADDR (TIMER_VADDR+0x5000)
-
 #define  IOBASE_VADDR   0xfe000000  /* Base for mapping pages */
 #define  IOBASE_LEN     0x00100000  /* Length of the IO area */
 #define  IOBASE_END     0xfe100000
 #define  DVMA_LEN       0x00040000  /* Size of the DVMA address space */
 #define  DVMA_END       0xfff40000
 
+/* IOMMU Mapping area, must be on a 16MB boundry!  Note this
+ * doesn't count the DVMA areas, the prom lives between the
+ * iommu mapping area (for scsi transfer buffers) and the
+ * dvma upper range (for lance packet ring buffers).
+ */
+#define  IOMMU_VADDR    0xff000000
+#define  IOMMU_LEN      0x00c00000
+#define  IOMMU_END      0xffc00000 /* KADB debugger vm starts here */
+
+/* On the sun4/4c we don't need an IOMMU area, but we need a place
+ * to reliably map locked down kernel data.  This includes the
+ * task_struct and kernel stack pages of each process plus the
+ * scsi buffers during dvma IO transfers, also the floppy buffers
+ * during pseudo dma which runs with traps off (no faults allowed).
+ * Some quick calculations yield:
+ *       NR_TASKS <512> * (3 * PAGE_SIZE) == 0x600000
+ * Subtract this from 0xc00000 and you get 0x927C0 of vm left
+ * over to map SCSI dvma + floppy pseudo-dma buffers.  So be
+ * careful if you change NR_TASKS or else there won't be enough
+ * room for it all.
+ */
+#define  SUN4C_LOCK_VADDR  0xff000000
+#define  SUN4C_LOCK_LEN    0x00c00000
+#define  SUN4C_LOCK_END    0xffc00000
+
 /* On sun4m machines we need per-cpu virtual areas */
 #define  PERCPU_VADDR   0xff000000  /* Base for per-cpu virtual mappings */
 #define  PERCPU_ENTSIZE 0x00100000
@@ -44,3 +62,4 @@
 #define  PERCPU_ISIDLING_OFFSET 0x03008      /* Is CPU in idle loop spinning? */
 
 #endif /* !(_SPARC_VADDRS_H) */
+
index e9a50fdc102075d39eb5dd732ac2e73b277a3a28..476daa3271839b6a4aebdd3e7d5e64d20e6a623b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: viking.h,v 1.5 1995/11/25 02:33:21 davem Exp $
+/* $Id: viking.h,v 1.6 1996/03/01 07:21:05 davem Exp $
  * viking.h:  Defines specific to the TI Viking MBUS module.
  *            This is SRMMU stuff.
  *
@@ -7,6 +7,8 @@
 #ifndef _SPARC_VIKING_H
 #define _SPARC_VIKING_H
 
+#include <asm/mxcc.h>
+
 /* Bits in the SRMMU control register for TI Viking modules.
  *
  * -------------------------------------------------------------
 #define VIKING_TCENABLE     0x00010000   /* Enable table-walks to be cached */
 #define VIKING_DPENABLE     0x00040000   /* Enable the data prefetcher */
 
-#endif
+extern inline void viking_flush_icache(void)
+{
+       __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+                            "i" (ASI_M_IC_FLCLEAR));
+}
+
+extern inline void viking_flush_dcache(void)
+{
+       __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+                            "i" (ASI_M_DC_FLCLEAR));
+}
+
+/* MXCC stuff... */
+extern inline void viking_enable_mxcc(void)
+{
+}
+
+extern inline void viking_mxcc_scrape(void)
+{
+       /* David, what did you learn in school today? */
+
+
+}
+
+#endif /* !(_SPARC_VIKING_H) */
diff --git a/include/asm-sparc/vuid_event.h b/include/asm-sparc/vuid_event.h
new file mode 100644 (file)
index 0000000..15dcbdf
--- /dev/null
@@ -0,0 +1,41 @@
+/* SunOS Virtual User Input Device (VUID) compatibility */
+
+
+typedef struct firm_event {
+       unsigned short id;        /* tag for this event */
+       unsigned char  pair_type; /* unused by X11 */
+        unsigned char  pair;     /* unused by X11 */
+        int            value;    /* VKEY_UP, VKEY_DOWN or delta */
+        struct timeval time;
+} Firm_event;
+
+enum {
+    FE_PAIR_NONE,
+    FE_PAIR_SET,
+    FE_PAIR_DELTA,
+    FE_PAIR_ABSOLUTE
+};
+
+/* VUID stream formats */
+#define VUID_NATIVE     0      /* Native byte stream format */
+#define VUID_FIRM_EVENT 1      /* send firm_event structures */
+
+/* ioctls */
+    /* Set input device byte stream format (any of VUID_{NATIVE,FIRM_EVENT}) */
+#define VUIDSFORMAT   _IOW('v', 1, int)
+    /* Retrieve input device byte stream format */
+#define VUIDGFORMAT   _IOR(v, 2, int)
+
+/* Possible tag values */
+/*    mouse buttons: */
+#define MS_LEFT         0x7f20
+#define MS_MIDDLE       0x7f21
+#define MS_RIGHT        0x7f22
+/*    motion: */
+#define LOC_X_DELTA     0x7f80
+#define LOC_Y_DELTA     0x7f81
+#define LOC_X_ABSOLUTE  0x7f82  /* X compat, unsupported */
+#define LOC_Y_ABSOLUTE  0x7f83  /* X compat, unsupported */
+
+#define VKEY_UP   0
+#define VKEY_DOWN 1
index a43712a70b49ca21e28221f4cea13271a3c92704..1359f5c634e43012c50ddaad329cddc03deb7739 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: winmacro.h,v 1.11 1995/11/25 02:33:23 davem Exp $
+/* $Id: winmacro.h,v 1.13 1995/12/29 21:48:04 davem Exp $
  * winmacro.h: Window loading-unloading macros.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 
 /* Loading and storing struct pt_reg trap frames. */
 #define LOAD_PT_INS(base_reg) \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_I0], %i0; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_I2], %i2; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_I4], %i4; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_I6], %i6;
+        ldd     [%base_reg + REGWIN_SZ + PT_I0], %i0; \
+        ldd     [%base_reg + REGWIN_SZ + PT_I2], %i2; \
+        ldd     [%base_reg + REGWIN_SZ + PT_I4], %i4; \
+        ldd     [%base_reg + REGWIN_SZ + PT_I6], %i6;
 
 #define LOAD_PT_GLOBALS(base_reg) \
-        ld      [%base_reg + STACKFRAME_SZ + PT_G1], %g1; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_G2], %g2; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_G4], %g4; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_G6], %g6;
+        ld      [%base_reg + REGWIN_SZ + PT_G1], %g1; \
+        ldd     [%base_reg + REGWIN_SZ + PT_G2], %g2; \
+        ldd     [%base_reg + REGWIN_SZ + PT_G4], %g4; \
+        ldd     [%base_reg + REGWIN_SZ + PT_G6], %g6;
 
 #define LOAD_PT_YREG(base_reg, scratch) \
-        ld      [%base_reg + STACKFRAME_SZ + PT_Y], %scratch; \
+        ld      [%base_reg + REGWIN_SZ + PT_Y], %scratch; \
         wr      %scratch, 0x0, %y;
 
 #define LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \
-        ld      [%base_reg + STACKFRAME_SZ + PT_PSR], %pt_psr; \
-        ld      [%base_reg + STACKFRAME_SZ + PT_PC], %pt_pc; \
-        ld      [%base_reg + STACKFRAME_SZ + PT_NPC], %pt_npc;
+        ld      [%base_reg + REGWIN_SZ + PT_PSR], %pt_psr; \
+        ld      [%base_reg + REGWIN_SZ + PT_PC], %pt_pc; \
+        ld      [%base_reg + REGWIN_SZ + PT_NPC], %pt_npc;
 
 #define LOAD_PT_ALL(base_reg, pt_psr, pt_pc, pt_npc, scratch) \
         LOAD_PT_YREG(base_reg, scratch) \
         LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc)
 
 #define STORE_PT_INS(base_reg) \
-        std     %i0, [%base_reg + STACKFRAME_SZ + PT_I0]; \
-        std     %i2, [%base_reg + STACKFRAME_SZ + PT_I2]; \
-        std     %i4, [%base_reg + STACKFRAME_SZ + PT_I4]; \
-        std     %i6, [%base_reg + STACKFRAME_SZ + PT_I6];
+        std     %i0, [%base_reg + REGWIN_SZ + PT_I0]; \
+        std     %i2, [%base_reg + REGWIN_SZ + PT_I2]; \
+        std     %i4, [%base_reg + REGWIN_SZ + PT_I4]; \
+        std     %i6, [%base_reg + REGWIN_SZ + PT_I6];
 
 #define STORE_PT_GLOBALS(base_reg) \
-        st      %g1, [%base_reg + STACKFRAME_SZ + PT_G1]; \
-        std     %g2, [%base_reg + STACKFRAME_SZ + PT_G2]; \
-        std     %g4, [%base_reg + STACKFRAME_SZ + PT_G4]; \
-        std     %g6, [%base_reg + STACKFRAME_SZ + PT_G6];
+        st      %g1, [%base_reg + REGWIN_SZ + PT_G1]; \
+        std     %g2, [%base_reg + REGWIN_SZ + PT_G2]; \
+        std     %g4, [%base_reg + REGWIN_SZ + PT_G4]; \
+        std     %g6, [%base_reg + REGWIN_SZ + PT_G6];
 
 #define STORE_PT_YREG(base_reg, scratch) \
         rd      %y, %scratch; \
-        st      %scratch, [%base_reg + STACKFRAME_SZ + PT_Y];
+        st      %scratch, [%base_reg + REGWIN_SZ + PT_Y];
 
-#define STORE_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc, pt_wim) \
-        st      %pt_psr, [%base_reg + STACKFRAME_SZ + PT_PSR]; \
-        st      %pt_pc, [%base_reg + STACKFRAME_SZ + PT_PC]; \
-        st      %pt_npc, [%base_reg + STACKFRAME_SZ + PT_NPC]; \
-        st      %pt_wim, [%base_reg + STACKFRAME_SZ + PT_WIM];
+#define STORE_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \
+        st      %pt_psr, [%base_reg + REGWIN_SZ + PT_PSR]; \
+        st      %pt_pc,  [%base_reg + REGWIN_SZ + PT_PC]; \
+        st      %pt_npc, [%base_reg + REGWIN_SZ + PT_NPC];
 
-#define STORE_PT_ALL(base_reg, reg_psr, reg_pc, reg_npc, reg_wim, g_scratch) \
-        STORE_PT_PRIV(base_reg, reg_psr, reg_pc, reg_npc, reg_wim) \
+#define STORE_PT_ALL(base_reg, reg_psr, reg_pc, reg_npc, g_scratch) \
+        STORE_PT_PRIV(base_reg, reg_psr, reg_pc, reg_npc) \
         STORE_PT_GLOBALS(base_reg) \
         STORE_PT_YREG(base_reg, g_scratch) \
         STORE_PT_INS(base_reg)
         st       %scratch, [%cur_reg + THREAD_W_SAVED];
 
 /* For now on a uniprocessor this is ok. */
-#define LOAD_CURRENT(dest_reg) \
+#ifdef __SMP__
+#error SMP not yet
+#define LOAD_CURRENT(dest_reg, idreg) \
+        rd       %tbr, %idreg; \
+        srl      %idreg, 24, %idreg; \
+       sethi    %hi(C_LABEL(current_set)), %dest_reg; \
+       or       %dest_reg, %lo(C_LABEL(current_set)), %dest_reg; \
+       add      %dest_reg, %idreg, %dest_reg;
+#else
+#define LOAD_CURRENT(dest_reg, idreg) \
         sethi    %hi(C_LABEL(current_set)), %dest_reg; \
         ld       [%dest_reg + %lo(C_LABEL(current_set))], %dest_reg;
+#endif
 
 #endif /* !(_SPARC_WINMACRO_H) */
index 0d1c403a6b4c9e0356ad752eada6aab39ae015c1..8dee275dce6b0bcb358caa533f341a1000b3593c 100644 (file)
@@ -23,6 +23,7 @@ struct linux_binprm{
        int argc, envc;
        char * filename;        /* Name of binary */
        unsigned long loader, exec;
+       int dont_iput;          /* binfmt handler has put inode */
 };
 
 /*
@@ -39,6 +40,7 @@ struct linux_binfmt {
 
 extern int register_binfmt(struct linux_binfmt *);
 extern int unregister_binfmt(struct linux_binfmt *);
+extern struct linux_binfmt * get_binfmt_list(void);
 
 extern int read_exec(struct inode *inode, unsigned long offset,
        char * addr, unsigned long count, int to_kmem);
@@ -47,10 +49,12 @@ extern int open_inode(struct inode * inode, int mode);
 
 extern int init_elf_binfmt(void);
 extern int init_aout_binfmt(void);
+extern int init_script_binfmt(void);
 
+extern int prepare_binprm(struct linux_binprm *);
+extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
 extern void flush_old_exec(struct linux_binprm * bprm);
-extern unsigned long setup_arg_pages(unsigned long text_size,unsigned long * page);
-extern unsigned long * create_tables(char * p,struct linux_binprm * bprm,int ibcs);
+extern unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm);
 extern unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
                unsigned long p, int from_kmem);
 
index b18a04c3376e4a8074429f03c7d1487b283610c9..5896ab00e926bfd50de659fdffc38bcf80531595 100644 (file)
@@ -15,14 +15,10 @@ struct irqaction {
 };
 
 
-struct bh_struct {
-       void (*routine)(void *);
-       void *data;
-};
-
+extern int bh_mask_count[32];
 extern unsigned long bh_active;
 extern unsigned long bh_mask;
-extern struct bh_struct bh_base[32];
+extern void (*bh_base[32])(void);
 
 asmlinkage void do_bottom_half(void);
 
@@ -41,21 +37,38 @@ enum {
        CM206_BH
 };
 
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+       bh_base[nr] = routine;
+       bh_mask_count[nr] = 0;
+       bh_mask |= 1 << nr;
+}
+
 extern inline void mark_bh(int nr)
 {
        set_bit(nr, &bh_active);
 }
 
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
 extern inline void disable_bh(int nr)
 {
-       clear_bit(nr, &bh_mask);
+       bh_mask &= ~(1 << nr);
+       bh_mask_count[nr]++;
 }
 
 extern inline void enable_bh(int nr)
 {
-       set_bit(nr, &bh_mask);
+       if (!--bh_mask_count[nr])
+               bh_mask |= 1 << nr;
 }
 
+/*
+ * start_bh_atomic/end_bh_atomic also nest
+ * naturally by using a counter
+ */
 extern inline void start_bh_atomic(void)
 {
        intr_count++;
diff --git a/include/linux/loop.h b/include/linux/loop.h
new file mode 100644 (file)
index 0000000..3724bb0
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _LINUX_LOOP_H
+#define _LINUX_LOOP_H
+
+/*
+ * include/linux/loop.h
+ *
+ * Written by Theodore Ts'o, 3/29/93.
+ *
+ * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
+ * permitted under the GNU Public License.
+ */
+
+#define LO_NAME_SIZE   64
+#define LO_KEY_SIZE    32
+       
+struct loop_device {
+       int             lo_number;
+       struct inode    *lo_inode;
+       int             lo_refcnt;
+       kdev_t          lo_device;
+       int             lo_offset;
+       int             lo_encrypt_type;
+       int             lo_encrypt_key_size;
+       int             lo_flags;
+       int             (*transfer)(struct loop_device *, int cmd,
+                                   char *raw_buf, char *loop_buf, int size);
+       char            lo_name[LO_NAME_SIZE];
+       char            lo_encrypt_key[LO_KEY_SIZE];
+#ifdef DES_AVAILABLE
+       des_key_schedule lo_des_key;
+       unsigned long   lo_des_init[2];
+#endif
+};
+
+typedef        int (* transfer_proc_t)(struct loop_device *, int cmd,
+                               char *raw_buf, char *loop_buf, int size);
+
+/*
+ * Loop flags
+ */
+#define LO_FLAGS_DO_BMAP       0x00000001
+
+struct loop_info {
+       int             lo_number;      /* ioctl r/o */
+       dev_t           lo_device;      /* ioctl r/o */
+       unsigned long   lo_inode;       /* ioctl r/o */
+       dev_t           lo_rdevice;     /* ioctl r/o */
+       int             lo_offset;
+       int             lo_encrypt_type;
+       int             lo_encrypt_key_size;    /* ioctl w/o */
+       int             lo_flags;       /* ioctl r/o */
+       char            lo_name[LO_NAME_SIZE];
+       unsigned char   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+       unsigned long   lo_init[2];
+       char            reserved[4];
+};
+
+/*
+ * Loop encryption types --- LO_CRYPT_IDEA isn't supported yet
+ */
+
+#define LO_CRYPT_NONE  0
+#define LO_CRYPT_XOR   1
+#define LO_CRYPT_DES   2
+#define LO_CRYPT_IDEA  3
+#define MAX_LO_CRYPT   4
+
+/*
+ * IOCTL commands --- we will commandeer 0x4C ('L')
+ */
+
+#define LOOP_SET_FD    0x4C00
+#define LOOP_CLR_FD    0x4C01
+#define LOOP_SET_STATUS        0x4C02
+#define LOOP_GET_STATUS        0x4C03
+
+#endif
index b5b4831676d804a49f93ae0d904a3fbf92907fac..e093056647a4e97fa610d2287b04c2e4227d9486 100644 (file)
@@ -2,7 +2,8 @@
 #define _LINUX_MAJOR_H
 
 /*
- * This file has definitions for major device numbers
+ * This file has definitions for major device numbers.
+ * For the device number assignments, see Documentation/devices.txt.
  */
 
 /* limits */
 #define MAX_CHRDEV 64
 #define MAX_BLKDEV 64
 
-/*
- * assignments
- *
- * devices are as follows (same as minix, so we can use the minix fs):
- *
- *      character              block                  comments
- *      --------------------   --------------------   --------------------
- *  0 - unnamed                unnamed                minor 0 = true nodev
- *  1 - /dev/mem               ramdisk
- *  2 - /dev/ptyp*             floppy
- *  3 - /dev/ttyp*             ide0 or hd
- *  4 - /dev/tty*
- *  5 - /dev/tty; /dev/cua*
- *  6 - lp
- *  7 - /dev/vcs*
- *  8 -                        scsi disk
- *  9 - scsi tape              multiple devices driver
- * 10 - mice
- * 11 -                        scsi cdrom
- * 12 - qic02 tape
- * 13 -                        xt disk
- * 14 - sound card
- * 15 -                        cdu31a cdrom
- * 16 - sockets                goldstar cdrom
- * 17 - af_unix                optics cdrom
- * 18 - af_inet                sanyo cdrom
- * 19 - cyclades /dev/ttyC*
- * 20 - cyclades /dev/cub*     mitsumi (mcdx) cdrom
- * 21 - scsi generic
- * 22 -                        ide1
- * 23 -                        mitsumi cdrom
- * 24 -                               sony535 cdrom
- * 25 -                        matsushita cdrom       minors 0..3
- * 26 -                        matsushita cdrom 2     minors 0..3
- * 27 - qic117 tape            matsushita cdrom 3     minors 0..3
- * 28 -                        matsushita cdrom 4     minors 0..3
- * 29 -                        aztech/orchid/okano/wearnes cdrom
- * 32 -                        philips/lms cm206 cdrom
- * 33 -                        ide2
- * 34 - z8530 driver           ide3
- * 36 - netlink
- */
-
 #define UNNAMED_MAJOR  0
 #define MEM_MAJOR      1
 #define RAMDISK_MAJOR  1
@@ -65,6 +23,7 @@
 #define TTYAUX_MAJOR   5
 #define LP_MAJOR       6
 #define VCS_MAJOR      7
+#define LOOP_MAJOR     7
 #define SCSI_DISK_MAJOR        8
 #define SCSI_TAPE_MAJOR        9
 #define MD_MAJOR        9
index b5e848482d2ad969f71200b570d14cd4318b3719..603dcd04048fe4a3d351112fb7da8debbb7c4060 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Definitions for the Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.5a
+ * VERSION: 1.7
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
  *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
+ *  Andreas Kies (testing the mysterious hang up's)
  *  ... somebody forgotten?
  *  
  */
 #define MCDX "mcdx"    
 
 #if MCDX_QUIET == 1
-#define INFO(x)
+#define INFO(x)  
+#define WARN(x) warn x
 #else
 #define INFO(x) warn x
+#define WARN(x) warn x
 #endif
 
-#define WARN(x) warn x
 
 #if MCDX_DEBUG == 1
 #define TRACE(x) trace x
 #define OPENCLOSE      0
 #define HW                 0
 #define TALK           0
-#define IRQ            1
+#define IRQ            0
 #define TRANSFER       0
 #define REQUEST                0
+#define SLEEP          0
 #else
 #define TRACE(x)
 #endif
 #define MCDX_IO_SIZE           4
 
 /*
- *     The Ports & bits
+ *     Bits
  */
 
-#define MCDX_RBIT_OPEN       0x80
-#define MCDX_RBIT_DISKSET    0x40
-#define MCDX_RBIT_CHANGED    0x20
-#define MCDX_RBIT_CHECK      0x10
-#define MCDX_RBIT_AUDIOTR    0x08
-#define MCDX_RBIT_RDERR      0x04
-#define MCDX_RBIT_AUDIOBS    0x02
-#define MCDX_RBIT_CMDERR     0x01
-#define MCDX_RBIT_DOOR       0x10
-#define MCDX_RBIT_STEN       0x04
-#define MCDX_RBIT_DTEN       0x02
-
+/* The status byte, returned from every command, set if
+ * the description is true */
+#define MCDX_RBIT_OPEN       0x80      /* door is open */
+#define MCDX_RBIT_DISKSET    0x40      /* disk set (recognised) */
+#define MCDX_RBIT_CHANGED    0x20      /* disk was changed */
+#define MCDX_RBIT_CHECK      0x10      /* disk rotates, servo is on */
+#define MCDX_RBIT_AUDIOTR    0x08   /* current track is audio */
+#define MCDX_RBIT_RDERR      0x04      /* read error, refer SENSE KEY */
+#define MCDX_RBIT_AUDIOBS    0x02      /* currently playing audio */
+#define MCDX_RBIT_CMDERR     0x01      /* command, param or format error */
+
+/* The I/O Register holding the h/w status of the drive,
+ * can be read at i/o base + 1 */
+#define MCDX_RBIT_DOOR       0x10      /* door is open */
+#define MCDX_RBIT_STEN       0x04      /* if 0, i/o base contains drive status */
+#define MCDX_RBIT_DTEN       0x02      /* if 0, i/o base contains data */
 
 /*
  *     The commands.
  * Errors
  */
 #define MCDX_E         1                       /* unspec error */
-#define MCDX_EOM       2                       /* end of media */
+#define MCDX_ST_EOM 0x0100             /* end of media */
+#define MCDX_ST_DRV 0x00ff             /* mask to query the drive status */
 
 #ifndef I_WAS_HERE
 #warning You have not edited mcdx.h
 #warning Perhaps irq and i/o settings are wrong.
 #endif
+
+/* ex:set ts=4 sw=4: */
index 8bece08c0e7266687e3cce9b7c8adfd870ee0ea0..837eca9d27ad4c5a79cc7db9e2dfa6e6cbafe335 100644 (file)
@@ -148,153 +148,3 @@ extern int unregister_md_personality (int p_num);
 
 #endif __KERNEL__
 #endif _MD_H
-
-/*
-   md.h : Multiple Devices driver for Linux
-          Copyright (C) 1994, 1995 Marc ZYNGIER
-         <zyngier@amertume.ufr-info-p7.ibp.fr> or
-         <maz@gloups.fdn.fr>
-         
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-*/
-
-#ifndef _MD_H
-#define _MD_H
-
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/ioctl.h>
-
-#define MD_VERSION "0.33"
-
-/* ioctls */
-#define REGISTER_DEV _IO (MD_MAJOR, 1)
-#define START_MD     _IO (MD_MAJOR, 2)
-#define STOP_MD      _IO (MD_MAJOR, 3)
-#define MD_INVALID   _IO (MD_MAJOR, 4)
-#define MD_VALID     _IO (MD_MAJOR, 5)
-
-/*
-   personalities :
-   Byte 0 : Chunk size factor
-   Byte 1 : Fault tolerance count for each physical device
-            (   0 means no fault tolerance,
-             0xFF means always tolerate faults)
-   Byte 2 : Personality
-   Byte 3 : Reserved.
- */
-
-#define FAULT_SHIFT       8
-#define PERSONALITY_SHIFT 16
-
-#define FACTOR_MASK       0xFFUL
-#define FAULT_MASK        0xFF00UL
-#define PERSONALITY_MASK  0xFF0000UL
-
-#define MD_RESERVED       0    /* Not used by now */
-#define LINEAR            (1UL << PERSONALITY_SHIFT)
-#define STRIPED           (2UL << PERSONALITY_SHIFT)
-#define STRIPPED          STRIPED /* Long lasting spelling mistake... */
-#define RAID0             STRIPED
-#define RAID1             (3UL << PERSONALITY_SHIFT)
-#define RAID5             (4UL << PERSONALITY_SHIFT)
-#define MAX_PERSONALITY   5
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <sys/types.h>
-#include <linux/fs.h>
-#include <linux/blkdev.h>
-
-#undef MD_COUNT_SIZE           /* Define this to have stats about
-                                  chunk size in /proc/mdstat */
-#define MAX_REAL     8         /* Max number of physical dev per md dev */
-#define MAX_MD_DEV   4         /* Max number of md dev */
-
-#define FACTOR(a)         ((a)->repartition & FACTOR_MASK)
-#define MAX_FAULT(a)      (((a)->repartition & FAULT_MASK)>>8)
-#define PERSONALITY(a)    ((a)->repartition & PERSONALITY_MASK)
-
-#define FACTOR_SHIFT(a) (PAGE_SHIFT + (a) - 10)
-
-/* Invalidation modes */
-#define VALID          0
-#define INVALID_NEXT   1
-#define INVALID_ALWAYS 2
-#define INVALID        3       /* Only useful to md_valid_device */
-
-/* Return values from personalities to md driver */
-#define REDIRECTED_BHREQ 0 /* Redirected individual buffers
-                             (shouldn't be used anymore since 0.31) */
-#define REDIRECTED_REQ   1 /* Redirected whole request */
-#define REDIRECT_FAILED -1 /* For RAID-1 */
-
-struct real_dev
-{
-  kdev_t dev;                  /* Device number */
-  int size;                    /* Device size (in blocks) */
-  int offset;                  /* Real device offset (in blocks) in md dev
-                                  (only used in linear mode) */
-  struct inode *inode;         /* Lock inode */
-  int fault_count;             /* Fault counter for invalidation */
-  int invalid;                 /* Indicate if the device is disabled :
-                                  VALID          - valid
-                                  INVALID_NEXT   - disabled for next access
-                                  INVALID_ALWAYS - permanently disabled
-                                  (for redundancy modes only) */
-};
-
-struct md_dev;
-
-struct md_personality
-{
-  char *name;
-  int (*map)(int minor, struct md_dev *md_dev, struct request *req);
-  int (*run)(int minor, struct md_dev *md_dev);
-  int (*stop)(int minor, struct md_dev *md_dev);
-  int (*status)(char *page, int minor, struct md_dev *md_dev);
-  int (*ioctl)(struct inode *inode, struct file *file,
-              unsigned int cmd, unsigned long arg);
-  int max_invalid_dev;
-};
-
-struct md_dev
-{
-  struct md_personality *pers;
-  int repartition;
-  int invalid_dev_count;
-  int busy;
-  int nb_dev;
-  void *private;
-#ifdef MD_COUNT_SIZE
-  unsigned int smallest_count;
-  unsigned int biggest_count;
-  unsigned int equal_count;
-#endif
-};
-
-extern struct real_dev devices[MAX_MD_DEV][MAX_REAL];
-extern struct md_dev md_dev[MAX_MD_DEV];
-extern int md_size[MAX_MD_DEV];
-
-extern void make_md_request(struct request *pending, int n);
-extern char *partition_name (kdev_t dev);
-
-#if defined(CONFIG_MD_SUPPORT_RAID1) || defined(CONFIG_MD_SUPPORT_RAID5)
-extern int md_valid_device (int minor, kdev_t dev, int mode);
-extern int md_can_reemit (int minor);
-#endif
-
-extern int register_md_personality (int p_num, struct md_personality *p);
-extern int unregister_md_personality (int p_num);
-
-#endif __KERNEL__
-#endif _MD_H
index 895c5ae4a248fd89836ce98c21fcf72364902233..ab3f65393365792cdec9a3a8afdec225dbc8c5d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  ncp_fs.h
+ *  ncp.h
  *
  *  Copyright (C) 1995 by Volker Lendecke
  *
index d53cd7f2cceeb0e3e685016c3d3d7b88ef009161..4db2ca25dee8bb346a616882528d2fc90af7beb5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  ncp_fs.h
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -42,6 +42,7 @@ struct ncp_fs_info {
 
 #define        NCP_IOC_NCPREQUEST              _IOR('n', 1, unsigned char *)
 #define        NCP_IOC_GETMOUNTUID             _IOR('u', 1, uid_t)
+#define NCP_IOC_CONN_LOGGED_IN          _IO('l', 1)
 
 #define NCP_GET_FS_INFO_VERSION (1)
 #define NCP_IOC_GET_FS_INFO             _IOWR('i', 1, unsigned char *)
@@ -128,10 +129,11 @@ extern struct inode_operations ncp_dir_inode_operations;
 void ncp_free_inode_info(struct ncp_inode_info *i);
 void ncp_free_all_inodes(struct ncp_server *server);
 void ncp_init_root(struct ncp_server *server);
-int  ncp_stat_root(struct ncp_server *server);
+int  ncp_conn_logged_in(struct ncp_server *server);
 void ncp_init_dir_cache(void);
-void ncp_invalid_dir_cache(unsigned long ino);
-void ncp_invalidate_all_inodes(struct ncp_server *server);
+void ncp_invalid_dir_cache(struct inode *ino);
+struct ncp_inode_info *ncp_find_inode(struct inode *inode);
+ino_t ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info);
 void ncp_free_dir_cache(void);
 int  ncp_date_dos2unix(__u16 time, __u16 date);
 void ncp_date_unix2dos(int unix_date, __u16 *time, __u16 *date);
@@ -145,8 +147,6 @@ int ncp_ioctl (struct inode * inode, struct file * filp,
 struct super_block *ncp_read_super(struct super_block *sb,
                                    void *raw_data, int silent);
 extern int init_ncp_fs(void);
-void ncp_invalidate_connection(struct ncp_server *server);
-int ncp_conn_is_valid(struct ncp_server *server);
 void ncp_trigger_message(struct ncp_server *server);
 
 /* linux/fs/ncpfs/sock.c */
index 763d80c98f065d9caefa61ef0cc36f8a269308ae..02ad1b4522c6f7aafc7f6d492e72414720f9e646 100644 (file)
@@ -28,6 +28,7 @@ struct ncp_inode_info {
                                    number of references in memory */
         struct ncp_inode_info *dir;
         struct ncp_inode_info *next, *prev;
+       struct inode *inode;
        struct nw_file_info finfo;
 };
 
index 0a5497e369ae466e497640d6f8f423e3b9559f42..9bea613f04c78ae75199652a50dec07f6c78b93a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  ncp_fs_sb.h
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
index 39d11b7d7d14f23e063690376b8df60d2edc8834..3de288659667945dc91b92beb4f731081ac54121 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  ncp_mount.h
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -26,7 +26,7 @@ struct ncp_mount_data {
        int version;
        unsigned int ncp_fd;    /* The socket to the ncp port */
        unsigned int wdog_fd;   /* Watchdog packets come here */
-       unsigned int message_fd; /* Not used yet, maybe for messages */
+       unsigned int message_fd; /* Message notifications come here */
         uid_t mounted_uid;      /* Who may umount() this filesystem? */
 
        struct sockaddr_ipx serv_addr;
index 56daca14ea6b3b406d341a3b79e1925cd27d29b4..4f54a48f3a879fd506826b236701c5df87b7c48b 100644 (file)
@@ -233,7 +233,7 @@ extern void         dev_queue_xmit(struct sk_buff *skb, struct device *dev,
 extern void            netif_rx(struct sk_buff *skb);
 extern void            dev_transmit(void);
 extern int             in_net_bh(void);
-extern void            net_bh(void *tmp);
+extern void            net_bh(void);
 extern void            dev_tint(struct device *dev);
 extern int             dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
 extern int             dev_ioctl(unsigned int cmd, void *);
index 3c1ca8eeb3b20203d65dd5b0a265d7fffd9eabc3..7644b22c004432f39187212b9c4419034fd6cb53 100644 (file)
@@ -33,8 +33,8 @@
 
 struct sk_buff_head 
 {
-       struct sk_buff  * volatile next;
-       struct sk_buff  * volatile prev;
+       struct sk_buff  * next;
+       struct sk_buff  * prev;
        __u32           qlen;           /* Must be same length as a pointer
                                           for using debugging */
 #if CONFIG_SKB_CHECK
@@ -45,8 +45,8 @@ struct sk_buff_head
 
 struct sk_buff 
 {
-       struct sk_buff  * volatile next;        /* Next buffer in list                          */
-       struct sk_buff  * volatile prev;        /* Previous buffer in list                      */
+       struct sk_buff  * next;                 /* Next buffer in list                          */
+       struct sk_buff  * prev;                 /* Previous buffer in list                      */
        struct sk_buff_head * list;             /* List we are on                               */
 #if CONFIG_SKB_CHECK
        int             magic_debug_cookie;
@@ -63,8 +63,8 @@ struct sk_buff
                struct iphdr    *iph;
                struct udphdr   *uh;
                unsigned char   *raw;
-               /* for passing an fd in a unix domain socket */
-               struct file *filp;
+               /* for passing file handles in a unix domain socket */
+               void *filp;
        } h;
   
        union 
@@ -161,6 +161,11 @@ extern int                 skb_tailroom(struct sk_buff *skb);
 extern void                    skb_reserve(struct sk_buff *skb, int len);
 extern void                    skb_trim(struct sk_buff *skb, int len);
 
+extern __inline__ int skb_queue_empty(struct sk_buff_head *list)
+{
+       return (list->next == (struct sk_buff *) list);
+}
+
 /*
  *     Peek an sk_buff. Unlike most other operations you _MUST_
  *     be careful with this one. A peek leaves the buffer on the
index bf2991adf644cad895d3f72b8e239254421d9685..cbb7e4b2b1d445e0876d3a9fcf7730d49c955178 100644 (file)
@@ -5,14 +5,15 @@
 #include <linux/sockios.h>             /* the SIOCxxx I/O controls     */
 #include <linux/uio.h>                 /* iovec support                */
 
-struct sockaddr {
-  unsigned short       sa_family;      /* address family, AF_xxx       */
-  char                 sa_data[14];    /* 14 bytes of protocol address */
+struct sockaddr 
+{
+       unsigned short  sa_family;      /* address family, AF_xxx       */
+       char            sa_data[14];    /* 14 bytes of protocol address */
 };
 
 struct linger {
-  int                  l_onoff;        /* Linger active                */
-  int                  l_linger;       /* How long to linger for       */
+       int             l_onoff;        /* Linger active                */
+       int             l_linger;       /* How long to linger for       */
 };
 
 struct msghdr 
@@ -25,6 +26,17 @@ struct msghdr
        int             msg_accrightslen;       /* Length of rights list */
 };
 
+/*
+ *     4.4BSD changed to these new names for no apparent reason.
+ */
+#define msg_control    msg_accrights   
+#define msg_controllen msg_accrightslen;       
+
+/* Control Messages */
+
+#define SCM_RIGHTS             1
+
 /* Socket types. */
 #define SOCK_STREAM    1               /* stream (connection) socket   */
 #define SOCK_DGRAM     2               /* datagram (conn.less) socket  */
@@ -73,6 +85,7 @@ struct msghdr
 #define MSG_OOB                1
 #define MSG_PEEK       2
 #define MSG_DONTROUTE  4
+/*#define MSG_CTRUNC   8       - We need to support this for BSD oddments */
 
 /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
 #define SOL_IP         0
index d483a155c20ba291a383c2eabb86cac2a1772ae8..8411c20993a33fc9d58959a83e1e57689b507e0d 100644 (file)
@@ -137,24 +137,20 @@ _INLINE_ void queue_task(struct tq_struct *bh_pointer,
  */
 _INLINE_ void run_task_queue(task_queue *list)
 {
-       register struct tq_struct *save_p;
        register struct tq_struct *p;
-       void *arg;
-       void (*f) (void *);
-
-       while(1) {
-               p = xchg(list,&tq_last);
-               if(p == &tq_last)
-                       break;
-
-               do {
-                       arg    = p -> data;
-                       f      = p -> routine;
-                       save_p = p -> next;
-                       p -> sync = 0;
-                       (*f)(arg);
-                       p = save_p;
-               } while(p != &tq_last);
+
+       p = xchg(list,&tq_last);
+
+       while (p != &tq_last) {
+               void *arg;
+               void (*f) (void *);
+               register struct tq_struct *save_p;
+               arg    = p -> data;
+               f      = p -> routine;
+               save_p = p;
+               p      = p -> next;
+               save_p -> sync = 0;
+               (*f)(arg);
        }
 }
 
index e11ad75fe0a21ecfb95bb7b7dd2b4955bbac633b..4428194ff914d29bcf2274cfbe257eb4c98db6da 100644 (file)
@@ -8,4 +8,11 @@ struct sockaddr_un {
        char sun_path[UNIX_PATH_MAX];   /* pathname */
 };
 
+struct cmsghdr {
+       unsigned int cmsg_len;
+       int cmsg_level;
+       int cmsg_type;
+       unsigned char cmsg_data[0];
+};
+
 #endif /* _LINUX_UN_H */
index dc4a48d6f548cda970387217a78d73b1a035a43f..d79ebcc09b1dd399f84de58ca89e3ecbe3f3f2e6 100644 (file)
@@ -2,3 +2,8 @@ extern void unix_proto_init(struct net_proto *pro);
 
 typedef struct sock unix_socket;
 
+extern int unix_gc_free;
+extern void unix_gc_add(struct sock *sk, struct file *fp);
+extern void unix_gc_remove(struct file *fp);
+
+#define UNIX_MAX_FD    8
index 45967cb191e653663c1a1a4ebd2cc85efd58cf6b..55080c45557a2aa9128fbe2bd4fe5032e01104ae 100644 (file)
@@ -38,7 +38,7 @@
 
 #define SSSID_SPARE    0x60    /* Unused bits in SSID for standard AX.25 */
 #define ESSID_SPARE    0x20    /* Unused bits in SSID for extended AX.25 */
-#define DAMA_FLAG      0x40    /* Well, it is *NOT* unused! (dl1bke 951121 */
+#define DAMA_FLAG      0x20    /* Well, it is *NOT* unused! (dl1bke 951121 */
 
 #define AX25_REPEATED  0x80
 
index e32af15b743c00b9ae54bba2c2ecdaec624a96be..b1412ea66a72a570841821eaa6066fc90181a4e4 100644 (file)
@@ -2,7 +2,8 @@
 #define __NET_NETLINK_H
 
 #define NET_MAJOR 36           /* Major 18 is reserved for networking                                          */
-#define MAX_LINKS 4            /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved      */
+#define MAX_LINKS 8            /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved      */
+                               /* 4-7 are psi0-psi3 */
 #define MAX_QBYTES 32768       /* Maximum bytes in the queue                                                   */
 
 #include <linux/config.h>
@@ -17,6 +18,7 @@ extern int init_netlink(void);
 #define NETLINK_SKIP           1       /* Reserved for ENskip                          */
 #define NETLINK_USERSOCK       2       /* Reserved for user mode socket protocols      */
 #define NETLINK_FIREWALL       3       /* Firewalling hook                             */
+#define NETLINK_PSI            4       /* PSI devices - 4 to 7 */
 
 #ifdef CONFIG_RTNETLINK
 extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *);
index f1c5e99adaf22c4b3f4539b0d39badd41343b742..04ad2f501ceb09e1dc7b031a71d7161946fbda11 100644 (file)
@@ -246,6 +246,9 @@ struct symbol_table symbol_table = {
        /* executable format registration */
        X(register_binfmt),
        X(unregister_binfmt),
+       X(get_binfmt_list),
+       X(search_binary_handler),
+       X(prepare_binprm),
 
        /* execution environment registration */
        X(lookup_exec_domain),
@@ -326,7 +329,6 @@ struct symbol_table symbol_table = {
        /* Program loader interfaces */
        X(setup_arg_pages),
        X(copy_strings),
-       X(create_tables),
        X(do_execve),
        X(flush_old_exec),
        X(open_inode),
index 55692441db25d3efce02cf291cd4c824dada339e..d5cc76e1a51e337eaa95b221be84130014001fb7 100644 (file)
@@ -30,11 +30,11 @@ static char buf[1024];
 extern void console_print(const char *);
 
 /* printk's without a loglevel use this.. */
-#define DEFAULT_MESSAGE_LOGLEVEL 5 /* KERN_NOTICE */
+#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 
-/* We show everything that is more important than this.. */
-#define MINIMUM_CONSOLE_LOGLEVEL 6 /* Minimum loglevel we let people use */
-#define DEFAULT_CONSOLE_LOGLEVEL 6 /* anything more serious than KERN_INFO */
+/* We show everything that is MORE important than this.. */
+#define MINIMUM_CONSOLE_LOGLEVEL 5 /* Minimum loglevel we let people use */
+#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_NOTICE */
 
 unsigned long log_size = 0;
 struct wait_queue * log_wait = NULL;
index 901677f4ca8cc662e2a1ae5de65ee36322a64d5e..eb559baa0fb75061eb4dfa854fd28a2a7b1a976d 100644 (file)
@@ -194,7 +194,7 @@ static void process_timeout(unsigned long __data)
  *        +ve: "goodness" value (the larger, the better)
  *      +1000: realtime process, select this.
  */
-static inline int goodness(struct task_struct * p, int this_cpu)
+static inline int goodness(struct task_struct * p, struct task_struct * prev, int this_cpu)
 {
        int weight;
 
@@ -230,7 +230,7 @@ static inline int goodness(struct task_struct * p, int this_cpu)
 #endif
 
                /* .. and a slight advantage to the current process */
-               if (p == current)
+               if (p == prev)
                        weight += 1;
        }
 
@@ -251,7 +251,7 @@ asmlinkage void schedule(void)
 {
        int c;
        struct task_struct * p;
-       struct task_struct * next;
+       struct task_struct * prev, * next;
        unsigned long timeout = 0;
        int this_cpu=smp_processor_id();
 
@@ -269,26 +269,27 @@ asmlinkage void schedule(void)
        run_task_queue(&tq_scheduler);
 
        need_resched = 0;
+       prev = current;
        cli();
        /* move an exhausted RR process to be last.. */
-       if (!current->counter && current->policy == SCHED_RR) {
-               current->counter = current->priority;
-               move_last_runqueue(current);
+       if (!prev->counter && prev->policy == SCHED_RR) {
+               prev->counter = prev->priority;
+               move_last_runqueue(prev);
        }
-       switch (current->state) {
+       switch (prev->state) {
                case TASK_INTERRUPTIBLE:
-                       if (current->signal & ~current->blocked)
+                       if (prev->signal & ~prev->blocked)
                                goto makerunnable;
-                       timeout = current->timeout;
+                       timeout = prev->timeout;
                        if (timeout && (timeout <= jiffies)) {
-                               current->timeout = 0;
+                               prev->timeout = 0;
                                timeout = 0;
                makerunnable:
-                               current->state = TASK_RUNNING;
+                               prev->state = TASK_RUNNING;
                                break;
                        }
                default:
-                       del_from_runqueue(current);
+                       del_from_runqueue(prev);
                case TASK_RUNNING:
        }
        p = init_task.next_run;
@@ -298,7 +299,7 @@ asmlinkage void schedule(void)
        /*
         *      This is safe as we do not permit re-entry of schedule()
         */
-       current->processor = NO_PROC_ID;        
+       prev->processor = NO_PROC_ID;   
 #endif 
 
 /*
@@ -310,7 +311,7 @@ asmlinkage void schedule(void)
        c = -1000;
        next = &init_task;
        while (p != &init_task) {
-               int weight = goodness(p, this_cpu);
+               int weight = goodness(p, prev, this_cpu);
                if (weight > c)
                        c = weight, next = p;
                p = p->next_run;
@@ -326,8 +327,8 @@ asmlinkage void schedule(void)
        /*
         *      Context switching between two idle threads is pointless.
         */
-       if(!current->pid && !next->pid)
-               next=current;
+       if(!prev->pid && !next->pid)
+               next=prev;
        /*
         *      Allocate process to CPU
         */
@@ -343,19 +344,19 @@ asmlinkage void schedule(void)
        else
                clear_bit(this_cpu,&smp_idle_map);
 #endif
-       if (current != next) {
+       if (prev != next) {
                struct timer_list timer;
 
                kstat.context_swtch++;
                if (timeout) {
                        init_timer(&timer);
                        timer.expires = timeout;
-                       timer.data = (unsigned long) current;
+                       timer.data = (unsigned long) prev;
                        timer.function = process_timeout;
                        add_timer(&timer);
                }
                get_mmu_context(next);
-               switch_to(next);
+               switch_to(prev,next);
                if (timeout)
                        del_timer(&timer);
        }
@@ -715,7 +716,7 @@ static void second_overflow(void)
 /*
  * disregard lost ticks for now.. We don't care enough.
  */
-static void timer_bh(void * unused)
+static void timer_bh(void)
 {
        unsigned long mask;
        struct timer_struct *tp;
@@ -747,12 +748,12 @@ static void timer_bh(void * unused)
        }
 }
 
-void tqueue_bh(void * unused)
+void tqueue_bh(void)
 {
        run_task_queue(&tq_timer);
 }
 
-void immediate_bh(void * unused)
+void immediate_bh(void)
 {
        run_task_queue(&tq_immediate);
 }
@@ -1290,10 +1291,7 @@ void sched_init(void)
 #ifdef __SMP__ 
        init_task.processor=cpu;
 #endif
-       bh_base[TIMER_BH].routine = timer_bh;
-       bh_base[TQUEUE_BH].routine = tqueue_bh;
-       bh_base[IMMEDIATE_BH].routine = immediate_bh;
-       enable_bh(TIMER_BH);
-       enable_bh(TQUEUE_BH);
-       enable_bh(IMMEDIATE_BH);
+       init_bh(TIMER_BH, timer_bh);
+       init_bh(TQUEUE_BH, tqueue_bh);
+       init_bh(IMMEDIATE_BH, immediate_bh);
 }
index 88a967d7faccd1b0fa8c92411dea27978d9ce654..a2ef3f308e6c19f80d230a252eb131c87a9b045f 100644 (file)
 
 unsigned long intr_count = 0;
 
+int bh_mask_count[32];
 unsigned long bh_active = 0;
 unsigned long bh_mask = 0;
-struct bh_struct bh_base[32];
+void (*bh_base[32])(void);
 
 
 asmlinkage void do_bottom_half(void)
 {
        unsigned long active;
        unsigned long mask, left;
-       struct bh_struct *bh;
+       void (**bh)(void);
 
        bh = bh_base;
        active = bh_active & bh_mask;
        for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) {
                if (mask & active) {
-                       void (*fn)(void *);
+                       void (*fn)(void);
                        bh_active &= ~mask;
-                       fn = bh->routine;
+                       fn = *bh;
                        if (!fn)
                                goto bad_bh;
-                       fn(bh->data);
+                       fn();
                }
        }
        return;
index c1d762b47a4cca1aaa9964360778143c6d9f35c2..72cd486b05690a40123d31cdb24de9eb2e0fca9a 100644 (file)
@@ -19,7 +19,7 @@
 #include <asm/system.h>
 #include <asm/dma.h>
 
-/* Define this is you want slow routines that try to trip errors */
+/* Define this if you want slow routines that try to trip errors */
 #undef SADISTIC_KMALLOC
 
 /* Private flags. */
@@ -89,8 +89,8 @@ struct size_descriptor {
 };
 
 /*
- * For now it is unsafe to allocate bucket sizes between n and n-16 where n is
- * 4096 * any power of two
+ * For now it is unsafe to allocate bucket sizes between n and
+ * n-sizeof(page_descriptor) where n is PAGE_SIZE * any power of two
  */
 #if PAGE_SIZE == 4096
 struct size_descriptor sizes[] =
index d3615016f0976783b71cbc83984de267bb28f983..026edf1db48cc67d61d71b82e7e174646344f69f 100644 (file)
@@ -348,7 +348,7 @@ unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, a
        }
                
        if (dama != NULL) 
-               *dama = !(buf[13] & DAMA_FLAG);
+               *dama = ~(buf[13] & DAMA_FLAG);
                
        /* Copy to, from */
        if (dest != NULL) 
index 186530b345074203c4cb2a92a36eef7bc0832840..f54b7880089cc37fa453a98da646dd0eadeaf2a9 100644 (file)
@@ -216,10 +216,10 @@ struct device *dev_get(const char *name)
 
 extern __inline__ void dev_load(const char *name)
 {
-        const char *sptr;
         if(!dev_get(name)) {
 #ifdef CONFIG_NET_ALIAS
+               const char *sptr;
                 for (sptr=name ; *sptr ; sptr++) if(*sptr==':') break;
                 if (!(*sptr && *(sptr+1)))
 #endif
@@ -557,7 +557,7 @@ int in_net_bh()     /* Used by timer.c */
  *     mark_bh(NET_BH);
  */
  
-void net_bh(void *tmp)
+void net_bh(void)
 {
        struct sk_buff *skb;
        struct packet_type *ptype;
@@ -728,9 +728,11 @@ void dev_tint(struct device *dev)
         */      
        for(i = 0;i < DEV_NUMBUFFS; i++,head++)
        {
-               struct sk_buff *skb = skb_peek(head);
 
-               if (skb) {
+               while (!skb_queue_empty(head)) {
+                       struct sk_buff *skb;
+
+                       skb = head->next;
                        __skb_unlink(skb, head);
                        /*
                         *      Stop anyone freeing the buffer while we retransmit it
@@ -1408,7 +1410,6 @@ int net_dev_init(void)
        net_alias_init();
 #endif
 
-       bh_base[NET_BH].routine = net_bh;
-       enable_bh(NET_BH);
+       init_bh(NET_BH, net_bh);
        return 0;
 }
index 56df49c390c032af1eb01fcc68b650cf3530d851..3d64f58ec2fcdb15eb1f599b2344804df6c09de7 100644 (file)
@@ -541,29 +541,18 @@ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigne
 void __release_sock(struct sock *sk)
 {
 #ifdef CONFIG_INET
-       struct sk_buff *skb;
-
-       if (!sk->prot)
+       if (!sk->prot || !sk->prot->rcv)
                return;
                
-       /*
-        *      This is only ever called from a user process context, hence
-        *      (until fine grained SMP) its safe. sk->users must be volatile
-        *      so the compiler doesn't do anything unfortunate with it.
-        *
-        *      The "barrier()" stuff takes care of that. Note that the rcv
-        *      function may not sleep, so "users" is not going to change there.
-        */
-
        /* See if we have any packets built up. */
        start_bh_atomic();
-       while ((skb = __skb_dequeue(&sk->back_log)) != NULL) 
-       {
-               if (sk->prot->rcv) 
-                       sk->prot->rcv(skb, skb->dev, (struct options*)skb->proto_priv,
-                                skb->saddr, skb->len, skb->daddr, 1,
-                               /* Only used for/by raw sockets. */
-                               (struct inet_protocol *)sk->pair); 
+       while (!skb_queue_empty(&sk->back_log)) {
+               struct sk_buff * skb = sk->back_log.next;
+               __skb_unlink(skb, &sk->back_log);
+               sk->prot->rcv(skb, skb->dev, (struct options*)skb->proto_priv,
+                             skb->saddr, skb->len, skb->daddr, 1,
+                             /* Only used for/by raw sockets. */
+                             (struct inet_protocol *)sk->pair); 
        }
        end_bh_atomic();
 #endif  
index e2e7ff61fd93cc0204b8bdc5d7b8e5025fa7a874..0e11aceb61df2c5cdf9efe384779cd61a6a6333d 100644 (file)
@@ -1390,9 +1390,10 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy
                        if (pos <= offset)
                                len=0;
                        if (pos >= offset+length)
-                               break;
+                               goto done;
                }
        }
+done:
        arp_unlock();
   
        *start = buffer+len-(pos-offset);       /* Start of wanted data */
index d77b280cf8208698bce9c1465547bc1493d5621f..047c0571f128121d8e72aa492ac6e65303278810 100644 (file)
@@ -1625,10 +1625,12 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                skb->saddr = daddr;
                skb->daddr = saddr;
 
-               /* We may need to add it to the backlog here. */
+               /*
+                * We may need to add it to the backlog here. 
+                */
                if (sk->users) 
                {
-                       skb_queue_tail(&sk->back_log, skb);
+                       __skb_queue_tail(&sk->back_log, skb);
                        return(0);
                }
        }
index 37097b82a6250ab8f6fef9b84f393260333540ea..8d557ab305ba2e94ae812bea28b87e88d77700f5 100644 (file)
@@ -1087,7 +1087,7 @@ ipxrtr_add_route(unsigned long network, ipx_interface *intrfc, unsigned char *no
                ipx_routes=rt;
        }
        else if (intrfc == ipx_internal_net)
-               return(-EINVAL);
+               return(-EEXIST);
 
        rt->ir_net = network;
        rt->ir_intrfc = intrfc;
index fcfb2df73e7bb48bf43d93aad40bc9bc2cb43171..93f06ccbff96839dd687f074c234a90220020197 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/net.h>
-
+#include <linux/fs.h>
 
 #define CONFIG_UNIX            /* always present...    */
 
index 6417647c6c5749e9c65723883630f0546efe8f00..22aa00ce8205af7f0fe4bab8fcebbeb66dee1264 100644 (file)
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := unix.o
-O_OBJS  := af_unix.o
+O_OBJS  := af_unix.o garbage.o
 
 include $(TOPDIR)/Rules.make
 
index 536027232137575be8289f921bb7da1d6af9465b..1a0b714cca08bfb7eea4acc1bc742cc284ddb9ee 100644 (file)
@@ -21,6 +21,9 @@
  *             Alan Cox        :       Fixed the stupid socketpair bug.
  *             Alan Cox        :       BSD compatibility fine tuning.
  *             Alan Cox        :       Fixed a bug in connect when interrupted.
+ *             Alan Cox        :       Sorted out a proper draft version of
+ *                                     file descriptor passing hacked up from
+ *                                     Mike Shaver's work.
  *
  *
  * Known differences from reference BSD that was tested:
@@ -273,7 +276,6 @@ static void def_callback3(struct sock *sk)
 static int unix_create(struct socket *sock, int protocol)
 {
        unix_socket *sk;
-/*     printk("Unix create\n");*/
        if(protocol && protocol != PF_UNIX)
                return -EPROTONOSUPPORT;
        sk=(unix_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
@@ -682,9 +684,194 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_
        return 0;
 }
 
-/* if msg->accrights != NULL, we have fds to pass.
- * Current implementation passes at most one fd.
+/*
+ *     Support routines for struct cmsghdr handling
+ */
+static struct cmsghdr *unix_copyrights(void *userp, int len)
+{
+       struct cmsghdr *cm;
+       if(len>256|| len <=0)
+               return NULL;
+       cm=kmalloc(len, GFP_KERNEL);
+       memcpy_fromfs(cm, userp, len);
+       return cm;
+}
+
+/*
+ *     Return a header block
+ */
+static void unix_returnrights(void *userp, int len, struct cmsghdr *cm)
+{
+       memcpy_tofs(userp, cm, len);
+       kfree(cm);
+}
+
+/*
+ *     Copy file descriptors into system space.
+ */
+static int unix_fd_copy(struct sock *sk, struct cmsghdr *cmsg, struct file **fp)
+{
+       int num=cmsg->cmsg_len-sizeof(struct cmsghdr);
+       int i;
+       int *fdp=(int *)cmsg->cmsg_data;
+       num/=4; /* Odd bytes are forgotten in BSD not errored */
+       
+       if(num>=UNIX_MAX_FD)
+               return -EINVAL;
+       
+       /*
+        *      Verify the descriptors.
+        */
+        
+       for(i=0;i<=num;i++)
+       {
+               if(fdp[i]<0||fdp[i]>=NR_OPEN)
+                       return -EINVAL;
+               if(current->files->fd[fdp[i]]==NULL)
+                       return -EBADF;
+       }
+       
+       /*
+        *      Make sure the garbage collector can cope.
+        */
+        
+       if(unix_gc_free<num)
+               return -ENOBUFS;
+       
+       for(i=0;i<=num;i++)
+       {
+               fp[i]=current->files->fd[fdp[i]];
+               fp[i]->f_count++;
+               unix_gc_add(sk, fp[i]);
+       }
+       
+       return num;
+}
+
+/*
+ *     Free the descriptors in the array
+ */
+
+static void unix_fd_free(struct sock *sk, struct file **fp, int num)
+{
+       int i;
+       for(i=0;i<num;i++)
+       {
+               close_fp(fp[i]);
+               unix_gc_remove(fp[i]);
+       }
+}
+
+/*
+ *     Count the free descriptors available to a process. 
+ *     Interpretation issue: Is the limit the highest descriptor (buggy
+ *     allowing passed fd's higher up to cause a limit to be exceeded) -
+ *     but how the old code did it - or like this...
+ */
+
+int unix_files_free(void)
+{
+       int i;
+       int n=0;
+       for (i=0;i<NR_OPEN;i++)
+       {
+               if(current->files->fd[i])
+                       n++;
+       }
+       i=NR_OPEN;
+       if(i>current->rlim[RLIMIT_NOFILE].rlim_cur)
+               i=current->rlim[RLIMIT_NOFILE].rlim_cur;
+       if(n>=i)
+               return 0;
+       return i-n;
+}
+
+/*
+ *     Perform the AF_UNIX file descriptor pass out functionality. This
+ *     is nasty and messy as is the whole design of BSD file passing.
+ */
+
+static void unix_detach_fds(struct sk_buff *skb, struct cmsghdr *cmsg)
+{
+       int i;
+       int cmnum;
+       struct file **fp;
+       struct file **ufp;
+       int *cmfptr=NULL;       /* =NULL To keep gcc happy */
+       int fdnum;
+       int ffree;
+       int ufn=0;
+       if(cmsg==NULL)
+               cmnum=0;
+       else
+       {
+               cmnum=cmsg->cmsg_len-sizeof(struct cmsghdr);
+               cmnum/=sizeof(int);
+               cmfptr=(int *)&cmsg->cmsg_data;
+       }
+       
+       memcpy(&fdnum,skb->h.filp,sizeof(int));
+       fp=(struct file **)(skb->h.filp+sizeof(int));
+       if(cmnum>fdnum)
+               cmnum=fdnum;
+       ffree=unix_files_free();
+       if(cmnum>ffree)
+               cmnum=ffree;
+       ufp=&current->files->fd[0];
+       
+       /*
+        *      Copy those that fit
+        */
+       for(i=0;i<cmnum;i++)
+       {
+               /*
+                *      Insert the fd
+                */
+               while(ufp[ufn]!=NULL)
+                       ufn++;
+               ufp[ufn]=fp[i];
+               *cmfptr++=ufn;
+               FD_CLR(ufn,&current->files->close_on_exec);
+               unix_gc_remove(fp[i]);
+       }
+       /*
+        *      Dump those that don't
+        */
+       for(;i<fdnum;i++)
+       {
+               close_fp(fp[i]);
+               unix_gc_remove(fp[i]);
+       }
+       kfree(skb->h.filp);
+       skb->h.filp=NULL;
+       
+}
+
+static void unix_destruct_fds(struct sk_buff *skb)
+{
+       unix_detach_fds(skb,NULL);
+}
+       
+/*
+ *     Attach the file descriptor array to an sk_buff
  */
+static void unix_attach_fds(int fpnum,struct file **fp,struct sk_buff *skb)
+{
+       skb->h.filp=kmalloc(sizeof(int)+fpnum*sizeof(struct file *), 
+                                                       GFP_KERNEL);
+       memcpy(skb->h.filp,&fpnum,sizeof(int));
+       memcpy(skb->h.filp+sizeof(int),fp,fpnum*sizeof(struct file *));
+       skb->destructor=unix_destruct_fds;
+}
+
+/*
+ *     Send AF_UNIX data.
+ */
+               
 static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
 {
        unix_socket *sk=sock->data;
@@ -694,8 +881,9 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
        struct sk_buff *skb;
        int limit=0;
        int sent=0;
-       /* for passing  fd, NULL indicates no fd */
-       struct file *filp;
+       struct file *fp[UNIX_MAX_FD];
+       int fpnum=0;
+       int fp_attached=0;
 
        if(sk->err)
                return sock_error(sk);
@@ -723,27 +911,27 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                        return -ENOTCONN;
        }
 
-
-       /* see if we want to access rights (fd) -- at the moment, 
-        * we can pass none or 1 fd
-         */
-       filp = NULL;
-       if(msg->msg_accrights) {
-               /* then accrightslen is meaningful */
-               if(msg->msg_accrightslen == sizeof(int)) {
-                       int fd;
-
-                       fd = get_user((int *) msg->msg_accrights);
-                       filp = file_from_fd(fd);
-                       if(!filp)
-                               return -EBADF;
-               } else if(msg->msg_accrightslen != 0) {
-                       /* if we have accrights, we fail here */
-                       return -EINVAL;
+       /*
+        *      A control message has been attached.
+        */
+       if(msg->msg_accrights) 
+       {
+               struct cmsghdr *cm=unix_copyrights(msg->msg_accrights, 
+                                               msg->msg_accrightslen);
+               if(cm==NULL || msg->msg_accrightslen<sizeof(struct cmsghdr) ||
+                  cm->cmsg_type!=SCM_RIGHTS ||
+                  cm->cmsg_level!=SOL_SOCKET ||
+                  msg->msg_accrightslen!=cm->cmsg_len)
+               {
+                       kfree(cm);
+                       return -EINVAL;
                }
+               fpnum=unix_fd_copy(sk,cm,fp);
+               kfree(cm);
+               if(fpnum<0)
+                       return fpnum;
        }
 
-       /* invariant -- flip points to a file to pass or NULL */
        while(sent < len)
        {
                /*
@@ -756,7 +944,10 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                if(size>(sk->sndbuf-sizeof(struct sk_buff))/2)  /* Keep two messages in the pipe so it schedules better */
                {
                        if(sock->type==SOCK_DGRAM)
+                       {
+                               unix_fd_free(sk,fp,fpnum);
                                return -EMSGSIZE;
+                       }
                        size=(sk->sndbuf-sizeof(struct sk_buff))/2;
                }
                /*
@@ -778,6 +969,7 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                
                if(skb==NULL)
                {
+                       unix_fd_free(sk,fp,fpnum);
                        if(sent)
                        {
                                sk->err=-err;
@@ -790,6 +982,14 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                skb->sk=sk;
                skb->free=1;
                
+               if(fpnum && !fp_attached)
+               {
+                       fp_attached=1;
+                       unix_attach_fds(fpnum,fp,skb);
+                       fpnum=0;
+               }
+               else
+                       skb->h.filp=NULL;
                memcpy_fromiovec(skb_put(skb,size),msg->msg_iov, size);
 
                cli();
@@ -823,16 +1023,9 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                                        return err;
                        }
                }
-               /* at this point, we want to add an fd if we have one  */
-               skb->h.filp = filp;
-               if (filp) {
-                       filp->f_count++;
-               }
-               
                skb_queue_tail(&other->receive_queue, skb);
                sti();
                /* if we sent an fd, only do it once */
-               filp = NULL;    
                other->data_ready(other,size);
                sent+=size;
        }
@@ -853,36 +1046,6 @@ static void unix_data_wait(unix_socket * sk)
        }
        sti();
 }
-               
-
-/*
- * return 0 if we can stick the fd, negative errno if we can't
- */
-static int stick_fd(struct file *filp, int *uaddr, int size)
-{
-       int slot;
-       int upper_bound;
-
-       if (!uaddr || size < sizeof(int))
-               return -EINVAL;
-
-       upper_bound = current->rlim[RLIMIT_NOFILE].rlim_cur;
-
-       if (upper_bound > NR_OPEN)
-               upper_bound = NR_OPEN;
-
-       for (slot = 0; slot < upper_bound;  slot++) {
-               if (current->files->fd[slot])
-                       continue;
-               /* have an fd */
-               current->files->fd[slot] = filp;
-               FD_CLR(slot, &current->files->close_on_exec);
-               /* need verify area here? */
-               put_user(slot, uaddr);
-               return 0;
-       } 
-       return -EMFILE;
-}
 
 static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
 {
@@ -894,8 +1057,8 @@ static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n
        int len;
        int num;
        struct iovec *iov=msg->msg_iov;
+       struct cmsghdr *cm=NULL;
        int ct=msg->msg_iovlen;
-       struct file *filp;
 
        if(flags&MSG_OOB)
                return -EOPNOTSUPP;
@@ -905,6 +1068,20 @@ static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n
                
        if(sk->err)
                return sock_error(sk);
+
+       if(msg->msg_accrights) 
+       {
+               cm=unix_copyrights(msg->msg_accrights, 
+                       msg->msg_accrightslen);
+               if(msg->msg_accrightslen<sizeof(struct cmsghdr)||
+                  cm->cmsg_type!=SCM_RIGHTS ||
+                  cm->cmsg_level!=SOL_SOCKET ||
+                  msg->msg_accrightslen!=cm->cmsg_len)
+               {
+                       kfree(cm);
+                       return -EINVAL;
+               }
+       }
        
        down(&sk->protinfo.af_unix.readsem);            /* Lock the socket */
        while(ct--)
@@ -953,11 +1130,8 @@ static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n
                        num=min(skb->len,size-copied);
                        memcpy_tofs(sp, skb->data, num);
 
-                       if ((filp = skb->h.filp) != NULL) {
-                               skb->h.filp = NULL;
-                               if (stick_fd(filp, msg->msg_accrights, msg->msg_accrightslen) < 0)
-                                       close_fp(filp);
-                       }
+                       if (skb->h.filp!=NULL)
+                               unix_detach_fds(skb,cm);
 
                        copied+=num;
                        done+=num;
@@ -970,12 +1144,14 @@ static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n
                                continue;
                        }
                        kfree_skb(skb, FREE_WRITE);
-                       if(sock->type==SOCK_DGRAM)
+                       if(sock->type==SOCK_DGRAM || cm)
                                goto out;
                }
        }
 out:
        up(&sk->protinfo.af_unix.readsem);
+       if(cm)
+               unix_returnrights(msg->msg_accrights,msg->msg_accrightslen,cm);
        return copied;
 }
 
@@ -1118,7 +1294,7 @@ static struct proto_ops unix_proto_ops = {
 
 void unix_proto_init(struct net_proto *pro)
 {
-       printk("NET3: Unix domain sockets 0.10 BETA for Linux NET3.033.\n");
+       printk("NET3: Unix domain sockets 0.12 for Linux NET3.033.\n");
        sock_register(unix_proto_ops.family, &unix_proto_ops);
 #ifdef CONFIG_PROC_FS
        proc_net_register(&(struct proc_dir_entry) {
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
new file mode 100644 (file)
index 0000000..67d9e06
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * NET3:       Garbage Collector For AF_UNIX sockets (STUB)
+ *
+ * Authors:    
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             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.
+ * Fixes:
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/un.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <asm/segment.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <net/af_unix.h>
+#include <linux/proc_fs.h>
+/*
+ *     Garbage Collector Stubs
+ */
+
+int unix_gc_free=128;          /* GC slots free */
+
+void unix_gc_remove(struct file *fp)
+{
+       ;
+}
+
+void unix_gc_add(struct sock *sk, struct file *fp)
+{
+       ;
+}
index 72755eeaf8e3eefdeb9fc86fd18af4e46f72afb0..8bf98133332bfb431e52355b729b56e73289a5f9 100644 (file)
@@ -17,7 +17,7 @@
 # dialog is available at sunsite.unc.edu or a sunsite mirror.
 #
 # Portions of this script were borrowed from the original Configure
-# script used in linux-1.3.55.
+# script.
 #
 # Please send comments / questions / bug fixes to roadcapw@cfw.com
 #
 # Change this to TRUE if you prefer all kernel options listed
 # in a single menu rather than the standard menu hierarchy.
 #
-# Don't forget to remove linux/.menuconfig.in
-#
 single_menu_mode=
 
 #
 # Make sure we're really running bash.
 #
-[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; }
+[ -z "$BASH" ] && { echo "Menuconfig requires bash" 1>&2; exit 1; }
 
 #
 # Cache function definitions
@@ -57,18 +55,19 @@ function extract_help () {
      #now pick out the right help text:
      text=$(sed -n "/^$var[    ]*\$/,\${
                         /^$var[        ]*\$/d
-                        /^#.*/d;/^[    ]*\$/q
+                        /^#.*/d
+                       /^[     ]*\$/q
                         p
                     }" Documentation/Configure.help)
 
      if [ -z "$text" ]
      then
-         echo "There is no help available for this setting."
+         echo "There is no help available for kernel option."
      else
          echo "$text"
      fi
   else
-        echo "There is no help available for this setting."
+        echo "There is no help available for kernel option."
   fi
 }
 
@@ -76,29 +75,37 @@ function extract_help () {
 # Activate a help dialog.
 #
 function help () {
-       extract_help $2 >help.out
-       $DIALOG --backtitle "$backtitle" --title "$1" --textbox help.out 20 75
+       extract_help $1 >help.out
+       $DIALOG --backtitle "$backtitle" --title "$2" --textbox help.out 20 75
        rm help.out
 }
 
+#
+# Show the README file.
+#
+function show_readme() {
+       $DIALOG --backtitle "$backtitle" \
+               --textbox scripts/README.Menuconfig 21 75
+}
 
 #
-# Init temporary scripts for the current menu.
+# Begin building the dialog menu command and Initialize the 
+# Radiolist function file.
 #
 function menu_name () {
        echo -ne "$DIALOG --title '$1'\
                        --backtitle '$backtitle' \
                        --menu '$menu_instructions' \
-                       21 75 11 '$default' " >submenu
-       >radiolists
+                       21 75 11 '$default' " >MCmenu
+       >MCradiolists
 }
 
 #
-# Additional comments are currently semi-supported
+# Additional comments
 #
 function comment () {
        comment_ctr=$[ comment_ctr + 1 ]
-       echo -ne "': $comment_ctr' '--- $1' " >>submenu
+       echo -ne "': $comment_ctr' '--- $1' " >>MCmenu
 }
 
 #
@@ -112,16 +119,27 @@ function define_bool () {
 # Add a submenu option to the menu currently under construction.
 #
 function submenu () {
-       echo -ne "'activate_menu $2' '$1  --->' " >>submenu
+       echo -ne "'activate_menu $2' '$1  --->' " >>MCmenu
 }
 
 #
-# This is to handle the Sound configuration.
+# Create a menu entry to handle the traditional sound configuration.
 #
-function yuck1 () {
-       echo -ne "'clear ; $MAKE $2' '$1' " >>submenu
+function soundcfg () {
+       echo -ne "'l_soundcfg' "\
+                "'Old configuration script "\
+                "(For: SM Wave, PSS & AudioTrix Pro) -->' " >>MCmenu
 }
 
+#
+# Startup the traditional sound configuration program.
+#
+function l_soundcfg () {
+       clear
+       $MAKE -C drivers/sound config
+}
+
+
 #
 # Create a boolean (Yes/No) function for our current menu
 # which calls our local bool function.
@@ -136,10 +154,10 @@ function bool () {
           ;;
        esac
 
-       echo -ne "'$2' '($flag) $1' " >>submenu
+       echo -ne "'$2' '($flag) $1' " >>MCmenu
 
        echo -e "function $2 () { l_bool '$1' '$yes' '$no' '$2' }\n" \
-               >>radiolists
+               >>MCradiolists
 }
 
 #
@@ -148,16 +166,19 @@ function bool () {
 function l_bool () {
        while true
        do
-               if $DIALOG --title "$1" \
+               $DIALOG --title "$1" \
                        --backtitle "$backtitle" \
                        --radiolist "$radiolist_instructions" 12 70 2 \
-                       'y' 'Yes' $2 'n' 'No' $3 2>dialog.out
-               then
-                       eval $4=`cat dialog.out`
-                       break
-               fi
-                       
-               help "$1" "$4"
+                       'y' 'Yes' $2 'n' 'No' $3 2>MCdialog.out
+
+               case "$?" in
+               0) eval $4=`cat MCdialog.out`
+                  break ;;
+
+               1) help "$4" "$1" ;;
+
+               *) break ;;
+               esac
        done
 }
 
@@ -174,10 +195,10 @@ function mod_bool () {
           ;;
        esac
 
-       echo -ne "'$2' '($flag) $1' " >>submenu
+       echo -ne "'$2' '($flag) $1' " >>MCmenu
 
        echo -e "function $2 () { l_mod_bool '$1' '$module' '$no' '$2' }\n" \
-               >>radiolists
+               >>MCradiolists
 }
 
 #
@@ -186,16 +207,20 @@ function mod_bool () {
 function l_mod_bool() {
        while true
        do
-               if $DIALOG --title "$1" \
+               $DIALOG --title "$1" \
                        --backtitle "$backtitle" \
                        --radiolist "$radiolist_instructions" 12 70 2 \
-                       'm' 'Module' $2 'n' 'No' $3 2>dialog.out
-               then
-                       eval $4=`cat dialog.out`
-                       break
-               fi
+                       'm' 'Module' $2 'n' 'No' $3 2>MCdialog.out
+
+               case "$?" in
+               0) eval $4=`cat MCdialog.out`
+                  break ;;
+
+               1) help "$4" "$1" ;;
+
+               *) break ;;
+               esac
                        
-               help "$1" "$4"
        done
 }
 
@@ -221,12 +246,12 @@ function tristate () {
                ;;
                esac
        
-               echo -ne "'$2' '($flag) $1' " >>submenu
+               echo -ne "'$2' '($flag) $1' " >>MCmenu
        
                echo -e "
                function $2 () { \
                        l_tristate '$1' '$yes' '$no' '$module' '$2'
-               }"  >>radiolists
+               }"  >>MCradiolists
        fi
 }
 
@@ -236,17 +261,20 @@ function tristate () {
 function l_tristate () {
        while true
        do
-               if $DIALOG --title "$1" \
+               $DIALOG --title "$1" \
                        --backtitle "$backtitle" \
                        --radiolist "$radiolist_instructions" 13 70 3 \
                        'y' 'Yes' $2 'n' 'No' $3 'm' 'Module' $4 \
-                       2>dialog.out
-               then
-                       eval $5=`cat dialog.out`
-                       break
-               fi
-                       
-               help "$1" "$5"
+                       2>MCdialog.out
+
+               case "$?" in
+               0) eval $5=`cat MCdialog.out`
+                  break ;;
+
+               1) help "$5" "$1" ;;
+
+               *) break ;;
+               esac
        done
 }
 
@@ -277,14 +305,14 @@ function dep_tristate () {
 }
 
 #
-# Create a function which will call our local int function.
+# Add a menu item which will call our local int function.
 # 
 function int () {
        eval $2=\${$2:-"$3"} x=\$$2
 
-       echo -ne "'$2' '($x) $1' " >>submenu
+       echo -ne "'$2' '($x) $1' " >>MCmenu
 
-       echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' }\n" >>radiolists
+       echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' }\n" >>MCradiolists
 }
 
 #
@@ -296,9 +324,9 @@ function l_int () {
                if $DIALOG --title "$1" \
                        --backtitle "$backtitle" \
                        --inputbox "$inputbox_instructions_int" \
-                       15 55 "$4" 2>dialog.out
+                       15 55 "$4" 2>MCdialog.out
                then
-                       answer="`cat dialog.out`"
+                       answer="`cat MCdialog.out`"
                        answer="${answer:-$3}"
 
                        if expr $answer : '0$\|-?[1-9][0-9]*$' >/dev/null
@@ -315,20 +343,20 @@ function l_int () {
                        break
                fi
 
-               help "$1" "$2"
+               help "$2" "$1"
        done
 }
 
 
 #
-# Create a function which will call our local int function.
+# Add a menu item which will call our local int function.
 # 
 function hex () {
        eval $2=\${$2:-"$3"} x=\${$2##*[x,X]}
 
-       echo -ne "'$2' '($x) $1' " >>submenu
+       echo -ne "'$2' '($x) $1' " >>MCmenu
 
-       echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' }\n" >>radiolists
+       echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' }\n" >>MCradiolists
 }
 
 #
@@ -340,9 +368,9 @@ function l_hex () {
                if $DIALOG --title "$1" \
                        --backtitle "$backtitle" \
                        --inputbox "$inputbox_instructions_hex" \
-                       15 55 "$4" 2>dialog.out
+                       15 55 "$4" 2>MCdialog.out
                then
-                       answer="`cat dialog.out`"
+                       answer="`cat MCdialog.out`"
                        answer="${answer:-$3}"
                        answer="${answer##*[x,X]}"
 
@@ -360,12 +388,12 @@ function l_hex () {
                        break
                fi
 
-               help "$1" "$2"
+               help "$2" "$1"
        done
 }
 
 #
-# Create a function which will call our local One-of-Many choice list.
+# Add a menu item which will call our local One-of-Many choice list.
 #
 function choice () {
        #
@@ -395,12 +423,12 @@ function choice () {
 
        : ${current:=$default}
 
-       echo -ne "'$firstchoice' '($current) $title' " >>submenu
+       echo -ne "'$firstchoice' '($current) $title' " >>MCmenu
 
        echo -e "
        function $firstchoice () {
                l_choice '$title' \"$choices\" $current
-       }\n" >>radiolists
+       }\n" >>MCradiolists
 }
 
 
@@ -433,13 +461,13 @@ function l_choice () {
                if $DIALOG --title "$title" \
                        --backtitle "$backtitle" \
                        --radiolist "$radiolist_instructions" \
-                       22 70 11 $list 2>dialog.out
+                       22 70 11 $list 2>MCdialog.out
                then
-                       choice=`cat dialog.out`
+                       choice=`cat MCdialog.out`
                        break
                fi
 
-               help "$title" "$firstchoice"
+               help "$firstchoice" "$title"
        done
 
        #
@@ -462,114 +490,130 @@ function l_choice () {
 
 
 #
-# Now parse the configuration files and create our mini scripts.
-# Each script represents a separate menu which when taken together
-# form a linked menu tree.  Since one configuration file
-# may source another elsewhere in the kernel source tree, this 
-# function is recursive.
+# A faster awk based recursive parser. (I hope)
 #
-function parse_config_files () {
-       if [ "_$single_menu_mode" = "_TRUE" ]
-       then
-               parse_single_menu $1
-               return
-       fi
-
-       while read command args
-       do
-               case $command in
-
-               #
-               # Will it ever happen that mainmenu_option will be followed
-               # by anything other then "next_comment"?  This assumes not..
-               #
-               mainmenu_option) 
-                       comment_is_option=TRUE
-                       ;;
-
-               comment)
-                       if [ "$comment_is_option" ]
-                       then
-                               comment_is_option=
-
-                               stack="$submenu\ 1$stack"
-
-                               menu_no=$[menu_no + 1]
-                               x="submenu$menu_no"
-
-                               echo "submenu $args $x" >> $submenu
-
-                               submenu=$x
-                               echo menu_name $args >$submenu
-                       else
-                               echo comment $args >> $submenu
-                       fi
-                       ;;
-       
-               endmenu)
-                       submenu="${stack%%\ 1*}"
-                       stack="${stack#*\ 1}"
-                       ;;
-
-               mainmenu_name)
-                       echo menu_name "'Main Menu'" > submenu0
-                       ;;
-
-               \$MAKE) echo "yuck1 'Configure (You must do this!)' '$args'"\
-                               >>$submenu
-                       ;;
+function parser1 () {
+awk '
+BEGIN {
+       menu_no = 0
+       comment_is_option = 0
+       parser("'$CONFIG_IN'","MCmenu0")
+}
 
-               source)
-                       parse_config_files "$args"
-                       ;;
+function parser(ifile,menu) {
+
+       while (getline <ifile) {
+               if ($1 == "mainmenu_option") {
+                       comment_is_option = "1"
+               }
+               else if ($1 == "comment" && comment_is_option == "1") {
+                       comment_is_option= "0"
+                       sub($1,"",$0)
+                       ++menu_no
+
+                       printf("submenu %s MCmenu%s\n", $0, menu_no) >>menu
+
+                       printf( "function MCmenu%s () {\n"\
+                               "default=$1\n"\
+                               "menu_name %s\n",\
+                                menu_no, $0) >"MCmenu"menu_no
+
+                       parser(ifile, "MCmenu"menu_no)
+               }
+               else if ($1 ~ "endmenu") {
+                       printf("}\n") >>menu
+                       return
+               } 
+               else if ($0 ~ /^#|$MAKE|mainmenu_name/) {
+                       printf("") >>menu
+               }
+               else if ($1 == "source") {
+                       # Yuk!  Blah!  Phooey!
+                       if ($2 ~ "drivers/sound") {
+                               printf("soundcfg\n") >>menu
+                       }
+
+                       parser($2,menu)
+               }
+               else {
+                       print >>menu
+               }
+       }
+}'
+}
 
-               '#'|'')  : ;;
+#
+# Secondary parser for single menu mode.
+#
+function parser2 () {
+awk '
+BEGIN {
+       parser("'$CONFIG_IN'","MCmenu0")
+}
 
-               *)      echo $command $args >> $submenu
-                       ;;
-               esac
-       done < $1
+function parser(ifile,menu) {
+
+       while (getline <ifile) {
+               if ($1 ~ /mainmenu_option|endmenu/) {
+                       printf("") >>menu
+               } 
+               else if ($0 ~ /^#|$MAKE|mainmenu_name/) {
+                       printf("") >>menu
+               }
+               else if ($1 == "source") {
+                       if ($2 ~ "drivers/sound") {
+                               printf("soundcfg\n") >>menu
+                       }
+                       parser($2,menu)
+               }
+               else {
+                       print >>menu
+               }
+       }
+}'
 }
 
 #
-# Parses configuration files into a single menu structure.
+# Parse all the config.in files into mini scripts.
 #
-function parse_single_menu () {
-
-       while read command args
-       do
-               case $command in
+function parse_config_files () {
+       rm -f MCmenu*
 
-               mainmenu_option | \
-               endmenu)
-                       : ;;
+       echo "function MCmenu0 () {" >MCmenu0
+       echo 'default=$1' >>MCmenu0
+       echo "menu_name 'Main Menu'" >>MCmenu0
 
-               mainmenu_name)
-                       echo menu_name "'Main Menu'" > submenu0
-                       ;;
 
-               \$MAKE) echo "yuck1 'Configure (You must do this!)' '$args'"\
-                               >>$submenu
-                       ;;
+       if [ "_$single_menu_mode" = "_TRUE" ]
+       then
+               parser2
+       else
+               parser1
+       fi
 
-               source)
-                       parse_single_menu "$args"
-                       ;;
+       echo "}" >>MCmenu0
 
-               '#'|'')  : ;;
+       #
+       # These mini scripts must be sourced into the current
+       # environment in order for all of this to work.  Leaving
+       # them on the disk as executables screws up the recursion
+       # in activate_menu(), among other things.  Once they are
+       # sourced we can disgard them.
+       #
+       for i in MCmenu*
+       do
+               source $i
+       done
 
-               *)      echo $command $args >> $submenu
-                       ;;
-               esac
-       done < $1
+       rm -f MCmenu*
 }
 
 #
 # This is the menu tree's bootstrap.
 #
-# Executes a mini script to create a set of functions, one per configuration
-# option.  These functions will in turn execute dialog commands or recursively
-# call other mini scripts.
+# Executes the parsed menus on demand and creates a set of functions,
+# one per configuration option.  These functions will in turn execute
+# dialog commands or recursively call other menus.
 #
 function activate_menu () {
 
@@ -577,23 +621,24 @@ function activate_menu () {
        do
                comment_ctr=0
                $1 "$default"           #Create the radiolists and dialog cmd
-               . radiolists            #Read in the dialog functions.
+               . MCradiolists          #Read in the dialog functions.
 
-               . submenu 2>dialog.out  #Activate this menu
+               . MCmenu 2>MCdialog.out #Activate this menu
 
                case "$?" in
                0)
-                       defaults="`cat dialog.out`\ 1$defaults"  #pseudo stack
-                       source dialog.out
-                       default="${defaults%%\ 1*}" defaults="${defaults#*\ 1}"
+                       defaults="`cat MCdialog.out`\12$defaults"  #psuedo stack
+                       . MCdialog.out
+                       default="${defaults%%\12*}" defaults="${defaults#*\12}"
                        ;;
                2)      
-                       echo >>dialog.out
-                       read selection <dialog.out
-                       default="${selection##* }"
+                       echo >>MCdialog.out
+                       read selection <MCdialog.out
+                       default="${selection%% *}"
+
                        case "$selection" in
-                       *"-->"*) : ;;
-                       *)       eval help "$selection" ;;
+                       *"-->"*) show_readme ;;
+                       *)       eval help $selection ;;
                        esac
                        ;;
                255|1)
@@ -733,12 +778,6 @@ save_configuration () {
                fi
        }
 
-       #
-       # This will hopfully prevent the sound configuration from
-       # running again.  (blagh!)
-       #
-       MAKE=:
-
        CONFIG=.tmpconfig
        CONFIG_H=.tmpconfig.h
 
@@ -749,16 +788,33 @@ save_configuration () {
        echo "/*" >$CONFIG_H
        echo " * Automatically generated by make menuconfig: don't edit" >>$CONFIG_H
        echo " */" >>$CONFIG_H
-       
-       . $CONFIG_IN
 
-       if [ -f .config ]
+       MAKE=:  #To prevent sound Makefile from running.
+       
+       if . $CONFIG_IN >>.menuconfig.log 2>&1
        then
-               rm -f .config.old
-               mv .config .config.old
+               #
+               # Create the sound driver's config files for cards
+               # Which are compatible with the new config method.
+               #
+               if [ "_$CONFIG_TRIX"   != "_y" -a\
+                    "_$CONFIG_PSS"    != "_y" -a\
+                    "_$CONFIG_SMWAVE" != "_y"    ]
+               then
+                       make -C drivers/sound kernelconfig >>.menuconfig.log 2>&1
+               fi
+
+               if [ -f .config ]
+               then
+                       rm -f .config.old
+                       mv .config .config.old
+               fi
+               mv .tmpconfig .config
+               mv .tmpconfig.h include/linux/autoconf.h
+               return 0
+       else
+               return 1
        fi
-       mv .tmpconfig .config
-       mv .tmpconfig.h include/linux/autoconf.h
 }
 
 #
@@ -770,25 +826,24 @@ cleanup () {
 }
 
 cleanup1 () {
-       rm -f submenu* radiolists dialog.out help.out
+       rm -f MCmenu* MCradiolists MCdialog.out help.out
 }
 
 cleanup2 () {
        rm -f .tmpconfig .tmpconfig.h
 }
 
-
 menu_instructions="\
 Arrow keys navigate the menu.  \
-Highlighted letters are shortcuts. \
+Highlighted letters are hotkeys. \
 Select an item with <Space Bar> or <Enter>. \
-When finished press <E> or <X> or <Esc>.  \
+When finished press <Esc><Esc> or <X>.  \
 (*) indicates an option will be compiled into the kernel.  \
 (M) indicates an option will be compiled as a module."
 
 radiolist_instructions="\
-Use the arrow keys to navigate this radiolist or \
-press the first letter of the item you wish to select \
+Use the arrow keys to navigate this window or \
+press the hotkey of the item you wish to select \
 followed by the <SPACE BAR>.
 Press <H> for additional information about this option."
 
@@ -805,12 +860,9 @@ backtitle="Linux Kernel Configuration"
 
 DIALOG="./scripts/lxdialog/lxdialog"
 
-comment_is_option=
-menu_no=0
-submenu=submenu0
 kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}"
 
-trap "cleanup ; rm -f .menuconfig.in ; exit 1" 1 2 15
+trap "cleanup ; rm -f .menuconfig ; exit 1" 1 2 15
 
 #
 # Locate default files.
@@ -842,57 +894,50 @@ else
   echo "#"
 fi
 
+# Fresh new log.
+>.menuconfig.log
+
+
+$DIALOG        --backtitle "$backtitle" \
+       --infobox "Preparing configuration scripts..." 3 40
 
 #
-# Convert the configuration files into our mini scripts.
-# Then put all the mini scripts into a single file which should
-# stick around and act as a cache until the kernel release changes
-# or "make mrproper".
+# Check kernel version of previous menuconfig build.
+# If it's different then we should tell the sound driver
+# to rebuild it's Config.in file.
 #
-if [ -e .menuconfig.in ]
+rebuildsound=TRUE
+if [ -e .menuconfig ]
 then
-       read x <.menuconfig.in
-       if [ "$x" != "# $kernel_version" ]
+       read x <.menuconfig
+       if [ "$x" = "# $kernel_version" ]
        then
-               rm -f .menuconfig.in
+               rebuildsound=
        fi
 fi
 
-if [ ! -e .menuconfig.in ]
+if [ "$rebuildsound" ]
 then
-       $DIALOG --backtitle "$backtitle" \
-               --infobox "Compiling configuration script..." 3 40
-
-       rm -f submenu*
-       parse_config_files $CONFIG_IN
-
+       # Activate the Linux compatible sound configuration.
+       # This may not work for all sound cards.  (See sound docs)
        #
-       # For handling Sound configuration. (Yuk!)
-       #
-       echo '$MAKE $*' >submenu999
-
-       echo "# $kernel_version" >.menuconfig.in
-
-       for i in submenu*
-       do
-               echo "function $i () {"
-               echo 'default=$1'
-               cat $i
-               echo -e "}\n\n"
-       done >> .menuconfig.in
+       make -C drivers/sound mkscript >>.menuconfig.log 2>&1
 
-       rm -f submenu*
+       echo "# $kernel_version" >.menuconfig
 fi
 
-source .menuconfig.in
+#
+# Read config.in files and parse them into one shell function per menu.
+#
+parse_config_files $CONFIG_IN
 
 #
 # Start the ball rolling from the top.
 #
-activate_menu submenu0
+activate_menu MCmenu0
 
 #
-# We're done with the menu scripts.  Get rid of them.
+# All done!
 #
 cleanup1
 
@@ -905,15 +950,19 @@ if $DIALOG --backtitle "$backtitle" \
 then
        save_configuration
 
-       $DIALOG --backtitle "$backtitle" --infobox "\
-The linux kernel is now hopefully configured for your setup.  \
-Check the top-level Makefile for additional configuration, \
-and do a 'make dep ; make clean' if you want to be sure all \
-the files are correctly re-made." 7 60
+       clear
+       cat <<EOM
+
+
+The linux kernel is now hopefully configured for your setup.
+Check the top-level Makefile for additional configuration,
+and do a 'make dep ; make clean' if you want to be sure all
+the files are correctly re-made.
+
+EOM
 else
-       $DIALOG --backtitle "$backtitle" \
-               --infobox "Your new configuration was not saved." 3 42 
-       
+       clear
+       echo -e "Your kernel configuration changes where NOT saved.\n"
 fi
 
 
index 19fa07ee4bccb7cb989869c52a4b09cb6ffbdeda..06ed90ad7fd512a404248c4972d0aaab3de9bb09 100644 (file)
-This is the Linux kernel menuconfig README file.
+This is the Linux kernel Menuconfig README file.
 
-Menuconfig gives the linux kernel configuration a long needed face lift.
-It features text based color menus, radiolists and dialogs, but does
-not require X Windows.  With this utility you can easily select a
-kernel option to modify without having to sift through 100 other options.
+Menuconfig gives the Linux kernel configuration a long needed face
+lift.  Featuring text based color menus and dialogs, it does not
+require X Windows.  With this utility you can easily select a kernel
+option to modify without sifting through 100 other options.
 
-The windowing support utility (lxdialog) is a VERY modified version of the
-dialog utility by Savio Lam <lam836@cs.cuhk.hk>.  Although lxdialog is 
-significantly different from dialog, I have left Savio's copyrights intact.
-Please DO NOT contact Savio with questions about lxdialog.  He will not be
-able to assist.
+The windowing support utility (lxdialog) is a VERY modified version of
+the dialog utility by Savio Lam <lam836@cs.cuhk.hk>.  Although lxdialog
+is significantly different from dialog, I have left Savio's copyrights
+intact.  Please DO NOT contact Savio with questions about lxdialog.
+He will not be able to assist.
 
-
-Please feel free to send any questions or comments or suggestions to
+Please feel free to send any questions, comments or suggestions to
 William Roadcap <roadcapw@cfw.com>.
 
+READ ON! There are hints and notices below...
+
 
-Some menuconfig keyboard hints:
+Some Menuconfig keyboard hints:
 
 Menus
 ----------
 o  Use the Up/Down arrow keys (cursor keys) to highlight the item 
    or submenu you wish to select.  
-   Shortcut: Press the option's highlighted letter. (usually the first)
+   Shortcut: Press the option's highlighted letter (hotkey).
+             Pressing a hotkey more than once will sequence
+             through all items which use that hotkey.
 
 o  Use the cursor keys to highlight <Select> and press <ENTER>.  
-   Shortcut: Press <Space Bar> or <S> if there's no item beginning with <S>.
+   Shortcut: Press the <SPACE BAR> or <S> if there is no item using
+             <S> as it's hotkey.
 
-o  To exit a menu use the cursor keys to highlight the <Exit> button and 
-   press <ENTER>.  
-   Shortcut: Press <Esc> or <E> or <X> if there's no option beginning 
-             those letters.
+o  To exit a menu use the cursor keys to highlight the <Exit> button
+   and press <ENTER>.  
+   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey
+             using those letters.  You may press a single <ESC>, but
+             there is a delayed response which you may find annoying.
 
-   Also, the <TAB> key will toggle between <Select>, <Exit> and <Help>
+   Also, the <TAB> and cursor keys will cycle between <Select>,
+   <Exit> and <Help>
 
-o  To get help with an item, use the cursor keys to highlight <Help> and
-   Press <ENTER>.
+o  To get help with an item, use the cursor keys to highlight <Help>
+   and Press <ENTER>.
    Shortcut: Press <H> or <?>.
 
 
 Radiolists  (Yes/No/Module)
 -----------
 o  Use the cursor keys to select the option you wish to set and press
-   <O> or the <SPACE BAR>.
+   <S> or the <SPACE BAR>.
    Shortcut: Press the first letter of the option you wish to set then
-             press <O> or <SPACE BAR>.
+             press <S> or <SPACE BAR>.
 
 o  To see available help for the item, use the cursor keys to highlight
    <Help> and Press <ENTER>.
    Shortcut: Press <H> or <?>.
 
-   Also, the <TAB> key will toggle between <Select> and <Help>
+   Also, the <TAB> and cursor keys will cycle between <Select> and
+   <Help>
 
 
 Data Entry
 -----------
 o  Enter the requested information and press <ENTER>
+   If you are entering hexidecimal values, it is not necessary to
+   add the '0x' prefix to the entry.
 
-o  For help, use the <TAB> key to highlight the help option and 
-   press <ENTER>.  You can try <TAB><H> as well.
+o  For help, use the <TAB> or cursor keys to highlight the help option
+   and press <ENTER>.  You can try <TAB><H> as well.
 
 
 Text Box    (Help Window)
 --------
-o  Use the cursor keys to scroll up/down/left/right.
+o  Use the cursor keys to scroll up/down/left/right.  The VI editor
+   keys h,j,k,l function here as do <SPACE BAR> and <B> for those
+   who are familiar with less and lynx.
 
-o  Press <E>, <X>, <Enter> or <Esc> to exit.
+o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.
 
 
 Final Acceptance
 ----------------
-With the exception of sound configuration, YOUR CHANGES ARE NOT FINAL.
-You will be given a last chance to confirm them prior to exiting menuconfig.
+With the exception of the old style sound configuration,
+YOUR CHANGES ARE NOT FINAL.  You will be given a last chance to
+confirm them prior to exiting Menuconfig.
 
+If Menuconfig quits with an error while saving your configuration,
+you may look in the file /usr/src/linux/.menuconfig.log for
+information which may help you determine the cause.
 
 
 Other information:
 
-Menuconfig attempts to reduce the amount of time it takes to reconfigure
-the kernel. 
-
-Menuconfig keeps a cache of it's compiled configuration scripts in 
-/usr/src/linux/.menuconfig.in.  This file will only be rebuilt if you
-do a 'make mrproper' or if the kernel version changes.  If you make manual 
-changes to any of the config.in files in the kernel source tree, you 
-must remove .menuconfig.in so that menuconfig will know to rebuild it.
-
 The windowing utility, lxdialog, will only be rebuilt if your kernel
-source tree is fresh, or changes are patched into it via a kernel patch
-or you do 'make mrproper'.  If changes to lxdialog are patched in, most
-likely the rebuild time will be short.  You may force a complete rebuild
-of lxdialog by changing to it's directory and doing 'make clean all'
+source tree is fresh, or changes are patched into it via a kernel
+patch or you do 'make mrproper'.  If changes to lxdialog are patched
+in, most likely the rebuild time will be short.  You may force a
+complete rebuild of lxdialog by changing to it's directory and doing
+'make clean all'
 
 NOTICE:  lxdialog requires the ncurses libraries to compile.  If you
          don't already have ncurses you really should get it.
 
-         The makefile for lxdialog attempts to find your ncurses header
-         file.  Although it should find the header for older versions of
-         ncurses, it is probably a good idea to get the latest ncurses
-         anyway.
+         The makefile for lxdialog attempts to find your ncurses
+         header file.  Although it should find the header for older
+         versions of ncurses, it is probably a good idea to get the
+         latest ncurses anyway.
+
+WARNING: It is not recommended that you change any defines in
+         lxdialog's header files.  If you have a grayscale display and
+         are brave, you may tinker with color.h to tune the colors to
+         your preference.
+
+COMPATABILITY ISSUE:
+         There have been some compatability problems reported with
+         older versions of bash and sed.  I am trying to work these
+         out but it is preferable that you upgrade those utilities.
 
-WARNING: It is not recommended that you change any defines in lxdialog's
-         header files.
 
+******** IMPORTANT, OPTIONAL ALTERNATE PERSONALITY AVAILABLE ********
+********                                                     ********
+If you prefer to have all of the kernel options listed in a single
+menu, rather than the default multimenu hierarchy, you may edit the
+Menuconfig script and change the line "single_menu_mode="  to 
+"single_menu_mode=TRUE".
 
-*** IMPORTANT, OPTIONAL ALTERNATE PERSONALITY AVAILABLE ***
-***                                                     ***
-If you prefer to have all of the kernel options listed in a single menu, 
-rather than the default multimenu hierarchy, you may edit the Menuconfig 
-script and change the line "single_menu_mode="  to "single_menu_mode=TRUE".  
-Don't forget to remove linux/.menuconfig.in afterwards.
+This mode is not recommended unless you have a fairly fast machine.
 
+<END OF README>
index 6072f2f436b944296536c774fbab7dace4f1974e..5695c72797a8f62609f03f8cb8763bce0ed25906 100644 (file)
@@ -2,26 +2,25 @@ CC = gcc
 CPP = gcc -E
 OPTIM = -O2 -Wall -fomit-frame-pointer
 
-CFLAGS = $(OPTIM) $(CURSES) -DLOCALE 
+CFLAGS = $(OPTIM) -DLOCALE 
 LDFLAGS = -s -L .
 LDLIBS = -lncurses
 
-CURSES =  -DCURSES_LOC="<curses.h>"
-
 ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
-        CFLAGS += -I/usr/include/ncurses
-        CURSES =  -DCURSES_LOC="<ncurses.h>"
+        CFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
 else
 ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h))
-        CFLAGS += -I/usr/include/ncurses
-        CURSES =  -DCURSES_LOC="<curses.h>"
+        CFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<curses.h>"
 else
 ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h))
-        CURSES =  -DCURSES_LOC="<ncurses.h>"
+        CFLAGS += -DCURSES_LOC="<ncurses.h>"
+else
+       CFLAGS += -DCURSES_LOC="<curses.h>"
 endif
 endif
 endif
 
+
 OBJS = checklist.o menubox.o textbox.o yesno.o inputbox.o \
        util.o lxdialog.o msgbox.o
 SRCS = $(OBJS:.o=.c)
index b79535fe03c7b0776512026b93a35d599dd2777f..b986b3a2edcd328858dfcfb104587b6919f1a1a9 100644 (file)
@@ -96,14 +96,15 @@ print_arrows (WINDOW * win, int choice, int item_no, int scroll,
  *  Display the termination buttons
  */
 static void
-print_buttons( WINDOW *dialog, int height, int width, int okval, int cancelval)
+print_buttons( WINDOW *dialog, int height, int width, int selected)
 {
     int x = width / 2 - 11;
     int y = height - 2;
 
-    print_button (dialog, "Select", y, x, okval);
-    print_button (dialog, " Help ", y, x + 14, cancelval);
+    print_button (dialog, "Select", y, x, selected == 0);
+    print_button (dialog, " Help ", y, x + 14, selected == 1);
 
+    wmove(dialog, y, x+1 + 14*selected);
     wrefresh (dialog);
 }
 
@@ -114,8 +115,9 @@ print_buttons( WINDOW *dialog, int height, int width, int okval, int cancelval)
 int
 dialog_checklist (const char *title, const char *prompt, int height, int width,
        int list_height, int item_no, const char * const * items, int flag)
+       
 {
-    int i, x, y, cur_x, cur_y, box_x, box_y;
+    int i, x, y, box_x, box_y;
     int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
     WINDOW *dialog, *list;
 
@@ -166,7 +168,6 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
     print_autowrap (dialog, prompt, width - 2, 1, 3);
 
     list_width = width - 6;
-    getyx (dialog, cur_y, cur_x);
     box_y = height - list_height - 5;
     box_x = (width - list_width) / 2 - 1;
 
@@ -196,7 +197,7 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
     print_arrows(dialog, choice, item_no, scroll,
                        box_y, box_x + check_x + 5, list_height);
 
-    print_buttons(dialog, height, width, TRUE, FALSE);
+    print_buttons(dialog, height, width, 0);
 
     while (key != ESC) {
        key = wgetch (dialog);
@@ -213,7 +214,6 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
                    if (!scroll)
                        continue;
                    /* Scroll list down */
-                   getyx (dialog, cur_y, cur_x);
                    if (list_height > 1) {
                        /* De-highlight current first item */
                        print_item (list, items[scroll * 3 + 1],
@@ -230,7 +230,6 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
                    print_arrows(dialog, choice, item_no, scroll,
                                box_y, box_x + check_x + 5, list_height);
 
-                   wmove (dialog, cur_y, cur_x);
                    wrefresh (dialog);
 
                    continue;   /* wait for another key press */
@@ -241,7 +240,6 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
                    if (scroll + choice >= item_no - 1)
                        continue;
                    /* Scroll list up */
-                   getyx (dialog, cur_y, cur_x);
                    if (list_height > 1) {
                        /* De-highlight current last item before scrolling up */
                        print_item (list, items[(scroll + max_choice - 1) * 3 + 1],
@@ -260,7 +258,6 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
                    print_arrows(dialog, choice, item_no, scroll,
                                box_y, box_x + check_x + 5, list_height);
 
-                   wmove (dialog, cur_y, cur_x);
                    wrefresh (dialog);
 
                    continue;   /* wait for another key press */
@@ -269,7 +266,6 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
            }
            if (i != choice) {
                /* De-highlight current item */
-               getyx (dialog, cur_y, cur_x);
                print_item (list, items[(scroll + choice) * 3 + 1],
                            status[scroll + choice], choice, FALSE);
                /* Highlight new item */
@@ -277,7 +273,6 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
                print_item (list, items[(scroll + choice) * 3 + 1],
                            status[scroll + choice], choice, TRUE);
                wnoutrefresh (list);
-               wmove (dialog, cur_y, cur_x);
                wrefresh (dialog);
            }
            continue;           /* wait for another key press */
@@ -289,17 +284,13 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
            delwin (dialog);
            free (status);
            return 1;
-           return 1;
        case TAB:
        case KEY_LEFT:
        case KEY_RIGHT:
-           if (!button) {
-               button = 1;     /* "Help" button selected */
-               print_buttons(dialog, height, width, FALSE, TRUE);
-           } else {
-               button = 0;     /* "OK" button selected */
-               print_buttons(dialog, height, width, TRUE, FALSE);
-           }
+           button = ((key == KEY_LEFT ? --button : ++button) < 0)
+                       ? 1 : (button > 1 ? 0 : button);
+
+           print_buttons(dialog, height, width, button);
            wrefresh (dialog);
            break;
        case 'S':
@@ -309,7 +300,6 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
            if (!button) {
                if (flag == FLAG_CHECK) {
                    status[scroll + choice] = !status[scroll + choice];
-                   getyx (dialog, cur_y, cur_x);
                    wmove (list, choice, check_x);
                    wattrset (list, check_selected_attr);
                    wprintw (list, "[%c]", status[scroll + choice] ? 'X' : ' ');
@@ -318,14 +308,12 @@ dialog_checklist (const char *title, const char *prompt, int height, int width,
                        for (i = 0; i < item_no; i++)
                            status[i] = 0;
                        status[scroll + choice] = 1;
-                       getyx (dialog, cur_y, cur_x);
                        for (i = 0; i < max_choice; i++)
                            print_item (list, items[(scroll + i) * 3 + 1],
                                        status[scroll + i], i, i == choice);
                    }
                }
                wnoutrefresh (list);
-               wmove (dialog, cur_y, cur_x);
                wrefresh (dialog);
             
                for (i = 0; i < item_no; i++) {
index 8ba290704be4e941a04d0cac6193f8a6dc136886..dd29e4e498a5b534261e84b2a6627ebdfb44e408 100644 (file)
@@ -53,6 +53,10 @@ static void
 print_arrows (WINDOW * win, int choice, int item_no, int scroll,
                int y, int x, int height)
 {
+    int cur_y, cur_x;
+
+    getyx(win, cur_y, cur_x);
+
     wmove(win, y, x);
 
     if (scroll > 0) {
@@ -83,22 +87,24 @@ print_arrows (WINDOW * win, int choice, int item_no, int scroll,
        waddch (win, ACS_HLINE);
        waddch (win, ACS_HLINE);
    }
+
+   wmove(win, cur_y, cur_x);
 }
 
 /*
  * Display the termination buttons.
  */
 static void
-print_buttons (WINDOW *win, int height, int width,
-               int okval, int exitval, int cancelval)
+print_buttons (WINDOW *win, int height, int width, int selected)
 {
     int x = width / 2 - 16;
     int y = height - 2;
 
-    print_button (win, "Select", y, x, okval);
-    print_button (win, " Exit ", y, x + 12, exitval);
-    print_button (win, " Help ", y, x + 24, cancelval);
+    print_button (win, "Select", y, x, selected == 0);
+    print_button (win, " Exit ", y, x + 12, selected == 1);
+    print_button (win, " Help ", y, x + 24, selected == 2);
 
+    wmove(win, y, x+1+12*selected);
     wrefresh (win);
 }
 
@@ -111,7 +117,7 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
                const char * const * items)
 
 {
-    int i, j, x, y, cur_x, cur_y, box_x, box_y;
+    int i, j, x, y, box_x, box_y;
     int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice;
     WINDOW *dialog, *menu;
 
@@ -145,7 +151,6 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
     print_autowrap (dialog, prompt, width - 2, 1, 3);
 
     menu_width = width - 6;
-    getyx (dialog, cur_y, cur_x);
     box_y = height - menu_height - 5;
     box_x = (width - menu_width) / 2 - 1;
 
@@ -186,7 +191,7 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
     print_arrows(dialog, choice, item_no, scroll,
                 box_y, box_x+item_x+1, menu_height);
 
-    print_buttons (dialog, height, width, TRUE, FALSE, FALSE);
+    print_buttons (dialog, height, width, 0);
 
     while (key != ESC) {
        key = wgetch (dialog);
@@ -209,8 +214,6 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
                    if (scroll) {
 
                        /* Scroll menu down */
-                       getyx (dialog, cur_y, cur_x);
-
                        if (menu_height > 1) {
                            /* De-highlight current first item */
                            print_item (menu, items[scroll*2+1], 0, FALSE,
@@ -227,7 +230,6 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
                        print_arrows(dialog, choice, item_no, scroll,
                                        box_y, box_x+item_x+1, menu_height);
 
-                       wmove (dialog, cur_y, cur_x);
                    }
                    continue;   /* wait for another key press */
                } else
@@ -236,7 +238,6 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
                if (choice == max_choice - 1) {
                    if (scroll + choice < item_no - 1) {
                        /* Scroll menu up */
-                       getyx (dialog, cur_y, cur_x);
                        if (menu_height > 1) {
                            /* De-highlight current last item */
                            print_item (menu, items[(scroll + max_choice - 1)
@@ -256,7 +257,6 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
                        print_arrows(dialog, choice, item_no, scroll,
                                        box_y, box_x+item_x+1, menu_height);
 
-                       wmove (dialog, cur_y, cur_x);
                        wrefresh (dialog);
                    }
                    continue;   /* wait for another key press */
@@ -265,7 +265,6 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
 
            if (i != choice) {
                /* De-highlight current item */
-               getyx (dialog, cur_y, cur_x);   /* Save cursor position */
                print_item (menu, items[(scroll+choice)*2+1], choice, FALSE,
                                 (items[(scroll+choice)*2][0] != ':'));
 
@@ -274,30 +273,19 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
                print_item (menu, items[(scroll+choice)*2+1], choice, TRUE,
                                 (items[(scroll+choice)*2][0] != ':'));
                wnoutrefresh (menu);
-               wmove (dialog, cur_y, cur_x);
                wrefresh (dialog);
            }
            continue;           /* wait for another key press */
        }
 
        switch (key) {
-       case TAB:
        case KEY_LEFT:
+       case TAB:
        case KEY_RIGHT:
-           switch (button) {
-           case 0:
-               button = 1;
-               print_buttons(dialog, height, width, FALSE, TRUE, FALSE);
-               break;
-           case 1:
-               button = 2;
-               print_buttons(dialog, height, width, FALSE, FALSE, TRUE);
-               break;
-           case 2:
-               button = 0;
-               print_buttons(dialog, height, width, TRUE, FALSE, FALSE);
-               break;
-           }
+           button = ((key == KEY_LEFT ? --button : ++button) < 0)
+                       ? 2 : (button > 2 ? 0 : button);
+
+           print_buttons(dialog, height, width, button);
            wrefresh (dialog);
            break;
        case ' ':
@@ -313,10 +301,10 @@ dialog_menu (const char *title, const char *prompt, int height, int width,
        case '\n':
            delwin (dialog);
            if (button == 2) 
-               fprintf(stderr, "\"%s\" %s", 
+               fprintf(stderr, "\"%s\" \"%s\"", 
+                       items[(scroll + choice) * 2],
                        items[(scroll + choice) * 2 + 1] +
-                       first_alpha(items[(scroll + choice) * 2 + 1]),
-                       items[(scroll + choice) * 2]);
+                       first_alpha(items[(scroll + choice) * 2 + 1]));
            else
                fprintf(stderr, items[(scroll + choice) * 2]);
 
index eda41b6270e043903ad0bf0bccdaacacd961cc76..6f40af6457db2637b9aaefde6ef895b94cbac682 100644 (file)
  * Display termination buttons
  */
 static void
-print_buttons(WINDOW *dialog, int height, int width, int okval, int cancelval)
+print_buttons(WINDOW *dialog, int height, int width, int selected)
 {
     int x = width / 2 - 10;
     int y = height - 2;
 
-    print_button (dialog, " Yes ", y, x, okval);
-    print_button (dialog, "  No  ", y, x + 13, cancelval);
+    print_button (dialog, " Yes ", y, x, selected == 0);
+    print_button (dialog, "  No  ", y, x + 13, selected == 1);
 
+    wmove(dialog, y, x+1 + 13*selected );
     wrefresh (dialog);
 }
 
@@ -72,7 +73,7 @@ dialog_yesno (const char *title, const char *prompt, int height, int width)
     wattrset (dialog, dialog_attr);
     print_autowrap (dialog, prompt, width - 2, 1, 3);
 
-    print_buttons(dialog, height, width, TRUE, FALSE);
+    print_buttons(dialog, height, width, 0);
 
     while (key != ESC) {
        key = wgetch (dialog);
@@ -87,17 +88,12 @@ dialog_yesno (const char *title, const char *prompt, int height, int width)
            return 1;
 
        case TAB:
-       case KEY_UP:
-       case KEY_DOWN:
        case KEY_LEFT:
        case KEY_RIGHT:
-           if (!button) {
-               button = 1;     /* "No" button selected */
-               print_buttons(dialog, height, width, FALSE, TRUE);
-           } else {
-               button = 0;     /* "Yes" button selected */
-               print_buttons(dialog, height, width, TRUE, FALSE);
-           }
+           button = ((key == KEY_LEFT ? --button : ++button) < 0)
+                       ? 1 : (button > 1 ? 0 : button);
+
+           print_buttons(dialog, height, width, button);
            wrefresh (dialog);
            break;
        case ' ':